ctf_hash.c revision 1.3 1 1.1 darran /*
2 1.1 darran * CDDL HEADER START
3 1.1 darran *
4 1.1 darran * The contents of this file are subject to the terms of the
5 1.1 darran * Common Development and Distribution License, Version 1.0 only
6 1.1 darran * (the "License"). You may not use this file except in compliance
7 1.1 darran * with the License.
8 1.1 darran *
9 1.1 darran * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 1.1 darran * or http://www.opensolaris.org/os/licensing.
11 1.1 darran * See the License for the specific language governing permissions
12 1.1 darran * and limitations under the License.
13 1.1 darran *
14 1.1 darran * When distributing Covered Code, include this CDDL HEADER in each
15 1.1 darran * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 1.1 darran * If applicable, add the following below this CDDL HEADER, with the
17 1.1 darran * fields enclosed by brackets "[]" replaced with your own identifying
18 1.1 darran * information: Portions Copyright [yyyy] [name of copyright owner]
19 1.1 darran *
20 1.1 darran * CDDL HEADER END
21 1.1 darran */
22 1.1 darran
23 1.3 christos #ifdef HAVE_NBTOOL_CONFIG_H
24 1.3 christos #include "nbtool_config.h"
25 1.3 christos #endif
26 1.1 darran /*
27 1.1 darran * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
28 1.1 darran * Use is subject to license terms.
29 1.1 darran */
30 1.1 darran
31 1.1 darran #pragma ident "%Z%%M% %I% %E% SMI"
32 1.1 darran
33 1.1 darran #include <ctf_impl.h>
34 1.1 darran
35 1.1 darran static const ushort_t _CTF_EMPTY[1] = { 0 };
36 1.1 darran
37 1.1 darran int
38 1.1 darran ctf_hash_create(ctf_hash_t *hp, ulong_t nelems)
39 1.1 darran {
40 1.1 darran if (nelems > USHRT_MAX)
41 1.1 darran return (EOVERFLOW);
42 1.1 darran
43 1.1 darran /*
44 1.1 darran * If the hash table is going to be empty, don't bother allocating any
45 1.1 darran * memory and make the only bucket point to a zero so lookups fail.
46 1.1 darran */
47 1.1 darran if (nelems == 0) {
48 1.1 darran bzero(hp, sizeof (ctf_hash_t));
49 1.2 christos hp->h_buckets = __UNCONST(_CTF_EMPTY);
50 1.1 darran hp->h_nbuckets = 1;
51 1.1 darran return (0);
52 1.1 darran }
53 1.1 darran
54 1.1 darran hp->h_nbuckets = 211; /* use a prime number of hash buckets */
55 1.1 darran hp->h_nelems = nelems + 1; /* we use index zero as a sentinel */
56 1.1 darran hp->h_free = 1; /* first free element is index 1 */
57 1.1 darran
58 1.1 darran hp->h_buckets = ctf_alloc(sizeof (ushort_t) * hp->h_nbuckets);
59 1.1 darran hp->h_chains = ctf_alloc(sizeof (ctf_helem_t) * hp->h_nelems);
60 1.1 darran
61 1.1 darran if (hp->h_buckets == NULL || hp->h_chains == NULL) {
62 1.1 darran ctf_hash_destroy(hp);
63 1.1 darran return (EAGAIN);
64 1.1 darran }
65 1.1 darran
66 1.1 darran bzero(hp->h_buckets, sizeof (ushort_t) * hp->h_nbuckets);
67 1.1 darran bzero(hp->h_chains, sizeof (ctf_helem_t) * hp->h_nelems);
68 1.1 darran
69 1.1 darran return (0);
70 1.1 darran }
71 1.1 darran
72 1.1 darran uint_t
73 1.1 darran ctf_hash_size(const ctf_hash_t *hp)
74 1.1 darran {
75 1.1 darran return (hp->h_nelems ? hp->h_nelems - 1 : 0);
76 1.1 darran }
77 1.1 darran
78 1.1 darran static ulong_t
79 1.1 darran ctf_hash_compute(const char *key, size_t len)
80 1.1 darran {
81 1.1 darran ulong_t g, h = 0;
82 1.1 darran const char *p, *q = key + len;
83 1.1 darran size_t n = 0;
84 1.1 darran
85 1.1 darran for (p = key; p < q; p++, n++) {
86 1.1 darran h = (h << 4) + *p;
87 1.1 darran
88 1.1 darran if ((g = (h & 0xf0000000)) != 0) {
89 1.1 darran h ^= (g >> 24);
90 1.1 darran h ^= g;
91 1.1 darran }
92 1.1 darran }
93 1.1 darran
94 1.1 darran return (h);
95 1.1 darran }
96 1.1 darran
97 1.1 darran int
98 1.1 darran ctf_hash_insert(ctf_hash_t *hp, ctf_file_t *fp, ushort_t type, uint_t name)
99 1.1 darran {
100 1.1 darran ctf_strs_t *ctsp = &fp->ctf_str[CTF_NAME_STID(name)];
101 1.1 darran const char *str = ctsp->cts_strs + CTF_NAME_OFFSET(name);
102 1.1 darran ctf_helem_t *hep = &hp->h_chains[hp->h_free];
103 1.1 darran ulong_t h;
104 1.1 darran
105 1.1 darran if (type == 0)
106 1.1 darran return (EINVAL);
107 1.1 darran
108 1.1 darran if (hp->h_free >= hp->h_nelems)
109 1.1 darran return (EOVERFLOW);
110 1.1 darran
111 1.1 darran if (ctsp->cts_strs == NULL)
112 1.1 darran return (ECTF_STRTAB);
113 1.1 darran
114 1.1 darran if (ctsp->cts_len <= CTF_NAME_OFFSET(name))
115 1.1 darran return (ECTF_BADNAME);
116 1.1 darran
117 1.1 darran if (str[0] == '\0')
118 1.1 darran return (0); /* just ignore empty strings on behalf of caller */
119 1.1 darran
120 1.1 darran hep->h_name = name;
121 1.1 darran hep->h_type = type;
122 1.1 darran h = ctf_hash_compute(str, strlen(str)) % hp->h_nbuckets;
123 1.1 darran hep->h_next = hp->h_buckets[h];
124 1.1 darran hp->h_buckets[h] = hp->h_free++;
125 1.1 darran
126 1.1 darran return (0);
127 1.1 darran }
128 1.1 darran
129 1.1 darran /*
130 1.1 darran * Wrapper for ctf_hash_lookup/ctf_hash_insert: if the key is already in the
131 1.1 darran * hash, override the previous definition with this new official definition.
132 1.1 darran * If the key is not present, then call ctf_hash_insert() and hash it in.
133 1.1 darran */
134 1.1 darran int
135 1.1 darran ctf_hash_define(ctf_hash_t *hp, ctf_file_t *fp, ushort_t type, uint_t name)
136 1.1 darran {
137 1.1 darran const char *str = ctf_strptr(fp, name);
138 1.1 darran ctf_helem_t *hep = ctf_hash_lookup(hp, fp, str, strlen(str));
139 1.1 darran
140 1.1 darran if (hep == NULL)
141 1.1 darran return (ctf_hash_insert(hp, fp, type, name));
142 1.1 darran
143 1.1 darran hep->h_type = type;
144 1.1 darran return (0);
145 1.1 darran }
146 1.1 darran
147 1.1 darran ctf_helem_t *
148 1.1 darran ctf_hash_lookup(ctf_hash_t *hp, ctf_file_t *fp, const char *key, size_t len)
149 1.1 darran {
150 1.1 darran ctf_helem_t *hep;
151 1.1 darran ctf_strs_t *ctsp;
152 1.1 darran const char *str;
153 1.1 darran ushort_t i;
154 1.1 darran
155 1.1 darran ulong_t h = ctf_hash_compute(key, len) % hp->h_nbuckets;
156 1.1 darran
157 1.1 darran for (i = hp->h_buckets[h]; i != 0; i = hep->h_next) {
158 1.1 darran hep = &hp->h_chains[i];
159 1.1 darran ctsp = &fp->ctf_str[CTF_NAME_STID(hep->h_name)];
160 1.1 darran str = ctsp->cts_strs + CTF_NAME_OFFSET(hep->h_name);
161 1.1 darran
162 1.1 darran if (strncmp(key, str, len) == 0 && str[len] == '\0')
163 1.1 darran return (hep);
164 1.1 darran }
165 1.1 darran
166 1.1 darran return (NULL);
167 1.1 darran }
168 1.1 darran
169 1.1 darran void
170 1.1 darran ctf_hash_destroy(ctf_hash_t *hp)
171 1.1 darran {
172 1.1 darran if (hp->h_buckets != NULL && hp->h_nbuckets != 1) {
173 1.1 darran ctf_free(hp->h_buckets, sizeof (ushort_t) * hp->h_nbuckets);
174 1.1 darran hp->h_buckets = NULL;
175 1.1 darran }
176 1.1 darran
177 1.1 darran if (hp->h_chains != NULL) {
178 1.1 darran ctf_free(hp->h_chains, sizeof (ctf_helem_t) * hp->h_nelems);
179 1.1 darran hp->h_chains = NULL;
180 1.1 darran }
181 1.1 darran }
182