2 * Regular Pattern Analyzer (RPA)
3 * Copyright (c) 2009-2010 Martin Stoilov
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 * Martin Stoilov <martin@rpasearch.com>
22 #include "rlib/rmap.h"
23 #include "rlib/rstring.h"
24 #include "rlib/rmem.h"
27 typedef struct r_mapnode_s {
40 static rboolean r_map_rstrequal(rstr_t *key1, rstr_t *key2)
42 return (key1->size == key2->size && r_strncmp((const char*)key1->str, (const char*)key2->str, key1->size) == 0) ? TRUE : FALSE;
46 static unsigned long r_map_rstrhash(const rstr_t *key)
48 const char *str = (const char*) key->str;
50 unsigned long size = key->size;
51 unsigned long hash = 0;
53 for (i = 0; i < size; i++, str++) {
54 hash = *str + (hash << 6) + (hash << 16) - hash;
59 void r_mapnode_init(r_mapnode_t *node, const char *key, rsize_t size)
61 // node->key = r_rstrdup(key, size);
62 node->key = r_string_create_strsize(key, size);
63 r_list_init(&node->active);
64 r_list_init(&node->hash);
68 r_mapnode_t *r_map_getfreenode(rmap_t *map, const char *key, rsize_t size)
70 r_mapnode_t *node = NULL;
72 if (r_list_empty(&map->inactive)) {
73 long index = r_carray_add(map->data, NULL);
74 node = (r_mapnode_t*)r_carray_slot(map->data, index);
75 r_mapnode_init(node, key, size);
78 node = r_list_entry(r_list_first(&map->inactive), r_mapnode_t, active);
79 r_list_del(&node->active);
80 r_mapnode_init(node, key, size);
86 robject_t *r_map_copy(const robject_t *obj)
88 return (robject_t*)NULL;
92 void r_map_cleanup(robject_t *obj)
95 rmap_t *map = (rmap_t*)obj;
97 while (!r_list_empty(&map->active)) {
98 node = r_list_entry(r_list_first(&map->active), r_mapnode_t, active);
99 if (!r_object_gcget((robject_t*)node->key))
100 r_string_destroy(node->key);
101 r_list_del(&node->active);
103 while (!r_list_empty(&map->inactive)) {
104 node = r_list_entry(r_list_first(&map->inactive), r_mapnode_t, active);
105 if (!r_object_gcget((robject_t*)node->key))
106 r_string_destroy(node->key);
107 r_list_del(&node->active);
110 r_carray_destroy(map->data);
112 r_object_cleanup(&map->obj);
116 robject_t *r_map_init(robject_t *obj, ruint32 type, r_object_cleanupfun cleanup, r_object_copyfun copy, unsigned int elt_size, unsigned int nbits)
118 rsize_t elt_realsize = R_SIZE_ALIGN(elt_size + sizeof(r_mapnode_t), sizeof(ruword));
120 rmap_t *map = (rmap_t*)obj;
121 if (nbits == 0 || nbits > 16) {
125 r_object_init(obj, type, cleanup, copy);
126 map->data = r_carray_create(elt_realsize);
128 map->elt_size = elt_size;
129 r_list_init(&map->active);
130 r_list_init(&map->inactive);
131 hashsize = r_map_hashsize(map);
132 map->hash = (rlist_t*)r_malloc(sizeof(rlist_t) * hashsize);
134 for (i = 0; i < hashsize; i++) {
135 r_list_init(&map->hash[i]);
141 rmap_t *r_map_create(unsigned int elt_size, unsigned int nbits)
144 map = (rmap_t*)r_object_create(sizeof(*map));
145 r_map_init((robject_t*)map, R_OBJECT_MAP, r_map_cleanup, r_map_copy, elt_size, nbits);
151 void r_map_destroy(rmap_t *map)
153 r_object_destroy((robject_t*)map);
157 long r_map_gckey_add(rmap_t *map, rgc_t* gc, const char *name, rsize_t namesize, rconstpointer pval)
161 node = r_map_getfreenode(map, name, namesize);
163 r_memcpy(node->value.data, pval, map->elt_size);
164 node->nbucket = (r_map_rstrhash(R_STRING2RSTR(node->key)) & r_map_hashmask(map));
165 r_list_addt(&map->hash[node->nbucket], &node->hash);
166 r_list_addt(&map->active, &node->active);
168 r_gc_add(gc, (robject_t*)node->key);
173 long r_map_gckey_add_s(rmap_t *map, rgc_t* gc, const char *name, rconstpointer pval)
175 return r_map_gckey_add(map, gc, name, r_strlen(name), pval);
179 long r_map_gckey_add_d(rmap_t *map, rgc_t* gc, double name, rconstpointer pval)
182 r_memset(key, 0, sizeof(key));
183 r_snprintf(key, sizeof(key) - 1, "%.15f", name);
184 return r_map_gckey_add_s(map, gc, key, pval);
188 long r_map_gckey_add_l(rmap_t *map, rgc_t* gc, long name, rconstpointer pval)
191 r_memset(key, 0, sizeof(key));
192 r_snprintf(key, sizeof(key) - 1, "%ld", name);
193 return r_map_gckey_add_s(map, gc, key, pval);
197 long r_map_add(rmap_t *map, const char *name, rsize_t namesize, rconstpointer pval)
199 return r_map_gckey_add(map, NULL, name, namesize, pval);
203 long r_map_add_s(rmap_t *map, const char *name, rconstpointer pval)
205 return r_map_gckey_add_s(map, NULL, name, pval);
209 long r_map_add_l(rmap_t *map, long name, rconstpointer pval)
211 return r_map_gckey_add_l(map, NULL, name, pval);
215 long r_map_add_d(rmap_t *map, double name, rconstpointer pval)
217 return r_map_gckey_add_d(map, NULL, name, pval);
221 r_mapnode_t *r_map_node(rmap_t *map, unsigned long index)
224 if (index >= r_carray_length(map->data))
226 node = (r_mapnode_t*)r_carray_slot(map->data, index);
227 if (r_list_empty(&node->hash))
233 rstring_t *r_map_key(rmap_t *map, unsigned long index)
235 r_mapnode_t *node = r_map_node(map, index);
242 rpointer r_map_value(rmap_t *map, unsigned long index)
244 r_mapnode_t *node = r_map_node(map, index);
247 return (rpointer)node->value.data;
251 long r_map_setvalue(rmap_t *map, long index, rconstpointer pval)
253 r_mapnode_t *node = r_map_node(map, index);
256 r_memcpy(node->value.data, pval, map->elt_size);
261 int r_map_delete(rmap_t *map, unsigned long index)
263 r_mapnode_t *node = r_map_node(map, index);
266 if (!r_object_gcget((robject_t*)node->key))
267 r_string_destroy(node->key);
269 r_list_del(&node->hash);
270 r_list_init(&node->hash);
271 r_list_del(&node->active);
272 r_list_addt(&map->inactive, &node->active);
277 long r_map_lookup(rmap_t *map, long current, const char *name, rsize_t namesize)
281 rstr_t lookupstr = {(char*)name, namesize};
282 unsigned long nbucket;
287 r_mapnode_t *curnode = r_map_node(map, current);
290 nbucket = curnode->nbucket;
291 bucket = &map->hash[nbucket];
292 pos = r_list_next(bucket, &curnode->hash);
294 nbucket = (r_map_rstrhash(&lookupstr) & r_map_hashmask(map));
295 bucket = &map->hash[nbucket];
296 pos = r_list_first(bucket);
298 for ( ; pos ; pos = r_list_next(bucket, pos)) {
299 node = r_list_entry(pos, r_mapnode_t, hash);
300 if (r_map_rstrequal(R_STRING2RSTR(node->key), &lookupstr)) {
310 long r_map_lookup_s(rmap_t *map, long current, const char *name)
312 return r_map_lookup(map, current, name, r_strlen(name));
316 long r_map_lookup_l(rmap_t *map, long current, long name)
319 r_memset(key, 0, sizeof(key));
320 r_snprintf(key, sizeof(key) - 1, "%ld", name);
321 return r_map_lookup_s(map, current, key);
325 long r_map_lookup_d(rmap_t *map, long current, double name)
328 r_memset(key, 0, sizeof(key));
329 r_snprintf(key, sizeof(key) - 1, "%.15f", name);
330 return r_map_lookup_s(map, current, key);
334 long r_map_taillookup(rmap_t *map, long current, const char *name, rsize_t namesize)
338 rstr_t lookupstr = {(char*)name, namesize};
339 unsigned long nbucket;
344 r_mapnode_t *curnode = r_map_node(map, current);
347 nbucket = curnode->nbucket;
348 bucket = &map->hash[nbucket];
349 pos = r_list_prev(bucket, &curnode->hash);
351 nbucket = (r_map_rstrhash(&lookupstr) & r_map_hashmask(map));
352 bucket = &map->hash[nbucket];
353 pos = r_list_last(bucket);
355 for ( ; pos ; pos = r_list_prev(bucket, pos)) {
356 node = r_list_entry(pos, r_mapnode_t, hash);
357 if (r_map_rstrequal(R_STRING2RSTR(node->key), &lookupstr)) {
367 long r_map_taillookup_s(rmap_t *map, long current, const char *name)
369 return r_map_taillookup(map, current, name, r_strlen(name));
373 long r_map_first(rmap_t *map)
376 rlink_t *pos = r_list_first(&map->active);
380 node = r_list_entry(pos, r_mapnode_t, active);
385 long r_map_last(rmap_t *map)
388 rlink_t *pos = r_list_last(&map->active);
392 node = r_list_entry(pos, r_mapnode_t, active);
397 long r_map_next(rmap_t *map, long current)
399 r_mapnode_t *node = r_map_node(map, current);
404 pos = r_list_next(&map->active, &node->active);
407 node = r_list_entry(pos, r_mapnode_t, active);
412 long r_map_prev(rmap_t *map, long current)
414 r_mapnode_t *node = r_map_node(map, current);
419 pos = r_list_prev(&map->active, &node->active);
422 node = r_list_entry(pos, r_mapnode_t, active);