1 /*
2 * nsfFunPtrHashTable.c --
3 *
4 * Provide a custom Tcl hashtable type, using function pointers
5 * as hash keys, and a slim wrapper around Tcl's hashtable
6 * API to manage them.
7 *
8 * Copyright (C) 2016-2018 Gustaf Neumann
9 * Copyright (C) 2016 Stefan Sobernig
10 *
11 * Vienna University of Economics and Business
12 * Institute of Information Systems and New Media
13 * A-1020, Welthandelsplatz 1
14 * Vienna, Austria
15 *
16 * This work is licensed under the MIT License https://www.opensource.org/licenses/MIT
17 *
18 * Copyright:
19 *
20 * Permission is hereby granted, free of charge, to any person obtaining a
21 * copy of this software and associated documentation files (the "Software"),
22 * to deal in the Software without restriction, including without limitation
23 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
24 * and/or sell copies of the Software, and to permit persons to whom the
25 * Software is furnished to do so, subject to the following conditions:
26 *
27 * The above copyright notice and this permission notice shall be included in
28 * all copies or substantial portions of the Software.
29 *
30 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
33 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
35 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
36 * DEALINGS IN THE SOFTWARE.
37 *
38 */
39
40
41 #include "nsfInt.h"
42
43 /*
44 * Definitions for HashType funPtr.
45 *
46 * Background: since it is not guaranteed that sizeof(function
47 * pointer) == sizeof(data pointer) (or sizeof(function pointer) <=
48 * sizeof(data pointer)), passing function pointers via data pointers
49 * - which is what default Tcl hash types do - is potentially
50 * dangerous. Therefore, and on top, it is not allowed under ISO
51 * C. So, we define our own type that allows one to hash on function
52 * pointers safely.
53 *
54 */
55 static unsigned int FunPtrKey(Tcl_HashTable *tablePtr, void *keyPtr);
56 static int CompareFunPtrKeys(void *keyPtr, Tcl_HashEntry *hPtr);
57 static Tcl_HashEntry *AllocFunPtrEntry(Tcl_HashTable *tablePtr, void *keyPtr);
58
59
60 typedef struct funPtrEntry_t {
61 Nsf_AnyFun *funPtr;
62 } funPtrEntry_t;
63
64 static Tcl_HashKeyType funPtrHashKeyType = {
65 1, /* version*/
66 0, /* flags */
67 FunPtrKey, /* hashKeyProc*/
68 CompareFunPtrKeys, /* compareKeysProc */
69 AllocFunPtrEntry, /* allocEntryProc */
70 NULL /* freeEntryProc */
71 };
72
73 /*
74 *----------------------------------------------------------------------
75 *
76 * FunPtrKey --
77 *
78 * Computes an unsigned int hash value from a function pointer.
79 *
80 * Results:
81 * Returns the computed hash.
82 *
83 * Side effects:
84 * None.
85 *
86 *----------------------------------------------------------------------
87 */
88
89 static unsigned int
FunPtrKey(Tcl_HashTable * UNUSED (tablePtr),void * keyPtr)90 FunPtrKey(
91 Tcl_HashTable *UNUSED(tablePtr), /* Hash table. */
92 void *keyPtr /* Key from which to compute hash value. */
93 ) {
94 funPtrEntry_t *e = (funPtrEntry_t *)keyPtr;
95 Nsf_AnyFun *value = e->funPtr;
96
97 /*
98 * This is a very simple approach for obtaining a hash value. Maybe one
99 * needs a more sophisticated approach with weird endians machines.
100 */
101 return PTR2UINT(value);
102
103 }
104
105 /*
106 *----------------------------------------------------------------------
107 *
108 * CompareFunPtrKeys --
109 *
110 * Compares two function pointer keys.
111 *
112 * Results:
113 * The return value is 0 if they are different and 1 if they are the
114 * same.
115 *
116 * Side effects:
117 * None.
118 *
119 *----------------------------------------------------------------------
120 */
121
122 static int
CompareFunPtrKeys(void * keyPtr,Tcl_HashEntry * hPtr)123 CompareFunPtrKeys(
124 void *keyPtr, /* New key to compare. */
125 Tcl_HashEntry *hPtr /* Existing key to compare. */
126 ) {
127 funPtrEntry_t *e = (funPtrEntry_t *)keyPtr;
128 Nsf_AnyFun *existingValue;
129
130 memcpy(&existingValue, &hPtr->key.oneWordValue, sizeof(Nsf_AnyFun *));
131
132 return e->funPtr == existingValue;
133 }
134
135 /*
136 *----------------------------------------------------------------------
137 *
138 * AllocFunPtrEntry --
139 *
140 * Allocate space for a Tcl_HashEntry containing the function pointer.
141 *
142 * Results:
143 * The return value is a pointer to the created entry.
144 *
145 * Side effects:
146 * None.
147 *
148 *----------------------------------------------------------------------
149 */
150 static Tcl_HashEntry *
AllocFunPtrEntry(Tcl_HashTable * UNUSED (tablePtr),void * keyPtr)151 AllocFunPtrEntry(
152 Tcl_HashTable *UNUSED(tablePtr), /* Hash table. */
153 void *keyPtr /* Key to store in the hash table entry. */
154 ) {
155 funPtrEntry_t *e = (funPtrEntry_t *)keyPtr;
156 Tcl_HashEntry *hPtr;
157 unsigned int size;
158 Nsf_AnyFun *value = e->funPtr;
159
160 size = sizeof(Tcl_HashEntry) + (sizeof(Nsf_AnyFun *)) - sizeof(hPtr->key);
161 if (size < sizeof(Tcl_HashEntry)) {
162 size = sizeof(Tcl_HashEntry);
163 }
164 hPtr = (Tcl_HashEntry *) ckalloc(size);
165
166 memcpy(&hPtr->key.oneWordValue, &value, sizeof(Nsf_AnyFun *));
167
168 hPtr->clientData = 0;
169
170 return hPtr;
171 }
172
173
174 /*
175 *----------------------------------------------------------------------
176 * Nsf_InitFunPtrHashTable --
177 *
178 * Initializes a hash table structure providing for function
179 * pointers as hash keys. It is a slim wrapper around
180 * Tcl_InitCustomHashTable().
181 *
182 * Results:
183 * None.
184 *
185 * Side effects:
186 * None.
187 *
188 *----------------------------------------------------------------------
189 */
190 void
Nsf_InitFunPtrHashTable(Tcl_HashTable * tablePtr)191 Nsf_InitFunPtrHashTable(Tcl_HashTable *tablePtr) {
192
193 nonnull_assert(tablePtr != NULL);
194
195 Tcl_InitCustomHashTable(tablePtr, TCL_CUSTOM_PTR_KEYS, &funPtrHashKeyType);
196
197 }
198
199 /*
200 *----------------------------------------------------------------------
201 * Nsf_CreateFunPtrHashEntry --
202 *
203 * Creates or finds an entry based on a given function-pointer
204 * key. It is a slim wrapper around Tcl_CreateHashEntry().
205 *
206 * Results:
207 * Returns a pointer to the matching entry.
208 *
209 * Side effects:
210 * A new entry may be stored in the hash table.
211 *
212 *----------------------------------------------------------------------
213 */
214
215 Tcl_HashEntry *
Nsf_CreateFunPtrHashEntry(Tcl_HashTable * tablePtr,Nsf_AnyFun * key,int * isNew)216 Nsf_CreateFunPtrHashEntry(
217 Tcl_HashTable *tablePtr,
218 Nsf_AnyFun *key,
219 int *isNew
220 ) {
221 Tcl_HashEntry *hPtr;
222 funPtrEntry_t entry;
223
224 nonnull_assert(tablePtr != NULL);
225 nonnull_assert(key != NULL);
226
227 entry.funPtr = key;
228 hPtr = Tcl_CreateHashEntry(tablePtr, (const char *)&entry, isNew);
229
230 return hPtr;
231 }
232
233 /*
234 *----------------------------------------------------------------------
235 * Nsf_FindFunPtrHashEntry --
236 *
237 * Finds the entry with a matching function-pointer key in a given
238 * table. It is a slim wrapper around Tcl_FindHashEntry().
239 *
240 * Results:
241 * Returns a pointer to the matching entry, or NULL.
242 *
243 * Side effects:
244 * None.
245 *
246 *----------------------------------------------------------------------
247 */
248
249 Tcl_HashEntry *
Nsf_FindFunPtrHashEntry(Tcl_HashTable * tablePtr,Nsf_AnyFun * key)250 Nsf_FindFunPtrHashEntry(Tcl_HashTable *tablePtr, Nsf_AnyFun *key) {
251 Tcl_HashEntry *hPtr;
252 funPtrEntry_t entry;
253
254 nonnull_assert(tablePtr != NULL);
255 nonnull_assert(key != NULL);
256
257 entry.funPtr = key;
258 hPtr = Tcl_FindHashEntry(tablePtr, (const char *)&entry);
259 return hPtr;
260
261 }
262
263 /*
264 * Local Variables:
265 * mode: c
266 * c-basic-offset: 2
267 * fill-column: 78
268 * indent-tabs-mode: nil
269 * eval: (c-guess)
270 * End:
271 */
272