* Initial import of the hashtable implementation of WayLand
- Kinda smart (150LOC) - Fork it for 64bit hash keys (make ht64 in libr/util) * Make RConfig use the RHashTable to resolve by name - Code cleanup resulting in -30LOC - O(1) access to config variables (speedup!) - Make r_list_free and r_list_destroy take sense
This commit is contained in:
parent
c6a579a291
commit
3d142e8ec1
1
TODO
1
TODO
|
@ -25,6 +25,7 @@ pancake
|
|||
|
||||
nibble
|
||||
------
|
||||
* Do not show XREF info if in the same function?
|
||||
* r_anal
|
||||
- Code analysis (detect when an argument is a flagmask or enum and display text format) (ollydbg)
|
||||
* r_bin
|
||||
|
|
|
@ -1,45 +1,41 @@
|
|||
/* radare - LGPL - Copyright 2006-2009 pancake<nopcode.org> */
|
||||
/* radare - LGPL - Copyright 2006-2011 pancake<nopcode.org> */
|
||||
|
||||
#include "r_config.h"
|
||||
|
||||
// XXX spaguetti code lives here
|
||||
|
||||
static int r_config_callback_q(void *data) {
|
||||
struct r_config_node_t *node = data;
|
||||
RConfigNode *node = data;
|
||||
*(node->cb_ptr_q) = node->i_value;
|
||||
return R_TRUE;
|
||||
}
|
||||
|
||||
static int r_config_callback_i(void *data) {
|
||||
struct r_config_node_t *node = data;
|
||||
RConfigNode *node = data;
|
||||
*(node->cb_ptr_i) = node->i_value;
|
||||
return R_TRUE;
|
||||
}
|
||||
|
||||
static int r_config_callback_s(void *data) {
|
||||
struct r_config_node_t *node = data;
|
||||
if (!node->value || node->value[0]=='\0') {
|
||||
RConfigNode *node = data;
|
||||
if (!node->value || !*node->value) {
|
||||
free (*node->cb_ptr_s);
|
||||
*node->cb_ptr_s = NULL;
|
||||
} else *node->cb_ptr_s = r_str_dup (*node->cb_ptr_s, node->value);
|
||||
return R_TRUE;
|
||||
}
|
||||
|
||||
R_API int r_config_set_callback_q(struct r_config_t *cfg, const char *name, ut64 *ptr)
|
||||
{
|
||||
struct r_config_node_t *node;
|
||||
node = r_config_node_get(cfg, name);
|
||||
R_API int r_config_set_callback_q(RConfig *cfg, const char *name, ut64 *ptr) {
|
||||
RConfigNode *node = r_config_node_get (cfg, name);
|
||||
if (node) {
|
||||
node->cb_ptr_q = ptr;
|
||||
node->callback = (void *)&r_config_callback_q;
|
||||
return 1;
|
||||
return R_TRUE;
|
||||
}
|
||||
return 0;
|
||||
return R_FALSE;
|
||||
}
|
||||
|
||||
R_API int r_config_set_callback_i(struct r_config_t *cfg, const char *name, int *ptr)
|
||||
{
|
||||
struct r_config_node_t *node = r_config_node_get(cfg, name);
|
||||
R_API int r_config_set_callback_i(RConfig *cfg, const char *name, int *ptr) {
|
||||
RConfigNode *node = r_config_node_get (cfg, name);
|
||||
if (node) {
|
||||
node->cb_ptr_i = ptr;
|
||||
node->callback = (void *)&r_config_callback_i;
|
||||
|
@ -48,9 +44,8 @@ R_API int r_config_set_callback_i(struct r_config_t *cfg, const char *name, int
|
|||
return R_FALSE;
|
||||
}
|
||||
|
||||
R_API int r_config_set_callback_s(struct r_config_t *cfg, const char *name, char **ptr)
|
||||
{
|
||||
struct r_config_node_t *node = r_config_node_get(cfg, name);
|
||||
R_API int r_config_set_callback_s(RConfig *cfg, const char *name, char **ptr) {
|
||||
RConfigNode *node = r_config_node_get (cfg, name);
|
||||
if (node) {
|
||||
node->cb_ptr_s = ptr;
|
||||
node->callback = (void *)&r_config_callback_s;
|
||||
|
|
|
@ -1,24 +1,22 @@
|
|||
/* radare - LGPL - Copyright 2006-2009 pancake<nopcode.org> */
|
||||
/* radare - LGPL - Copyright 2006-2011 pancake<nopcode.org> */
|
||||
|
||||
#include "r_config.h"
|
||||
#include "r_util.h" // r_str_hash, r_str_chop, ...
|
||||
|
||||
R_API RConfigNode* r_config_node_new(const char *name, const char *value) {
|
||||
RConfigNode *node =
|
||||
(RConfigNode *)
|
||||
malloc(sizeof(RConfigNode));
|
||||
INIT_LIST_HEAD(&(node->list));
|
||||
RConfigNode *node = R_NEW (RConfigNode);
|
||||
node->name = strdup (name);
|
||||
node->hash = r_str_hash (name);
|
||||
node->value = value?strdup(value):strdup("");
|
||||
node->value = strdup (value?value:"");
|
||||
node->flags = CN_RW | CN_STR;
|
||||
node->i_value = 0;
|
||||
node->callback = NULL;
|
||||
return node;
|
||||
}
|
||||
|
||||
R_API void r_config_list(RConfig *cfg, const char *str, int rad) {
|
||||
struct list_head *i;
|
||||
R_API void r_config_list(RConfig *cfg, const char *str, boolt rad) {
|
||||
RConfigNode *node;
|
||||
RListIter *iter;
|
||||
int len = 0;
|
||||
|
||||
if (!strnull (str)) {
|
||||
|
@ -26,28 +24,19 @@ R_API void r_config_list(RConfig *cfg, const char *str, int rad) {
|
|||
len = strlen (str);
|
||||
}
|
||||
|
||||
list_for_each(i, &(cfg->nodes)) {
|
||||
RConfigNode *bt = list_entry(i, RConfigNode, list);
|
||||
r_list_foreach (cfg->nodes, iter, node) {
|
||||
if (str) {
|
||||
if (strncmp(str, bt->name, len) == 0)
|
||||
if (!strncmp (str, node->name, len))
|
||||
cfg->printf ("%s%s = %s\n", rad?"e ":"",
|
||||
bt->name, bt->value);
|
||||
} else cfg->printf ("%s%s = %s\n", rad?"e ":"", bt->name, bt->value);
|
||||
node->name, node->value);
|
||||
} else cfg->printf ("%s%s = %s\n", rad?"e ":"", node->name, node->value);
|
||||
}
|
||||
}
|
||||
|
||||
R_API RConfigNode *r_config_node_get(RConfig *cfg, const char *name) {
|
||||
struct list_head *i;
|
||||
int hash;
|
||||
if (strnull (name))
|
||||
return NULL;
|
||||
hash = r_str_hash (name);
|
||||
list_for_each_prev (i, &(cfg->nodes)) {
|
||||
RConfigNode *bt = list_entry (i, RConfigNode, list);
|
||||
if (bt->hash == hash)
|
||||
return bt;
|
||||
}
|
||||
return NULL;
|
||||
return r_hashtable_lookup (cfg->ht, r_str_hash (name));
|
||||
}
|
||||
|
||||
R_API const char *r_config_get(RConfig *cfg, const char *name) {
|
||||
|
@ -84,14 +73,10 @@ R_API ut64 r_config_get_i(RConfig *cfg, const char *name) {
|
|||
return (ut64)0LL;
|
||||
}
|
||||
|
||||
// TODO: use typedef declaration here
|
||||
R_API RConfigNode *r_config_set_cb(RConfig *cfg, const char *name, const char *value, int (*callback)(void *user, void *data))
|
||||
{
|
||||
RConfigNode *node;
|
||||
node = r_config_set(cfg, name, value);
|
||||
node->callback = callback;
|
||||
if (node->callback)
|
||||
node->callback(cfg->user, node);
|
||||
R_API RConfigNode *r_config_set_cb(RConfig *cfg, const char *name, const char *value, RConfigCallback cb) {
|
||||
RConfigNode *node = r_config_set (cfg, name, value);
|
||||
if ((node->callback = cb))
|
||||
cb (cfg->user, node);
|
||||
return node;
|
||||
}
|
||||
|
||||
|
@ -107,12 +92,9 @@ R_API RConfigNode *r_config_set(RConfig *cfg, const char *name, const char *valu
|
|||
RConfigNode *node;
|
||||
char *ov = NULL;
|
||||
ut64 oi;
|
||||
|
||||
if (name[0] == '\0')
|
||||
if (strnull (name))
|
||||
return NULL;
|
||||
|
||||
node = r_config_node_get (cfg, name);
|
||||
|
||||
// TODO: store old value somewhere..
|
||||
if (node) {
|
||||
if (node->flags & CN_RO) {
|
||||
|
@ -141,17 +123,16 @@ R_API RConfigNode *r_config_set(RConfig *cfg, const char *name, const char *valu
|
|||
}
|
||||
}
|
||||
} else {
|
||||
if (cfg->lock) {
|
||||
eprintf ("config is locked: cannot create '%s'\n", name);
|
||||
} else {
|
||||
if (!cfg->lock) {
|
||||
node = r_config_node_new (name, value);
|
||||
if (value && (!strcmp(value,"true")||!strcmp(value,"false"))) {
|
||||
node->flags|=CN_BOOL;
|
||||
node->i_value = (!strcmp(value,"true"))?1:0;
|
||||
}
|
||||
list_add_tail (&(node->list), &(cfg->nodes));
|
||||
r_hashtable_insert (cfg->ht, node->hash, node);
|
||||
r_list_append (cfg->nodes, node);
|
||||
cfg->n_nodes++;
|
||||
}
|
||||
} else eprintf ("config is locked: cannot create '%s'\n", name);
|
||||
}
|
||||
|
||||
if (node && node->callback) {
|
||||
|
@ -169,7 +150,8 @@ R_API RConfigNode *r_config_set(RConfig *cfg, const char *name, const char *valu
|
|||
R_API int r_config_rm(RConfig *cfg, const char *name) {
|
||||
RConfigNode *node = r_config_node_get (cfg, name);
|
||||
if (node) {
|
||||
list_del (&(node->list));
|
||||
r_hashtable_remove (cfg->ht, node->hash);
|
||||
r_list_delete_data (cfg->nodes, node);
|
||||
cfg->n_nodes--;
|
||||
return R_TRUE;
|
||||
}
|
||||
|
@ -177,9 +159,8 @@ R_API int r_config_rm(RConfig *cfg, const char *name) {
|
|||
}
|
||||
|
||||
R_API RConfigNode *r_config_set_i(RConfig *cfg, const char *name, const ut64 i) {
|
||||
char buf[128];
|
||||
char *ov = NULL;
|
||||
ut64 oi;
|
||||
char buf[128], *ov = NULL;
|
||||
RConfigNode *node = r_config_node_get (cfg, name);
|
||||
|
||||
if (node) {
|
||||
|
@ -199,16 +180,16 @@ R_API RConfigNode *r_config_set_i(RConfig *cfg, const char *name, const ut64 i)
|
|||
//node->flags = CN_RW | CN_INT;
|
||||
node->i_value = i;
|
||||
} else {
|
||||
if (cfg->lock) {
|
||||
eprintf ("(locked: no new keys can be created)");
|
||||
} else {
|
||||
sprintf(buf, "0x%08"PFMT64x"", i);
|
||||
if (!cfg->lock) {
|
||||
if (i<1024) sprintf (buf, "%"PFMT64d"", i);
|
||||
else sprintf (buf, "0x%08"PFMT64x"", i);
|
||||
node = r_config_node_new (name, buf);
|
||||
node->flags = CN_RW | CN_OFFT;
|
||||
node->i_value = i;
|
||||
list_add_tail(&(node->list), &(cfg->nodes));
|
||||
r_hashtable_insert (cfg->ht, node->hash, node);
|
||||
r_list_append (cfg->nodes, node);
|
||||
cfg->n_nodes++;
|
||||
}
|
||||
} else eprintf ("(locked: no new keys can be created)");
|
||||
}
|
||||
|
||||
if (node && node->callback) {
|
||||
|
@ -274,28 +255,29 @@ R_API void r_config_lock(RConfig *cfg, int l) {
|
|||
}
|
||||
|
||||
R_API RConfig *r_config_new(void *user) {
|
||||
RConfig *cfg;
|
||||
|
||||
cfg = R_NEW (RConfig);
|
||||
RConfig *cfg = R_NEW (RConfig);
|
||||
if (cfg) {
|
||||
cfg->ht = r_hashtable_new ();
|
||||
cfg->nodes = r_list_new ();
|
||||
cfg->nodes->free = free;
|
||||
cfg->user = user;
|
||||
cfg->n_nodes = 0;
|
||||
cfg->lock = 0;
|
||||
cfg->printf = (void *)printf;
|
||||
INIT_LIST_HEAD (&(cfg->nodes));
|
||||
}
|
||||
return cfg;
|
||||
}
|
||||
|
||||
R_API int r_config_free(RConfig *cfg) {
|
||||
// TODO: Free node list
|
||||
// XXX: memory leak ! r_list_destroy (cfg->nodes);
|
||||
r_list_free (cfg->nodes);
|
||||
r_hashtable_free (cfg->ht);
|
||||
free (cfg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
R_API void r_config_visual_hit_i(RConfig *cfg, const char *name, int delta) {
|
||||
RConfigNode *node =
|
||||
r_config_node_get(cfg, name);
|
||||
RConfigNode *node = r_config_node_get (cfg, name);
|
||||
if (node && (node->flags & CN_INT || node->flags & CN_OFFT))
|
||||
r_config_set_i(cfg, name, r_config_get_i(cfg, name)+delta);
|
||||
}
|
||||
|
|
|
@ -90,7 +90,6 @@ static const char *radare_argv[] = {
|
|||
static const char *tmp_argv[TMP_ARGV_SZ];
|
||||
static int autocomplete(RLine *line) {
|
||||
RCore *core = line->user;
|
||||
struct list_head *pos;
|
||||
RListIter *iter;
|
||||
RFlagItem *flag;
|
||||
if (core) {
|
||||
|
@ -181,9 +180,10 @@ printf ("FILEN %d\n", n);
|
|||
line->completion.argv = tmp_argv;
|
||||
} else
|
||||
if (!memcmp (line->buffer.data, "e ", 2)) {
|
||||
RConfigNode *bt;
|
||||
RListIter *iter;
|
||||
int i = 0, n = strlen (line->buffer.data+2);
|
||||
list_for_each_prev (pos, &core->config->nodes) {
|
||||
RConfigNode *bt = list_entry(pos, RConfigNode, list);
|
||||
r_list_foreach (core->config->nodes, iter, bt) {
|
||||
if (!memcmp (bt->name, line->buffer.data+2, n)) {
|
||||
tmp_argv[i++] = bt->name;
|
||||
if (i==TMP_ARGV_SZ)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* radare - LGPL - Copyright 2010 - nibble<develsec.org> */
|
||||
/* radare - LGPL - Copyright 2010-2011 - nibble<develsec.org> */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
@ -12,7 +12,6 @@ R_API int r_core_gdiff(RCore *c, RCore *c2) {
|
|||
RAnalFcn *fcn;
|
||||
RAnalBlock *bb;
|
||||
RListIter *iter, *iter2;
|
||||
ut8 *buf;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
|
|
|
@ -303,8 +303,9 @@ static void config_visual_hit(RCore *core, const char *name) {
|
|||
}
|
||||
|
||||
R_API void r_core_visual_config(RCore *core) {
|
||||
RListIter *iter;
|
||||
RConfigNode *bt;
|
||||
char cmd[1024];
|
||||
struct list_head *pos;
|
||||
#define MAX_FORMAT 2
|
||||
char *fs = NULL;
|
||||
char *fs2 = NULL;
|
||||
|
@ -327,8 +328,7 @@ R_API void r_core_visual_config(RCore *core) {
|
|||
r_cons_printf ("\n Eval spaces:\n\n");
|
||||
hit = 0;
|
||||
j = i = 0;
|
||||
list_for_each(pos, &(core->config->nodes)) {
|
||||
struct r_config_node_t *bt = list_entry(pos, struct r_config_node_t, list);
|
||||
r_list_foreach (core->config->nodes, iter, bt) {
|
||||
if (option==i) {
|
||||
fs = bt->name;
|
||||
hit = 1;
|
||||
|
@ -360,8 +360,7 @@ R_API void r_core_visual_config(RCore *core) {
|
|||
hit = 0;
|
||||
j = i = 0;
|
||||
// TODO: cut -d '.' -f 1 | sort | uniq !!!
|
||||
list_for_each (pos, &(core->config->nodes)) {
|
||||
RConfigNode *bt = list_entry (pos, RConfigNode, list);
|
||||
r_list_foreach (core->config->nodes, iter, bt) {
|
||||
if (option==i) {
|
||||
fs2 = bt->name;
|
||||
hit = 1;
|
||||
|
|
|
@ -23,3 +23,9 @@ DROP TABLE flags
|
|||
INSERT INTO flags (name, offset) VALUES ("patata", 33)
|
||||
|
||||
UPDATE flags SET offset=33 WHERE offset==20
|
||||
|
||||
STORE
|
||||
- ut32
|
||||
- ut64
|
||||
- Endianness matterz
|
||||
- RList *get_range (0, 4096)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* radare - LGPL - Copyright 2009-2010 pancake<nopcode.org> */
|
||||
/* radare - LGPL - Copyright 2009-2011 pancake<nopcode.org> */
|
||||
|
||||
#include "r_db.h"
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
/* radare - LGPL - Copyright 2009-2011 pancake<nopcode.org> */
|
||||
|
||||
#include "r_db.h"
|
||||
#include "r_util.h"
|
||||
/*
|
||||
|
@ -14,7 +16,7 @@ sizes['i'] = 4;
|
|||
struct r_db_table_t *r_db_table_new(const char *name, const char *fmt, const char *fields) {
|
||||
int i;
|
||||
int offset = 0;
|
||||
struct r_db_table_t *table = R_NEW(struct r_db_table_t);
|
||||
struct r_db_table_t *table = R_NEW (RDatabaseTable);
|
||||
table->args = strdup (fields);
|
||||
table->nelems = r_str_word_set0 (table->args);
|
||||
if (table->nelems != strlen (fmt)) {
|
||||
|
|
|
@ -16,7 +16,7 @@ typedef int (*RConfigCallback)(void *user, void *data);
|
|||
|
||||
typedef struct r_config_node_t {
|
||||
char *name;
|
||||
int hash;
|
||||
ut32 hash;
|
||||
int flags;
|
||||
char *value;
|
||||
ut64 i_value;
|
||||
|
@ -24,7 +24,6 @@ typedef struct r_config_node_t {
|
|||
int *cb_ptr_i;
|
||||
char **cb_ptr_s;
|
||||
RConfigCallback callback;
|
||||
struct list_head list;
|
||||
} RConfigNode;
|
||||
|
||||
typedef struct r_config_t {
|
||||
|
@ -32,8 +31,9 @@ typedef struct r_config_t {
|
|||
int last_notfound;
|
||||
int n_nodes;
|
||||
void *user;
|
||||
void (*printf)(const char *str, ...);
|
||||
struct list_head nodes;
|
||||
PrintfCallback printf;
|
||||
RList *nodes;
|
||||
RHashTable *ht;
|
||||
} RConfig;
|
||||
|
||||
#ifdef R_API
|
||||
|
|
|
@ -49,6 +49,7 @@ R_API void r_list_sort(RList *list, RListComparator cmp);
|
|||
|
||||
R_API void r_list_init(RList *list);
|
||||
R_API void r_list_delete (RList *list, RListIter *iter);
|
||||
R_API boolt r_list_delete_data (RList *list, void *ptr);
|
||||
R_API void r_list_iter_init (RListIter *iter, RList *list);
|
||||
R_API void r_list_destroy (RList *list);
|
||||
R_API void r_list_free (RList *list);
|
||||
|
|
|
@ -243,7 +243,7 @@ R_API char *r_str_trim(char *str);
|
|||
R_API char *r_str_trim_head(char *str);
|
||||
R_API char *r_str_trim_tail(char *str);
|
||||
R_API char *r_str_trim_head_tail(char *str);
|
||||
R_API int r_str_hash(const char *str);
|
||||
R_API ut32 r_str_hash(const char *str);
|
||||
R_API ut64 r_str_hash64(const char *str);
|
||||
R_API char *r_str_clean(char *str);
|
||||
R_API int r_str_nstr(char *from, char *to, int size);
|
||||
|
@ -383,6 +383,50 @@ R_API void r_big_div(RNumBig *c, RNumBig *a, RNumBig *b);
|
|||
R_API void r_big_div_ut(RNumBig *a, RNumBig *b, ut32 c);
|
||||
R_API int r_big_divisible_ut(RNumBig *n, ut32 v);
|
||||
R_API void r_big_mod(RNumBig *c, RNumBig *a, RNumBig *b);
|
||||
|
||||
/** hashtable **/
|
||||
typedef struct r_hashtable_entry_t {
|
||||
ut32 hash;
|
||||
void *data;
|
||||
} RHashTableEntry;
|
||||
|
||||
typedef struct r_hashtable_t {
|
||||
RHashTableEntry *table;
|
||||
ut32 size;
|
||||
ut32 rehash;
|
||||
ut32 max_entries;
|
||||
ut32 size_index;
|
||||
ut32 entries;
|
||||
ut32 deleted_entries;
|
||||
} RHashTable;
|
||||
|
||||
typedef struct r_hashtable64_entry_t {
|
||||
ut64 hash;
|
||||
void *data;
|
||||
} RHashTable64Entry;
|
||||
|
||||
typedef struct r_hashtable64_t {
|
||||
RHashTable64Entry *table;
|
||||
ut64 size;
|
||||
ut64 rehash;
|
||||
ut64 max_entries;
|
||||
ut64 size_index;
|
||||
ut64 entries;
|
||||
ut64 deleted_entries;
|
||||
} RHashTable64;
|
||||
|
||||
|
||||
R_API RHashTable* r_hashtable_new(void);
|
||||
R_API void r_hashtable_free(RHashTable *ht);
|
||||
R_API void *r_hashtable_lookup(RHashTable *ht, ut32 hash);
|
||||
R_API boolt r_hashtable_insert(RHashTable *ht, ut32 hash, void *data);
|
||||
R_API void r_hashtable_remove(RHashTable *ht, ut32 hash);
|
||||
|
||||
R_API RHashTable64* r_hashtable64_new(void);
|
||||
R_API void r_hashtable64_free(RHashTable64 *ht);
|
||||
R_API void *r_hashtable64_lookup(RHashTable64 *ht, ut64 hash);
|
||||
R_API boolt r_hashtable64_insert(RHashTable64 *ht, ut64 hash, void *data);
|
||||
R_API void r_hashtable64_remove(RHashTable64 *ht, ut64 hash);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,6 +3,7 @@ include ../config.mk
|
|||
NAME=r_util
|
||||
OBJ=mem.o pool.o num.o str.o re.o hex.o file.o alloca.o range.o log.o
|
||||
OBJ+=prof.o cache.o sys.o btree.o buf.o list.o flist.o w32-sys.o base64.o
|
||||
OBJ+=ht.o ht64.o
|
||||
ifeq (${HAVE_LIB_GMP},1)
|
||||
OBJ+=big-gmp.o
|
||||
else
|
||||
|
@ -16,3 +17,7 @@ endif
|
|||
LDFLAGS+=${BN_LIBS}
|
||||
|
||||
include ../rules.mk
|
||||
|
||||
ht64:
|
||||
cat ht.c | sed -e s,hashtable,hashtable64,g -e s,HashTable,HashTable64,g -e s,ut32,ut64,g > ht64.c
|
||||
#cat ht.c ht64.c | sed -e 's,) {,);,'
|
||||
|
|
|
@ -0,0 +1,235 @@
|
|||
/*
|
||||
* Copyright © 2009 Intel Corporation
|
||||
* Copyright © 1988-2004 Keith Packard and Bart Massey.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the names of the authors
|
||||
* or their institutions shall not be used in advertising or
|
||||
* otherwise to promote the sale, use or other dealings in this
|
||||
* Software without prior written authorization from the
|
||||
* authors.
|
||||
*
|
||||
* Authors:
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
* Keith Packard <keithp@keithp.com>
|
||||
* Integration in r2 core api
|
||||
* pancake <nopcode.org>
|
||||
*/
|
||||
|
||||
#include <r_util.h>
|
||||
|
||||
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
|
||||
|
||||
/*
|
||||
* From Knuth -- a good choice for hash/rehash values is p, p-2 where
|
||||
* p and p-2 are both prime. These tables are sized to have an extra 10%
|
||||
* free to avoid exponential performance degradation as the hash table fills
|
||||
*/
|
||||
|
||||
static const ut32 deleted_data;
|
||||
|
||||
static const struct {
|
||||
ut32 max_entries, size, rehash;
|
||||
} hash_sizes[] = {
|
||||
{ 2, 5, 3 },
|
||||
{ 4, 7, 5 },
|
||||
{ 8, 13, 11 },
|
||||
{ 16, 19, 17 },
|
||||
{ 32, 43, 41 },
|
||||
{ 64, 73, 71 },
|
||||
{ 128, 151, 149 },
|
||||
{ 256, 283, 281 },
|
||||
{ 512, 571, 569 },
|
||||
{ 1024, 1153, 1151 },
|
||||
{ 2048, 2269, 2267 },
|
||||
{ 4096, 4519, 4517 },
|
||||
{ 8192, 9013, 9011 },
|
||||
{ 16384, 18043, 18041 },
|
||||
{ 32768, 36109, 36107 },
|
||||
{ 65536, 72091, 72089 },
|
||||
{ 131072, 144409, 144407 },
|
||||
{ 262144, 288361, 288359 },
|
||||
{ 524288, 576883, 576881 },
|
||||
{ 1048576, 1153459, 1153457 },
|
||||
{ 2097152, 2307163, 2307161 },
|
||||
{ 4194304, 4613893, 4613891 },
|
||||
{ 8388608, 9227641, 9227639 },
|
||||
{ 16777216, 18455029, 18455027 },
|
||||
{ 33554432, 36911011, 36911009 },
|
||||
{ 67108864, 73819861, 73819859 },
|
||||
{ 134217728, 147639589, 147639587 },
|
||||
{ 268435456, 295279081, 295279079 },
|
||||
{ 536870912, 590559793, 590559791 },
|
||||
{ 1073741824, 1181116273, 1181116271},
|
||||
{ 2147483648ul, 2362232233ul, 2362232231ul}
|
||||
};
|
||||
|
||||
#define entry_is_free(x) (!x->data)
|
||||
#define entry_is_deleted(x) (x->data==&deleted_data)
|
||||
#define entry_is_present(x) (x->data && x->data != &deleted_data)
|
||||
|
||||
/**
|
||||
* Finds a hash table entry with the given key and hash of that key.
|
||||
*
|
||||
* Returns NULL if no entry is found. Note that the data pointer may be
|
||||
* modified by the user.
|
||||
*/
|
||||
static RHashTableEntry* r_hashtable_search(RHashTable *ht, ut32 hash) {
|
||||
ut32 double_hash, hash_address = hash % ht->size;
|
||||
do {
|
||||
RHashTableEntry *entry = ht->table + hash_address;
|
||||
if (entry_is_free (entry))
|
||||
return NULL;
|
||||
if (entry_is_present (entry) && entry->hash == hash)
|
||||
return entry;
|
||||
double_hash = hash % ht->rehash;
|
||||
if (double_hash == 0)
|
||||
double_hash = 1;
|
||||
hash_address = (hash_address + double_hash) % ht->size;
|
||||
} while (hash_address != hash % ht->size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void r_hashtable_rehash(RHashTable *ht, int new_size_index) {
|
||||
RHashTable old_ht = *ht;
|
||||
RHashTableEntry *e;
|
||||
if (new_size_index >= ARRAY_SIZE (hash_sizes))
|
||||
return;
|
||||
// XXX: This code is redupped! fuck't
|
||||
ht->table = malloc (hash_sizes[new_size_index].size * sizeof (*ht->table));
|
||||
if (!ht->table)
|
||||
return;
|
||||
ht->size_index = new_size_index;
|
||||
ht->size = hash_sizes[ht->size_index].size;
|
||||
ht->rehash = hash_sizes[ht->size_index].rehash;
|
||||
ht->max_entries = hash_sizes[ht->size_index].max_entries;
|
||||
ht->entries = 0;
|
||||
ht->deleted_entries = 0;
|
||||
for (e = old_ht.table; e != old_ht.table + old_ht.size; e++) {
|
||||
if (entry_is_present (e))
|
||||
r_hashtable_insert (ht, e->hash, e->data);
|
||||
}
|
||||
free (old_ht.table);
|
||||
}
|
||||
|
||||
R_API RHashTable* r_hashtable_new(void) {
|
||||
RHashTable *ht = malloc (sizeof (*ht));
|
||||
if (!ht)
|
||||
return NULL;
|
||||
// TODO: use slices here
|
||||
ht->table = malloc (ht->size * sizeof (*ht->table));
|
||||
if (!ht->table) {
|
||||
free (ht);
|
||||
return NULL;
|
||||
}
|
||||
ht->size_index = 0;
|
||||
ht->entries = 0;
|
||||
ht->deleted_entries = 0;
|
||||
ht->size = hash_sizes[ht->size_index].size;
|
||||
ht->rehash = hash_sizes[ht->size_index].rehash;
|
||||
ht->max_entries = hash_sizes[ht->size_index].max_entries;
|
||||
return ht;
|
||||
}
|
||||
|
||||
R_API void r_hashtable_free(RHashTable *ht) {
|
||||
if (ht) free (ht->table), free (ht);
|
||||
}
|
||||
|
||||
R_API void *r_hashtable_lookup(RHashTable *ht, ut32 hash) {
|
||||
RHashTableEntry *entry = r_hashtable_search (ht, hash);
|
||||
return entry? entry->data : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the data with the given hash into the table.
|
||||
*
|
||||
* Note that insertion may rearrange the table on a resize or rehash,
|
||||
* so previously found hash_entries are no longer valid after this function.
|
||||
*/
|
||||
R_API boolt r_hashtable_insert(RHashTable *ht, ut32 hash, void *data) {
|
||||
ut32 hash_address;
|
||||
|
||||
if (ht->entries >= ht->max_entries)
|
||||
r_hashtable_rehash (ht, ht->size_index + 1);
|
||||
else if (ht->deleted_entries + ht->entries >= ht->max_entries)
|
||||
r_hashtable_rehash (ht, ht->size_index);
|
||||
|
||||
hash_address = hash % ht->size;
|
||||
do {
|
||||
RHashTableEntry *entry = ht->table + hash_address;
|
||||
ut32 double_hash;
|
||||
|
||||
if (!entry_is_present (entry)) {
|
||||
if (entry_is_deleted (entry))
|
||||
ht->deleted_entries--;
|
||||
entry->hash = hash;
|
||||
entry->data = data;
|
||||
ht->entries++;
|
||||
return R_TRUE;
|
||||
}
|
||||
|
||||
double_hash = hash % ht->rehash;
|
||||
if (double_hash == 0)
|
||||
double_hash = 1;
|
||||
hash_address = (hash_address + double_hash) % ht->size;
|
||||
} while (hash_address != hash % ht->size);
|
||||
|
||||
/* We could hit here if a required resize failed. An unchecked-malloc
|
||||
* application could ignore this result.
|
||||
*/
|
||||
return R_FALSE;
|
||||
}
|
||||
|
||||
R_API void r_hashtable_remove(RHashTable *ht, ut32 hash) {
|
||||
RHashTableEntry *entry = r_hashtable_search (ht, hash);
|
||||
if (entry) {
|
||||
entry->data = (void *) &deleted_data;
|
||||
ht->entries--;
|
||||
ht->deleted_entries++;
|
||||
}
|
||||
}
|
||||
|
||||
#if TEST
|
||||
int main () {
|
||||
const char *str;
|
||||
int ret;
|
||||
RHashTable *ht = r_hashtable_new ();
|
||||
#define HASH 268453705
|
||||
|
||||
ret = r_hashtable_insert (ht, HASH, "patata");
|
||||
if (!ret)
|
||||
printf ("Cannot reinsert !!1\n");
|
||||
|
||||
str = r_hashtable_lookup (ht, HASH);
|
||||
if (str) printf ("String is (%s)\n", str);
|
||||
else printf ("Cannot find string\n");
|
||||
|
||||
r_hashtable_remove (ht, HASH);
|
||||
|
||||
str = r_hashtable_lookup (ht, HASH);
|
||||
if (str) printf ("String is (%s)\n", str);
|
||||
else printf("Cannot find string which is ok :)\n");
|
||||
|
||||
r_hashtable_search (ht, HASH);
|
||||
|
||||
r_hashtable_free (ht);
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
* Copyright © 2009 Intel Corporation
|
||||
* Copyright © 1988-2004 Keith Packard and Bart Massey.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the names of the authors
|
||||
* or their institutions shall not be used in advertising or
|
||||
* otherwise to promote the sale, use or other dealings in this
|
||||
* Software without prior written authorization from the
|
||||
* authors.
|
||||
*
|
||||
* Authors:
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
* Keith Packard <keithp@keithp.com>
|
||||
* Integration in r2 core api
|
||||
* pancake <nopcode.org>
|
||||
*/
|
||||
|
||||
#include <r_util.h>
|
||||
|
||||
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
|
||||
|
||||
/*
|
||||
* From Knuth -- a good choice for hash/rehash values is p, p-2 where
|
||||
* p and p-2 are both prime. These tables are sized to have an extra 10%
|
||||
* free to avoid exponential performance degradation as the hash table fills
|
||||
*/
|
||||
|
||||
static const ut64 deleted_data;
|
||||
|
||||
static const struct {
|
||||
ut64 max_entries, size, rehash;
|
||||
} hash_sizes[] = {
|
||||
{ 2, 5, 3 },
|
||||
{ 4, 7, 5 },
|
||||
{ 8, 13, 11 },
|
||||
{ 16, 19, 17 },
|
||||
{ 32, 43, 41 },
|
||||
{ 64, 73, 71 },
|
||||
{ 128, 151, 149 },
|
||||
{ 256, 283, 281 },
|
||||
{ 512, 571, 569 },
|
||||
{ 1024, 1153, 1151 },
|
||||
{ 2048, 2269, 2267 },
|
||||
{ 4096, 4519, 4517 },
|
||||
{ 8192, 9013, 9011 },
|
||||
{ 16384, 18043, 18041 },
|
||||
{ 32768, 36109, 36107 },
|
||||
{ 65536, 72091, 72089 },
|
||||
{ 131072, 144409, 144407 },
|
||||
{ 262144, 288361, 288359 },
|
||||
{ 524288, 576883, 576881 },
|
||||
{ 1048576, 1153459, 1153457 },
|
||||
{ 2097152, 2307163, 2307161 },
|
||||
{ 4194304, 4613893, 4613891 },
|
||||
{ 8388608, 9227641, 9227639 },
|
||||
{ 16777216, 18455029, 18455027 },
|
||||
{ 33554432, 36911011, 36911009 },
|
||||
{ 67108864, 73819861, 73819859 },
|
||||
{ 134217728, 147639589, 147639587 },
|
||||
{ 268435456, 295279081, 295279079 },
|
||||
{ 536870912, 590559793, 590559791 },
|
||||
{ 1073741824, 1181116273, 1181116271},
|
||||
{ 2147483648ul, 2362232233ul, 2362232231ul}
|
||||
};
|
||||
|
||||
#define entry_is_free(x) (!x->data)
|
||||
#define entry_is_deleted(x) (x->data==&deleted_data)
|
||||
#define entry_is_present(x) (x->data && x->data != &deleted_data)
|
||||
|
||||
/**
|
||||
* Finds a hash table entry with the given key and hash of that key.
|
||||
*
|
||||
* Returns NULL if no entry is found. Note that the data pointer may be
|
||||
* modified by the user.
|
||||
*/
|
||||
static RHashTable64Entry* r_hashtable64_search(RHashTable64 *ht, ut64 hash) {
|
||||
ut64 double_hash, hash_address = hash % ht->size;
|
||||
do {
|
||||
RHashTable64Entry *entry = ht->table + hash_address;
|
||||
if (entry_is_free (entry))
|
||||
return NULL;
|
||||
if (entry_is_present (entry) && entry->hash == hash)
|
||||
return entry;
|
||||
double_hash = hash % ht->rehash;
|
||||
if (double_hash == 0)
|
||||
double_hash = 1;
|
||||
hash_address = (hash_address + double_hash) % ht->size;
|
||||
} while (hash_address != hash % ht->size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void r_hashtable64_rehash(RHashTable64 *ht, int new_size_index) {
|
||||
RHashTable64 old_ht = *ht;
|
||||
RHashTable64Entry *e;
|
||||
if (new_size_index >= ARRAY_SIZE (hash_sizes))
|
||||
return;
|
||||
// XXX: This code is redupped! fuck't
|
||||
ht->table = malloc (hash_sizes[new_size_index].size * sizeof (*ht->table));
|
||||
if (!ht->table)
|
||||
return;
|
||||
ht->size_index = new_size_index;
|
||||
ht->size = hash_sizes[ht->size_index].size;
|
||||
ht->rehash = hash_sizes[ht->size_index].rehash;
|
||||
ht->max_entries = hash_sizes[ht->size_index].max_entries;
|
||||
ht->entries = 0;
|
||||
ht->deleted_entries = 0;
|
||||
for (e = old_ht.table; e != old_ht.table + old_ht.size; e++) {
|
||||
if (entry_is_present (e))
|
||||
r_hashtable64_insert (ht, e->hash, e->data);
|
||||
}
|
||||
free (old_ht.table);
|
||||
}
|
||||
|
||||
R_API RHashTable64* r_hashtable64_new(void) {
|
||||
RHashTable64 *ht = malloc (sizeof (*ht));
|
||||
if (!ht)
|
||||
return NULL;
|
||||
// TODO: use slices here
|
||||
ht->table = malloc (ht->size * sizeof (*ht->table));
|
||||
if (!ht->table) {
|
||||
free (ht);
|
||||
return NULL;
|
||||
}
|
||||
ht->size_index = 0;
|
||||
ht->entries = 0;
|
||||
ht->deleted_entries = 0;
|
||||
ht->size = hash_sizes[ht->size_index].size;
|
||||
ht->rehash = hash_sizes[ht->size_index].rehash;
|
||||
ht->max_entries = hash_sizes[ht->size_index].max_entries;
|
||||
return ht;
|
||||
}
|
||||
|
||||
R_API void r_hashtable64_free(RHashTable64 *ht) {
|
||||
if (ht) free (ht->table), free (ht);
|
||||
}
|
||||
|
||||
R_API void *r_hashtable64_lookup(RHashTable64 *ht, ut64 hash) {
|
||||
RHashTable64Entry *entry = r_hashtable64_search (ht, hash);
|
||||
return entry? entry->data : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the data with the given hash into the table.
|
||||
*
|
||||
* Note that insertion may rearrange the table on a resize or rehash,
|
||||
* so previously found hash_entries are no longer valid after this function.
|
||||
*/
|
||||
R_API boolt r_hashtable64_insert(RHashTable64 *ht, ut64 hash, void *data) {
|
||||
ut64 hash_address;
|
||||
|
||||
if (ht->entries >= ht->max_entries)
|
||||
r_hashtable64_rehash (ht, ht->size_index + 1);
|
||||
else if (ht->deleted_entries + ht->entries >= ht->max_entries)
|
||||
r_hashtable64_rehash (ht, ht->size_index);
|
||||
|
||||
hash_address = hash % ht->size;
|
||||
do {
|
||||
RHashTable64Entry *entry = ht->table + hash_address;
|
||||
ut64 double_hash;
|
||||
|
||||
if (!entry_is_present (entry)) {
|
||||
if (entry_is_deleted (entry))
|
||||
ht->deleted_entries--;
|
||||
entry->hash = hash;
|
||||
entry->data = data;
|
||||
ht->entries++;
|
||||
return R_TRUE;
|
||||
}
|
||||
|
||||
double_hash = hash % ht->rehash;
|
||||
if (double_hash == 0)
|
||||
double_hash = 1;
|
||||
hash_address = (hash_address + double_hash) % ht->size;
|
||||
} while (hash_address != hash % ht->size);
|
||||
|
||||
/* We could hit here if a required resize failed. An unchecked-malloc
|
||||
* application could ignore this result.
|
||||
*/
|
||||
return R_FALSE;
|
||||
}
|
||||
|
||||
R_API void r_hashtable64_remove(RHashTable64 *ht, ut64 hash) {
|
||||
RHashTable64Entry *entry = r_hashtable64_search (ht, hash);
|
||||
if (entry) {
|
||||
entry->data = (void *) &deleted_data;
|
||||
ht->entries--;
|
||||
ht->deleted_entries++;
|
||||
}
|
||||
}
|
||||
|
||||
#if TEST
|
||||
int main () {
|
||||
const char *str;
|
||||
int ret;
|
||||
RHashTable64 *ht = r_hashtable64_new ();
|
||||
|
||||
ret = r_hashtable64_insert (ht, 33, "patata");
|
||||
if (!ret)
|
||||
printf ("Cannot reinsert !!1\n");
|
||||
|
||||
str = r_hashtable64_lookup (ht, 33);
|
||||
if (str) printf ("String is (%s)\n", str);
|
||||
else printf ("Cannot find string\n");
|
||||
|
||||
r_hashtable64_remove (ht, 33);
|
||||
|
||||
str = r_hashtable64_lookup (ht, 33);
|
||||
if (str) printf ("String is (%s)\n", str);
|
||||
else printf("Cannot find string\n");
|
||||
|
||||
r_hashtable64_search (ht, 33);
|
||||
|
||||
r_hashtable64_free (ht);
|
||||
}
|
||||
#endif
|
|
@ -1,3 +1,5 @@
|
|||
/* radare - LGPL - Copyright 2007-2011 pancake<nopcode.org> */
|
||||
|
||||
#include "r_util.h"
|
||||
|
||||
R_API void r_list_init(RList *list) {
|
||||
|
@ -42,14 +44,22 @@ R_API void r_list_split (RList *list, void *ptr) {
|
|||
}
|
||||
|
||||
R_API void r_list_split_iter (RList *list, RListIter *iter) {
|
||||
if (list->head == iter)
|
||||
list->head = iter->n;
|
||||
if (list->tail == iter)
|
||||
list->tail = iter->p;
|
||||
if (iter->p)
|
||||
iter->p->n = iter->n;
|
||||
if (iter->n)
|
||||
iter->n->p = iter->p;
|
||||
if (list->head == iter) list->head = iter->n;
|
||||
if (list->tail == iter) list->tail = iter->p;
|
||||
if (iter->p) iter->p->n = iter->n;
|
||||
if (iter->n) iter->n->p = iter->p;
|
||||
}
|
||||
|
||||
R_API boolt r_list_delete_data (RList *list, void *ptr) {
|
||||
void *p;
|
||||
RListIter *iter;
|
||||
r_list_foreach (list, iter, p) {
|
||||
if (ptr == p) {
|
||||
r_list_delete (list, iter);
|
||||
return R_TRUE;
|
||||
}
|
||||
}
|
||||
return R_FALSE;
|
||||
}
|
||||
|
||||
R_API void r_list_delete (RList *list, RListIter *iter) {
|
||||
|
@ -75,12 +85,15 @@ R_API void r_list_destroy (RList *list) {
|
|||
RListIter *next = it->n;
|
||||
r_list_delete (list, it);
|
||||
it = next;
|
||||
// free (it);
|
||||
}
|
||||
list->head = list->tail = NULL;
|
||||
}
|
||||
//free (list);
|
||||
}
|
||||
|
||||
R_API void r_list_free (RList *list) {
|
||||
list->free = NULL;
|
||||
r_list_destroy (list);
|
||||
free (list);
|
||||
}
|
||||
|
@ -362,7 +375,7 @@ int main () {
|
|||
}
|
||||
|
||||
r_list_free (l);
|
||||
r_list_free (list);
|
||||
//r_list_free (l);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -174,8 +174,8 @@ R_API ut64 r_str_hash64(const char *str) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
R_API int r_str_hash(const char *str) {
|
||||
int ret = 0;
|
||||
R_API ut32 r_str_hash(const char *str) {
|
||||
ut32 ret = 0;
|
||||
for (;*str; str++)
|
||||
ret ^= (ret<<7 | *str);
|
||||
return ret;
|
||||
|
|
Loading…
Reference in New Issue