Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4358 Serge 1
/**************************************************************************
2
 *
3
 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
4
 * All Rights Reserved.
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a
7
 * copy of this software and associated documentation files (the
8
 * "Software"), to deal in the Software without restriction, including
9
 * without limitation the rights to use, copy, modify, merge, publish,
10
 * distribute, sub license, and/or sell copies of the Software, and to
11
 * permit persons to whom the Software is furnished to do so, subject to
12
 * the following conditions:
13
 *
14
 * The above copyright notice and this permission notice (including the
15
 * next paragraph) shall be included in all copies or substantial portions
16
 * of the Software.
17
 *
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21
 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
 *
26
 **************************************************************************/
27
 
28
/**
29
 * Key lookup/associative container.
30
 *
31
 * Like Jose's util_hash_table, based on CSO cache code for now.
32
 *
33
 * Author: Brian Paul
34
 */
35
 
36
 
37
#include "pipe/p_compiler.h"
38
#include "util/u_debug.h"
39
 
40
#include "cso_cache/cso_hash.h"
41
 
42
#include "util/u_memory.h"
43
#include "util/u_keymap.h"
44
 
45
 
46
struct keymap
47
{
48
   struct cso_hash *cso;
49
   unsigned key_size;
50
   unsigned max_entries; /* XXX not obeyed net */
51
   unsigned num_entries;
52
   keymap_delete_func delete_func;
53
};
54
 
55
 
56
struct keymap_item
57
{
58
   void *key, *value;
59
};
60
 
61
 
62
/**
63
 * This the default key-delete function used when the client doesn't
64
 * provide one.
65
 */
66
static void
67
default_delete_func(const struct keymap *map,
68
                    const void *key, void *data, void *user)
69
{
70
   FREE((void*) data);
71
}
72
 
73
 
74
static INLINE struct keymap_item *
75
hash_table_item(struct cso_hash_iter iter)
76
{
77
   return (struct keymap_item *) cso_hash_iter_data(iter);
78
}
79
 
80
 
81
/**
82
 * Return 4-byte hash key for a block of bytes.
83
 */
84
static unsigned
85
hash(const void *key, unsigned keySize)
86
{
87
   unsigned i, hash;
88
 
89
   keySize /= 4; /* convert from bytes to uints */
90
 
91
   hash = 0;
92
   for (i = 0; i < keySize; i++) {
93
      hash ^= (i + 1) * ((const unsigned *) key)[i];
94
   }
95
 
96
   /*hash = hash ^ (hash >> 11) ^ (hash >> 22);*/
97
 
98
   return hash;
99
}
100
 
101
 
102
/**
103
 * Create a new map.
104
 * \param keySize  size of the keys in bytes
105
 * \param maxEntries  max number of entries to allow (~0 = infinity)
106
 * \param deleteFunc  optional callback to call when entries
107
 *                    are deleted/replaced
108
 */
109
struct keymap *
110
util_new_keymap(unsigned keySize, unsigned maxEntries,
111
                 keymap_delete_func deleteFunc)
112
{
113
   struct keymap *map = MALLOC_STRUCT(keymap);
114
   if (!map)
115
      return NULL;
116
 
117
   map->cso = cso_hash_create();
118
   if (!map->cso) {
119
      FREE(map);
120
      return NULL;
121
   }
122
 
123
   map->max_entries = maxEntries;
124
   map->num_entries = 0;
125
   map->key_size = keySize;
126
   map->delete_func = deleteFunc ? deleteFunc : default_delete_func;
127
 
128
   return map;
129
}
130
 
131
 
132
/**
133
 * Delete/free a keymap and all entries.  The deleteFunc that was given at
134
 * create time will be called for each entry.
135
 * \param user  user-provided pointer passed through to the delete callback
136
 */
137
void
138
util_delete_keymap(struct keymap *map, void *user)
139
{
140
   util_keymap_remove_all(map, user);
141
   cso_hash_delete(map->cso);
142
   FREE(map);
143
}
144
 
145
 
146
static INLINE struct cso_hash_iter
147
hash_table_find_iter(const struct keymap *map, const void *key,
148
                     unsigned key_hash)
149
{
150
   struct cso_hash_iter iter;
151
   struct keymap_item *item;
152
 
153
   iter = cso_hash_find(map->cso, key_hash);
154
   while (!cso_hash_iter_is_null(iter)) {
155
      item = (struct keymap_item *) cso_hash_iter_data(iter);
156
      if (!memcmp(item->key, key, map->key_size))
157
         break;
158
      iter = cso_hash_iter_next(iter);
159
   }
160
 
161
   return iter;
162
}
163
 
