mirror of
https://github.com/radareorg/radare2.git
synced 2024-11-27 15:10:53 +00:00
New io.buffer cache system and refactorized RHashTable
Implement io.buffer for fast IO (work in progress) Rewrite util/cache.c and use it form io/buffer.c Refactor util/ht.c and util/ht64.c to reuse code Various minor fixes in RIO api cache.c must be rewritten into r_buf for
This commit is contained in:
parent
ebe2f35630
commit
60a951e9b1
@ -1,4 +1,4 @@
|
||||
/* radare - LGPL - Copyright 2009-2012 - pancake */
|
||||
/* radare - LGPL - Copyright 2009-2013 - pancake */
|
||||
|
||||
#include <r_core.h>
|
||||
|
||||
@ -44,6 +44,22 @@ static int config_iomaxblk_callback(void *user, void *data) {
|
||||
return R_TRUE;
|
||||
}
|
||||
|
||||
static int config_iobuffer_callback(void *user, void *data) {
|
||||
RCore *core = (RCore *) user;
|
||||
RConfigNode *node = (RConfigNode *) data;
|
||||
if (node->i_value) {
|
||||
ut64 from, to;
|
||||
from = r_config_get_i (core->config, "io.buffer.from");
|
||||
to = r_config_get_i (core->config, "io.buffer.to");
|
||||
if (from>=to) {
|
||||
eprintf ("ERROR: io.buffer.from >= io.buffer.to"
|
||||
" (0x%"PFMT64x" >= 0x%"PFMT64x")\n", from, to);
|
||||
} else r_io_buffer_load (core->io, from, (int)(to-from));
|
||||
} else r_io_buffer_close (core->io);
|
||||
r_core_block_read (core, 0);
|
||||
return R_TRUE;
|
||||
}
|
||||
|
||||
static int config_iozeromap_callback(void *user, void *data) {
|
||||
RCore *core = (RCore *) user;
|
||||
RConfigNode *node = (RConfigNode *) data;
|
||||
@ -729,7 +745,12 @@ R_API int r_core_config_init(RCore *core) {
|
||||
r_config_set_i_cb (cfg, "search.align", 0, &config_searchalign_callback);
|
||||
r_config_desc (cfg, "search.align", "Only catch aligned search hits");
|
||||
|
||||
sprintf (buf, "%d", R_CORE_BLOCKSIZE_MAX);
|
||||
r_config_set_cb (cfg, "io.buffer", "false", &config_iobuffer_callback);
|
||||
r_config_desc (cfg, "io.buffer", "load and use buffer cache if enabled");
|
||||
r_config_set_i (cfg, "io.buffer.from", 0);
|
||||
r_config_desc (cfg, "io.buffer.from", "lower address of buffered cache");
|
||||
r_config_set_i (cfg, "io.buffer.to", 0);
|
||||
r_config_desc (cfg, "io.buffer.to", "higher address of buffered cache");
|
||||
r_config_set_cb (cfg, "io.zeromap", buf, &config_iozeromap_callback);
|
||||
r_config_desc (cfg, "io.zeromap", "double map the last opened file to address zero");
|
||||
r_config_set_cb (cfg, "io.maxblk", buf, &config_iomaxblk_callback);
|
||||
|
@ -15,7 +15,7 @@ R_API int r_core_dump(RCore *core, const char *file, ut64 addr, ut64 size) {
|
||||
}
|
||||
buf = malloc (bs);
|
||||
r_cons_break (NULL, NULL);
|
||||
for (i=0; i<size; ) {
|
||||
for (i=0; i<size; i+=bs) {
|
||||
if (r_cons_singleton ()->breaked)
|
||||
break;
|
||||
if ((i+bs)>size)
|
||||
@ -25,7 +25,6 @@ R_API int r_core_dump(RCore *core, const char *file, ut64 addr, ut64 size) {
|
||||
eprintf ("write error\n");
|
||||
break;
|
||||
}
|
||||
i += bs;
|
||||
}
|
||||
eprintf ("dumped 0x%"PFMT64x" bytes\n", i);
|
||||
r_cons_break_end ();
|
||||
|
@ -128,6 +128,8 @@ typedef struct r_io_t {
|
||||
//XXX: Need by rap
|
||||
void *user;
|
||||
int (*core_cmd_cb)(void *user, const char *str);
|
||||
RCache *buffer;
|
||||
int buffer_enabled;
|
||||
} RIO;
|
||||
|
||||
//struct r_io_plugin_fd_t {
|
||||
@ -227,6 +229,7 @@ R_API RIODesc *r_io_open_as(RIO *io, const char *urihandler, const char *file, i
|
||||
R_API int r_io_redirect(RIO *io, const char *file);
|
||||
R_API int r_io_set_fd(RIO *io, RIODesc *fd);
|
||||
R_API int r_io_set_fdn(RIO *io, int fd);
|
||||
R_API const ut8* r_io_get_raw (RIO *io, ut64 addr, int *len);
|
||||
R_API RBuffer *r_io_read_buf(RIO *io, ut64 addr, int len);
|
||||
R_API int r_io_read(RIO *io, ut8 *buf, int len);
|
||||
R_API int r_io_read_at(RIO *io, ut64 addr, ut8 *buf, int len);
|
||||
@ -321,6 +324,12 @@ R_API int r_io_desc_del(RIO *io, int fd);
|
||||
R_API RIODesc *r_io_desc_get(RIO *io, int fd);
|
||||
//R_API int r_io_desc_generate(RIO *io);
|
||||
|
||||
/* buffer.c */
|
||||
R_API void r_io_buffer_close(RIO* io);
|
||||
R_API int r_io_buffer_load(RIO* io, ut64 addr, int len);
|
||||
R_API const ut8* r_io_buffer_get (RIO *io, ut64 addr, int *len);
|
||||
R_API int r_io_buffer_read (RIO *io, ut64 addr, ut8* buf, int len);
|
||||
|
||||
/* plugins */
|
||||
extern RIOPlugin r_io_plugin_procpid;
|
||||
extern RIOPlugin r_io_plugin_malloc;
|
||||
|
@ -83,17 +83,11 @@ typedef struct r_buf_t {
|
||||
} RBuffer;
|
||||
|
||||
/* r_cache */
|
||||
// TOTHINK: move into a separated library?
|
||||
typedef struct r_cache_item_t {
|
||||
ut64 addr;
|
||||
char *str;
|
||||
struct list_head list;
|
||||
} RCacheItem;
|
||||
|
||||
typedef struct r_cache_t {
|
||||
ut64 start;
|
||||
ut64 end;
|
||||
struct list_head items;
|
||||
ut64 base;
|
||||
ut8 *buf;
|
||||
ut64 len;
|
||||
} RCache;
|
||||
|
||||
typedef struct r_prof_t {
|
||||
@ -160,7 +154,6 @@ enum {
|
||||
R_SYS_BITS_64 = 8,
|
||||
};
|
||||
|
||||
|
||||
/** hashtable **/
|
||||
typedef struct r_hashtable_entry_t {
|
||||
ut32 hash;
|
||||
@ -308,10 +301,9 @@ R_API void r_poolfactory_free(RPoolFactory *pf);
|
||||
R_API int r_mem_count(const ut8 **addr);
|
||||
R_API RCache* r_cache_new();
|
||||
R_API void r_cache_free(RCache *c);
|
||||
R_API char *r_cache_get(RCache *c, ut64 addr);
|
||||
R_API int r_cache_set(RCache *c, ut64 addr, char *str);
|
||||
R_API int r_cache_validate(RCache *c, ut64 from, ut64 to);
|
||||
R_API int r_cache_invalidate(RCache *c, ut64 from, ut64 to);
|
||||
R_API const ut8* r_cache_get(RCache *c, ut64 addr, int *len);
|
||||
R_API int r_cache_set(RCache *c, ut64 addr, const ut8 *buf, int len);
|
||||
R_API void r_cache_flush (RCache *c);
|
||||
|
||||
R_API void r_prof_start(RProfile *p);
|
||||
R_API double r_prof_end(RProfile *p);
|
||||
|
@ -3,7 +3,8 @@ include ../config.mk
|
||||
NAME=r_io
|
||||
DEPS=r_lib r_util r_socket r_cons
|
||||
STATIC_OBJS=$(subst ..,p/..,$(subst io_,p/io_,$(STATIC_OBJ)))
|
||||
OBJS=${STATIC_OBJS} io.o plugin.o map.o section.o desc.o cache.o undo.o
|
||||
OBJS=${STATIC_OBJS}
|
||||
OBJS+=io.o plugin.o map.o section.o desc.o cache.o undo.o buffer.o
|
||||
|
||||
CFLAGS+=-Wall -DCORELIB
|
||||
|
||||
|
56
libr/io/buffer.c
Normal file
56
libr/io/buffer.c
Normal file
@ -0,0 +1,56 @@
|
||||
/* radare - LGPL - Copyright 2013 - pancake */
|
||||
|
||||
#include "r_io.h"
|
||||
|
||||
R_API void r_io_buffer_close(RIO* io) {
|
||||
r_cache_flush (io->buffer);
|
||||
io->buffer_enabled = 0;
|
||||
}
|
||||
|
||||
R_API int r_io_buffer_load(RIO* io, ut64 addr, int len) {
|
||||
ut64 at;
|
||||
int i, r;
|
||||
ut8 buf[512];
|
||||
if (len<1) return R_FALSE;
|
||||
io->buffer_enabled = 0;
|
||||
for (i=0; i<len; i+=sizeof (buf)) {
|
||||
at = addr+i; //r_io_section_vaddr_to_offset (io, addr+i);
|
||||
//r_io_seek (io, addr+i, R_IO_SEEK_SET);
|
||||
r_io_seek (io, at, R_IO_SEEK_SET);
|
||||
memset (buf, 0xff, sizeof (buf));
|
||||
r = r_io_read (io, buf, sizeof (buf));
|
||||
//eprintf ("r=%d %llx\n", r, addr+i);
|
||||
//if (buf[0] !=0xff) eprintf ("STORE %02x %02x %02x\n", buf[0], buf[1], buf[2]);
|
||||
if (r<1) break;
|
||||
r_cache_set (io->buffer, at, buf, sizeof (buf));
|
||||
}
|
||||
io->buffer_enabled = 1;
|
||||
return R_TRUE;
|
||||
}
|
||||
|
||||
R_API const ut8* r_io_buffer_get (RIO *io, ut64 addr, int *len) {
|
||||
return r_cache_get (io->buffer, addr, len);
|
||||
}
|
||||
|
||||
R_API int r_io_buffer_read (RIO *io, ut64 addr, ut8* buf, int len) {
|
||||
const ut8 *ret;
|
||||
int next, l = 0;
|
||||
// align addr if out of buffer if its mapped on io //
|
||||
ret = r_cache_get (io->buffer, addr, &l);
|
||||
if (!ret) {
|
||||
if (l<1) return 0; // no next block in buffer cache
|
||||
if (l>len) return 0; // next block too far
|
||||
next = l;
|
||||
ret = r_cache_get (io->buffer, addr+next+1, &l);
|
||||
if (!ret) return 0;
|
||||
if (l<len) memset (buf+l, 0xff, (len-l));
|
||||
if (l>len) l = len;
|
||||
memset (buf, 0xff, next);
|
||||
memcpy (buf+next, ret, (len-next));
|
||||
return len;
|
||||
}
|
||||
if (l>len) l = len;
|
||||
else if (l<len) memset (buf+l, 0xff, (len-l));
|
||||
memcpy (buf, ret, l);
|
||||
return l;
|
||||
}
|
23
libr/io/io.c
23
libr/io/io.c
@ -1,4 +1,4 @@
|
||||
/* radare - LGPL - Copyright 2008-2012 - pancake */
|
||||
/* radare - LGPL - Copyright 2008-2013 - pancake */
|
||||
|
||||
#include "r_io.h"
|
||||
#include "r_util.h"
|
||||
@ -10,6 +10,8 @@
|
||||
R_API RIO *r_io_new() {
|
||||
RIO *io = R_NEW (RIO);
|
||||
if (!io) return NULL;
|
||||
io->buffer = r_cache_new (); // TODO: use RBuffer here
|
||||
io->buffer_enabled = 0;
|
||||
io->zeromap = R_FALSE; // if true, then 0 is mapped with contents of file
|
||||
io->fd = NULL;
|
||||
io->write_mask_fd = -1;
|
||||
@ -57,6 +59,7 @@ R_API RIO *r_io_free(RIO *io) {
|
||||
/* TODO: memory leaks */
|
||||
r_list_free (io->sections);
|
||||
r_list_free (io->maps);
|
||||
r_cache_free (io->buffer);
|
||||
r_io_desc_fini (io);
|
||||
free (io);
|
||||
return NULL;
|
||||
@ -159,6 +162,8 @@ R_API int r_io_set_fdn(RIO *io, int fd) {
|
||||
}
|
||||
|
||||
static inline int r_io_read_internal(RIO *io, ut8 *buf, int len) {
|
||||
if (io->buffer_enabled)
|
||||
return r_io_buffer_read (io, io->off, buf, len);
|
||||
if (io->plugin && io->plugin->read)
|
||||
return io->plugin->read (io, io->fd, buf, len);
|
||||
return read (io->fd->fd, buf, len);
|
||||
@ -173,15 +178,19 @@ R_API int r_io_read(RIO *io, ut8 *buf, int len) {
|
||||
*/
|
||||
return r_io_read_at (io, io->off, buf, len);
|
||||
}
|
||||
|
||||
// XXX: this is buggy. must use seek+read
|
||||
R_API int r_io_read_at(RIO *io, ut64 addr, ut8 *buf, int len) {
|
||||
int ret, l, olen = len;
|
||||
int w = 0;
|
||||
|
||||
io->off = addr; // HACK
|
||||
//r_io_seek (io, addr, R_IO_SEEK_SET);
|
||||
// XXX: this is buggy!
|
||||
memset (buf, 0xff, len);
|
||||
|
||||
if (io->buffer_enabled) {
|
||||
return r_io_buffer_read (io, addr, buf, len);
|
||||
}
|
||||
while (len>0) {
|
||||
int ms;
|
||||
ut64 last = r_io_section_next (io, addr);
|
||||
@ -311,15 +320,19 @@ R_API int r_io_write(struct r_io_t *io, const ut8 *buf, int len) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
R_API int r_io_write_at(struct r_io_t *io, ut64 addr, const ut8 *buf, int len) {
|
||||
R_API int r_io_write_at(RIO *io, ut64 addr, const ut8 *buf, int len) {
|
||||
if (r_io_seek (io, addr, R_IO_SEEK_SET)<0)
|
||||
return -1;
|
||||
return r_io_write (io, buf, len);
|
||||
}
|
||||
|
||||
R_API ut64 r_io_seek(struct r_io_t *io, ut64 offset, int whence) {
|
||||
R_API ut64 r_io_seek(RIO *io, ut64 offset, int whence) {
|
||||
int posix_whence = SEEK_SET;
|
||||
ut64 ret = UT64_MAX;
|
||||
if (io->buffer_enabled) {
|
||||
io->off = offset;
|
||||
return offset;
|
||||
}
|
||||
switch (whence) {
|
||||
case R_IO_SEEK_SET:
|
||||
posix_whence = SEEK_SET;
|
||||
@ -388,7 +401,7 @@ R_API int r_io_system(RIO *io, const char *cmd) {
|
||||
}
|
||||
|
||||
// TODO: remove int fd here???
|
||||
R_API int r_io_close(struct r_io_t *io, RIODesc *fd) {
|
||||
R_API int r_io_close(RIO *io, RIODesc *fd) {
|
||||
if (io == NULL || fd == NULL)
|
||||
return -1;
|
||||
int nfd = fd->fd;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* radare - LGPL - Copyright 2009-2012 - pancake */
|
||||
/* radare - LGPL - Copyright 2009-2013 - pancake */
|
||||
|
||||
#include "r_types.h"
|
||||
#include "r_util.h"
|
||||
|
@ -1,61 +1,74 @@
|
||||
/* radare - LGPL - Copyright 2009-2011 pancake<nopcode.org> */
|
||||
/* radare - LGPL - Copyright 2013 - pancake */
|
||||
|
||||
// TODO: Use r_list instead of list.h
|
||||
#include <r_util.h>
|
||||
// TODO: optimize reallocs.. store RBuffer info.. wait. extend r_buf_ for that?
|
||||
|
||||
R_API struct r_cache_t *r_cache_new() {
|
||||
RCache *a = R_NEW (RCache);
|
||||
if (a) INIT_LIST_HEAD (&a->items);
|
||||
return a;
|
||||
R_API RCache *r_cache_new() {
|
||||
RCache *c = R_NEW (RCache);
|
||||
c->buf = NULL;
|
||||
c->base = 0;
|
||||
c->len = 0;
|
||||
return c;
|
||||
}
|
||||
|
||||
R_API void r_cache_free(struct r_cache_t *a) {
|
||||
free(a);
|
||||
R_API void r_cache_free(RCache *c) {
|
||||
free (c->buf);
|
||||
free (c);
|
||||
}
|
||||
|
||||
R_API char *r_cache_get(struct r_cache_t *c, ut64 addr) {
|
||||
struct list_head *pos;
|
||||
list_for_each_prev (pos, &c->items) {
|
||||
struct r_cache_item_t *h = list_entry (pos, struct r_cache_item_t, list);
|
||||
if (h->addr == addr)
|
||||
return h->str;
|
||||
R_API const ut8* r_cache_get(RCache *c, ut64 addr, int *len) {
|
||||
if (!c->buf)
|
||||
return NULL;
|
||||
if (len) *len = c->base - addr;
|
||||
if (addr<c->base)
|
||||
return NULL;
|
||||
if (addr>(c->base+c->len))
|
||||
return NULL;
|
||||
if (len) *len = c->len - (addr-c->base);
|
||||
//eprintf ("4 - %d\n", (addr-c->base));
|
||||
return c->buf + (addr-c->base);
|
||||
}
|
||||
|
||||
R_API int r_cache_set(RCache *c, ut64 addr, const ut8 *buf, int len) {
|
||||
if (c->buf == NULL) {
|
||||
c->buf = malloc (len);
|
||||
if (!c->buf) return 0;
|
||||
memcpy (c->buf, buf, len);
|
||||
c->base = addr;
|
||||
c->len = len;
|
||||
} else
|
||||
if (addr < c->base) {
|
||||
ut8 *b;
|
||||
int baselen = (c->base - addr);
|
||||
int newlen = baselen + (len > (c->len+newlen))? len: c->base;
|
||||
// XXX expensive heap usage. must simplify
|
||||
b = malloc (newlen);
|
||||
if (!b) return 0;
|
||||
memset (b, 0xff, newlen);
|
||||
memcpy (b+baselen, c->buf, c->len);
|
||||
memcpy (b, buf, len);
|
||||
free (c->buf);
|
||||
c->buf = b;
|
||||
c->base = addr;
|
||||
c->len = newlen;
|
||||
} else if ((addr+len)>(c->base+c->len)) {
|
||||
ut8 *b;
|
||||
int baselen = (addr - c->base);
|
||||
int newlen = baselen + len;
|
||||
b = realloc (c->buf, newlen);
|
||||
if (!b) return 0;
|
||||
memcpy (b+baselen, buf, len);
|
||||
c->buf = b;
|
||||
c->len = newlen;
|
||||
} else {
|
||||
memcpy (c->buf, buf, len);
|
||||
}
|
||||
return NULL;
|
||||
return c->len;
|
||||
}
|
||||
|
||||
R_API int r_cache_set(struct r_cache_t *c, ut64 addr, char *str) {
|
||||
struct r_cache_item_t *a = R_NEW (struct r_cache_item_t);
|
||||
a->addr = addr;
|
||||
a->str = strdup (str);
|
||||
list_add_tail (&(a->list), &(c->items));
|
||||
return R_TRUE;
|
||||
}
|
||||
|
||||
R_API int r_cache_validate(struct r_cache_t *c, ut64 start, ut64 end) {
|
||||
int ret = R_FALSE;
|
||||
struct list_head *pos, *n;
|
||||
|
||||
list_for_each_safe (pos, n, &c->items) {
|
||||
struct r_cache_item_t *h = (struct r_cache_item_t *)list_entry (pos, struct r_cache_item_t, list);
|
||||
if (h->addr <start || h->addr > end) {
|
||||
free (h->str);
|
||||
list_del (&h->list);
|
||||
ret = R_TRUE;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
R_API int r_cache_invalidate(struct r_cache_t *c, ut64 start, ut64 end) {
|
||||
int ret = R_FALSE;
|
||||
struct list_head *pos, *n;
|
||||
list_for_each_safe (pos, n, &c->items) {
|
||||
struct r_cache_item_t *h = list_entry (pos, struct r_cache_item_t, list);
|
||||
if (h->addr >=start && h->addr <= end) {
|
||||
free (h->str);
|
||||
list_del (&h->list);
|
||||
ret = R_TRUE;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
R_API void r_cache_flush (RCache *c) {
|
||||
c->base = 0;
|
||||
c->len = 0;
|
||||
free (c->buf);
|
||||
c->buf = NULL;
|
||||
}
|
||||
|
@ -43,10 +43,24 @@
|
||||
* 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
|
||||
*/
|
||||
#if HT64
|
||||
#define utH ut64
|
||||
#define ht_(name) r_hashtable64_##name
|
||||
#define RHT RHashTable64
|
||||
#define RHTE RHashTable64Entry
|
||||
#else
|
||||
#define utH ut32
|
||||
#define ht_(name) r_hashtable_##name
|
||||
#define RHT RHashTable
|
||||
#define RHTE RHashTableEntry
|
||||
#endif
|
||||
|
||||
static const ut32 deleted_data;
|
||||
//static const utH deleted_data;
|
||||
// HACK :D .. but.. use magic instead?
|
||||
#define deleted_data hash_sizes
|
||||
|
||||
static const struct {
|
||||
// XXX: this can be ut32 ...
|
||||
ut32 max_entries, size, rehash;
|
||||
} hash_sizes[] = {
|
||||
{ 2, 5, 3 },
|
||||
@ -92,13 +106,13 @@ static const struct {
|
||||
* 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;
|
||||
static RHTE* ht_(search)(RHT *ht, utH hash) {
|
||||
utH double_hash, hash_address;
|
||||
if (ht == NULL)
|
||||
return NULL;
|
||||
hash_address = hash % ht->size;
|
||||
do {
|
||||
RHashTableEntry *entry = ht->table + hash_address;
|
||||
RHTE *entry = ht->table + hash_address;
|
||||
if (entry_is_free (entry))
|
||||
return NULL;
|
||||
if (entry_is_present (entry) && entry->hash == hash)
|
||||
@ -111,9 +125,9 @@ static RHashTableEntry* r_hashtable_search(RHashTable *ht, ut32 hash) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void r_hashtable_rehash(RHashTable *ht, int new_size_index) {
|
||||
RHashTable old_ht = *ht;
|
||||
RHashTableEntry *e;
|
||||
static void ht_(rehash)(RHT *ht, int new_size_index) {
|
||||
RHT old_ht = *ht;
|
||||
RHTE *e;
|
||||
if (new_size_index >= ARRAY_SIZE (hash_sizes))
|
||||
return;
|
||||
// XXX: This code is redupped! fuck't
|
||||
@ -128,13 +142,13 @@ static void r_hashtable_rehash(RHashTable *ht, int new_size_index) {
|
||||
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);
|
||||
ht_(insert) (ht, e->hash, e->data);
|
||||
}
|
||||
free (old_ht.table);
|
||||
}
|
||||
|
||||
R_API RHashTable* r_hashtable_new(void) {
|
||||
RHashTable *ht = R_NEW (RHashTable);
|
||||
R_API RHT* ht_(new)(void) {
|
||||
RHT *ht = R_NEW (RHT);
|
||||
if (!ht) return NULL;
|
||||
// TODO: use slices here
|
||||
ht->size = hash_sizes[0].size;
|
||||
@ -151,12 +165,12 @@ R_API RHashTable* r_hashtable_new(void) {
|
||||
return ht;
|
||||
}
|
||||
|
||||
R_API void r_hashtable_free(RHashTable *ht) {
|
||||
R_API void ht_(free)(RHT *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);
|
||||
R_API void *ht_(lookup)(RHT *ht, utH hash) {
|
||||
RHTE *entry = ht_(search) (ht, hash);
|
||||
return entry? entry->data : NULL;
|
||||
}
|
||||
|
||||
@ -166,18 +180,18 @@ R_API void *r_hashtable_lookup(RHashTable *ht, ut32 hash) {
|
||||
* 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;
|
||||
R_API boolt ht_(insert) (RHT *ht, utH hash, void *data) {
|
||||
utH hash_address;
|
||||
|
||||
if (ht->entries >= ht->max_entries)
|
||||
r_hashtable_rehash (ht, ht->size_index + 1);
|
||||
ht_(rehash) (ht, ht->size_index + 1);
|
||||
else if (ht->deleted_entries + ht->entries >= ht->max_entries)
|
||||
r_hashtable_rehash (ht, ht->size_index);
|
||||
ht_(rehash) (ht, ht->size_index);
|
||||
|
||||
hash_address = hash % ht->size;
|
||||
do {
|
||||
RHashTableEntry *entry = ht->table + hash_address;
|
||||
ut32 double_hash;
|
||||
RHTE *entry = ht->table + hash_address;
|
||||
utH double_hash;
|
||||
|
||||
if (!entry_is_present (entry)) {
|
||||
if (entry_is_deleted (entry))
|
||||
@ -187,7 +201,6 @@ R_API boolt r_hashtable_insert(RHashTable *ht, ut32 hash, void *data) {
|
||||
ht->entries++;
|
||||
return R_TRUE;
|
||||
}
|
||||
|
||||
double_hash = hash % ht->rehash;
|
||||
if (double_hash == 0)
|
||||
double_hash = 1;
|
||||
@ -200,8 +213,8 @@ R_API boolt r_hashtable_insert(RHashTable *ht, ut32 hash, void *data) {
|
||||
return R_FALSE;
|
||||
}
|
||||
|
||||
R_API void r_hashtable_remove(RHashTable *ht, ut32 hash) {
|
||||
RHashTableEntry *entry = r_hashtable_search (ht, hash);
|
||||
R_API void ht_(remove) (RHT *ht, utH hash) {
|
||||
RHTE *entry = ht_(search) (ht, hash);
|
||||
if (entry) {
|
||||
entry->data = (void *) &deleted_data;
|
||||
ht->entries--;
|
||||
@ -213,25 +226,24 @@ R_API void r_hashtable_remove(RHashTable *ht, ut32 hash) {
|
||||
int main () {
|
||||
const char *str;
|
||||
int ret;
|
||||
RHashTable *ht = r_hashtable_new ();
|
||||
RHT *ht = ht_(new) ();
|
||||
#define HASH 268453705
|
||||
|
||||
ret = r_hashtable_insert (ht, HASH, "patata");
|
||||
ret = ht_(insert) (ht, HASH, "patata");
|
||||
if (!ret)
|
||||
printf ("Cannot reinsert !!1\n");
|
||||
|
||||
str = r_hashtable_lookup (ht, HASH);
|
||||
str = ht_(lookup) (ht, HASH);
|
||||
if (str) printf ("String is (%s)\n", str);
|
||||
else printf ("Cannot find string\n");
|
||||
|
||||
r_hashtable_remove (ht, HASH);
|
||||
ht_(remove) (ht, HASH);
|
||||
|
||||
str = r_hashtable_lookup (ht, HASH);
|
||||
str = ht_(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);
|
||||
ht_(search) (ht, HASH);
|
||||
ht_(free) (ht);
|
||||
}
|
||||
#endif
|
||||
|
235
libr/util/ht64.c
235
libr/util/ht64.c
@ -1,234 +1,7 @@
|
||||
/*
|
||||
* 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>
|
||||
*/
|
||||
#ifndef _INCLUDE_HT64_H_
|
||||
#define _INCLUDE_HT64_H_
|
||||
|
||||
#include <r_util.h>
|
||||
#define HT64 1
|
||||
#include "ht.c"
|
||||
|
||||
#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 = calloc (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 = R_NEW (RHashTable64);
|
||||
if (!ht) return NULL;
|
||||
// TODO: use slices here
|
||||
ht->size = hash_sizes[0].size;
|
||||
ht->table = calloc (ht->size, sizeof (*ht->table));
|
||||
if (!ht->table) {
|
||||
free (ht);
|
||||
return NULL;
|
||||
}
|
||||
ht->size_index = 0;
|
||||
ht->entries = 0;
|
||||
ht->deleted_entries = 0;
|
||||
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 ();
|
||||
#define HASH 268453705
|
||||
|
||||
ret = r_hashtable64_insert (ht, HASH, "patata");
|
||||
if (!ret)
|
||||
printf ("Cannot reinsert !!1\n");
|
||||
|
||||
str = r_hashtable64_lookup (ht, HASH);
|
||||
if (str) printf ("String is (%s)\n", str);
|
||||
else printf ("Cannot find string\n");
|
||||
|
||||
r_hashtable64_remove (ht, HASH);
|
||||
|
||||
str = r_hashtable64_lookup (ht, HASH);
|
||||
if (str) printf ("String is (%s)\n", str);
|
||||
else printf("Cannot find string which is ok :)\n");
|
||||
|
||||
r_hashtable64_search (ht, HASH);
|
||||
|
||||
r_hashtable64_free (ht);
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user