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:
pancake 2013-01-12 04:29:45 +01:00
parent ebe2f35630
commit 60a951e9b1
11 changed files with 225 additions and 336 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
/* radare - LGPL - Copyright 2009-2012 - pancake */
/* radare - LGPL - Copyright 2009-2013 - pancake */
#include "r_types.h"
#include "r_util.h"

View File

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

View File

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

View File

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