164
 
165
static INLINE struct keymap_item *
166
hash_table_find_item(const struct keymap *map, const void *key,
167
                     unsigned key_hash)
168
{
169
   struct cso_hash_iter iter = hash_table_find_iter(map, key, key_hash);
170
   if (cso_hash_iter_is_null(iter)) {
171
      return NULL;
172
   }
173
   else {
174
      return hash_table_item(iter);
175
   }
176
}
177
 
178
 
179
/**
180
 * Insert a new key + data pointer into the table.
181
 * Note: we create a copy of the key, but not the data!
182
 * If the key is already present in the table, replace the existing
183
 * entry (calling the delete callback on the previous entry).
184
 * If the maximum capacity of the map is reached an old entry
185
 * will be deleted (the delete callback will be called).
186
 */
187
boolean
188
util_keymap_insert(struct keymap *map, const void *key,
189
                   const void *data, void *user)
190
{
191
   unsigned key_hash;
192
   struct keymap_item *item;
193
   struct cso_hash_iter iter;
194
 
195
   assert(map);
196
   if (!map)
197
      return FALSE;
198
 
199
   key_hash = hash(key, map->key_size);
200
 
201
   item = hash_table_find_item(map, key, key_hash);
202
   if (item) {
203
      /* call delete callback for old entry/item */
204
      map->delete_func(map, item->key, item->value, user);
205
      item->value = (void *) data;
206
      return TRUE;
207
   }
208
 
209
   item = MALLOC_STRUCT(keymap_item);
210
   if (!item)
211
      return FALSE;
212
 
213
   item->key = mem_dup(key, map->key_size);
214
   item->value = (void *) data;
215
 
216
   iter = cso_hash_insert(map->cso, key_hash, item);
217
   if (cso_hash_iter_is_null(iter)) {
218
      FREE(item);
219
      return FALSE;
220
   }
221
 
222
   map->num_entries++;
223
 
224
   return TRUE;
225
}
226
 
227
 
228
/**
229
 * Look up a key in the map and return the associated data pointer.
230
 */
231
const void *
232
util_keymap_lookup(const struct keymap *map, const void *key)
233
{
234
   unsigned key_hash;
235
   struct keymap_item *item;
236
 
237
   assert(map);
238
   if (!map)
239
      return NULL;
240
 
241
   key_hash = hash(key, map->key_size);
242
 
243
   item = hash_table_find_item(map, key, key_hash);
244
   if (!item)
245
      return NULL;
246
 
247
   return item->value;
248
}
249
 
250
 
251
/**
252
 * Remove an entry from the map.
253
 * The delete callback will be called if the given key/entry is found.
254
 * \param user  passed to the delete callback as the last param.
255
 */
256
void
257
util_keymap_remove(struct keymap *map, const void *key, void *user)
258
{
259
   unsigned key_hash;
260
   struct cso_hash_iter iter;
261
   struct keymap_item *item;
262
 
263
   assert(map);
264
   if (!map)
265
      return;
266
 
267
   key_hash = hash(key, map->key_size);
268
 
269
   iter = hash_table_find_iter(map, key, key_hash);
270
   if (cso_hash_iter_is_null(iter))
271
      return;
272
 
273
   item = hash_table_item(iter);
274
   assert(item);
275
   if (!item)
276
      return;
277
   map->delete_func(map, item->key, item->value, user);
278
   FREE(item->key);
279
   FREE(item);
280
 
281
   map->num_entries--;
282
 
283
   cso_hash_erase(map->cso, iter);
284
}
285
 
286
 
287
/**
288
 * Remove all entries from the map, calling the delete callback for each.
289
 * \param user  passed to the delete callback as the last param.
290
 */
291
void
292
util_keymap_remove_all(struct keymap *map, void *user)
293
{
294
   struct cso_hash_iter iter;
295
   struct keymap_item *item;
296
 
297
   assert(map);
298
   if (!map)
299
      return;
300
 
301
   iter = cso_hash_first_node(map->cso);
302
   while (!cso_hash_iter_is_null(iter)) {
303
      item = (struct keymap_item *)
304
         cso_hash_take(map->cso, cso_hash_iter_key(iter));
305
      map->delete_func(map, item->key, item->value, user);
306
      FREE(item->key);
307
      FREE(item);
308
      iter = cso_hash_first_node(map->cso);
309
   }
310
}
311
 
312
 
313
extern void
314
util_keymap_info(const struct keymap *map)
315
{
316
   debug_printf("Keymap %p: %u of max %u entries\n",
317
                (void *) map, map->num_entries, map->max_entries);
318
}