* 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:
pancake 2011-03-17 19:05:39 +01:00
parent c6a579a291
commit 3d142e8ec1
17 changed files with 658 additions and 142 deletions

1
TODO
View File

@ -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

View File

@ -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;

View File

@ -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);
}

View File

@ -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)

View File

@ -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++) {

View File

@ -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;

View File

@ -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)

View File

@ -1,4 +1,4 @@
/* radare - LGPL - Copyright 2009-2010 pancake<nopcode.org> */
/* radare - LGPL - Copyright 2009-2011 pancake<nopcode.org> */
#include "r_db.h"

View File

@ -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)) {

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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,) {,);,'

235
libr/util/ht.c Normal file
View File

@ -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

234
libr/util/ht64.c Normal file
View File

@ -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

View File

@ -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;
}

View File

@ -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;