implement id-storage-API

This commit is contained in:
condret 2017-02-06 15:27:43 +00:00
parent c76baa3036
commit 3dee0cb665
4 changed files with 220 additions and 1 deletions

View File

@ -44,6 +44,7 @@
#include "r_util/r_tree.h"
#include "r_util/r_uleb128.h"
#include "r_util/r_utf8.h"
#include "r_util/r_id_storage.h"
#if __UNIX__
#include <signal.h>
#endif

View File

@ -0,0 +1,37 @@
/* radare2 - LGPL - Copyright 2017 - condret */
#ifndef R_ID_STORAGE_H
#define R_ID_STORAGE_H
#include <r_util.h>
#include <r_types.h>
typedef struct r_id_pool_t {
ut32 start_id;
ut32 last_id;
ut32 next_id;
RQueue *freed_ids;
} RIDPool;
R_API RIDPool *r_id_pool_new (ut32 start_id, ut32 last_id);
R_API bool r_id_pool_grab_id (RIDPool *pool, ut32 *grabber);
R_API bool r_id_pool_kick_id (RIDPool *pool, ut32 kick);
R_API void r_id_pool_free (RIDPool *pool);
typedef struct r_id_storage_t {
RIDPool *pool;
void **data;
ut32 top_id;
ut32 size;
} RIDStorage;
typedef bool (*RIDStorageForeachCb)(void *user, void *data, ut32 id);
R_API RIDStorage *r_id_storage_new (ut32 start_id, ut32 last_id);
R_API bool r_id_storage_set (RIDStorage *storage, void *data, ut32 id);
R_API bool r_id_storage_add (RIDStorage *storage, void *data, ut32 *id);
R_API void *r_id_storage_get (RIDStorage *storage, ut32 id);
R_API void r_id_storage_delete (RIDStorage *storage, ut32 id);
R_API void *r_id_storage_take (RIDStorage *storage, ut32 id);
R_API bool r_id_storage_foreach (RIDStorage *storage, RIDStorageForeachCb cb, void *user);
R_API void r_id_storage_free (RIDStorage *storage);
#endif

View File

@ -11,7 +11,7 @@ OBJS+=sandbox.o calc.o thread.o thread_lock.o thread_msg.o
OBJS+=strpool.o bitmap.o strht.o p_date.o p_format.o print.o
OBJS+=p_seven.o slist.o randomart.o log.o zip.o debruijn.o
OBJS+=utf8.o strbuf.o lib.o name.o spaces.o signal.o syscmd.o
OBJS+=diff.o bdiff.o stack.o queue.o tree.o des.o
OBJS+=diff.o bdiff.o stack.o queue.o tree.o des.o id_storage.o
OBJS+=punycode.o
# DO NOT BUILD r_big api (not yet used and its buggy)

181
libr/util/id_storage.c Normal file
View File

@ -0,0 +1,181 @@
/* radare2 - LGPL - Copyright 2017 - condret */
#include <r_util.h>
#include <r_types.h>
ut32 get_msb (ut32 v) {
int i;
for (i = 31; i > (-1); i--) {
if (v & (0x1 << i))
return (v & (0x1 << i));
}
return 0;
}
R_API RIDPool *r_id_pool_new (ut32 start_id, ut32 last_id) {
RIDPool *pool = NULL;
if (start_id < last_id) {
pool = R_NEW0 (RIDPool);
pool->next_id = pool->start_id = start_id;
pool->last_id = last_id;
}
return pool;
}
R_API bool r_id_pool_grab_id (RIDPool *pool, ut32 *grabber) {
if (!pool || !grabber)
return false;
if (pool->freed_ids) {
*grabber = (ut32)r_queue_dequeue (pool->freed_ids);
if (r_queue_is_empty (pool->freed_ids)) {
r_queue_free (pool->freed_ids);
pool->freed_ids = NULL;
}
return true;
}
if (pool->next_id < pool->last_id) {
*grabber = pool->next_id;
pool->next_id++;
return true;
}
return false;
}
R_API bool r_id_pool_kick_id (RIDPool *pool, ut32 kick) {
if (!pool || (kick < pool->start_id) || (pool->start_id == pool->next_id))
return false;
if (kick == (pool->next_id - 1)) {
pool->next_id--;
return true;
}
if (!pool->freed_ids)
pool->freed_ids = r_queue_new (2);
r_queue_enqueue (pool->freed_ids, (void *)kick);
return true;
}
R_API void r_id_pool_free (RIDPool *pool) {
if (pool && pool->freed_ids) {
r_queue_free (pool->freed_ids);
}
free (pool);
}
R_API RIDStorage *r_id_storage_new (ut32 start_id, ut32 last_id) {
RIDPool *pool;
RIDStorage *storage = NULL;
if ((start_id < 16) && (pool = r_id_pool_new (start_id, last_id))) {
storage = R_NEW0 (RIDStorage);
storage->pool = pool;
}
return storage;
}
static bool id_storage_reallocate (RIDStorage *storage, ut32 size) {
void *data;
if (!storage)
return false;
if (storage->size == size)
return true;
if (storage->size > size) {
storage->data = realloc (storage->data, size * sizeof(void *));
storage->size = size;
return true;
}
data = storage->data;
storage->data = R_NEWS0 (void *, size);
if (data) {
memcpy (storage->data, data, storage->size);
}
storage->size = size;
return true;
}
R_API bool r_id_storage_set (RIDStorage *storage, void *data, ut32 id) {
ut32 n;
if (!storage || !storage->pool || (id >= storage->pool->next_id))
return false;
n = get_msb (id + 1);
if (n > ((storage->size / 2) + (storage->size / 4))) {
if (n < (storage->pool->last_id / 2)) {
if (!id_storage_reallocate (storage, n*2))
return false;
} else if (n != (storage->pool->last_id)) {
if (!id_storage_reallocate (storage, storage->pool->last_id))
return false;
}
}
storage->data[id] = data;
if (id > storage->top_id)
storage->top_id = id;
return true;
}
R_API bool r_id_storage_add (RIDStorage *storage, void *data, ut32 *id) {
if (!storage)
return false;
if (!r_id_pool_grab_id (storage->pool, id))
return false;
return r_id_storage_set (storage, data, *id);
}
R_API void *r_id_storage_get (RIDStorage *storage, ut32 id) {
if (!storage || !storage->data || (storage->size >= id))
return NULL;
return storage->data[id];
}
R_API void r_id_storage_delete (RIDStorage *storage, ut32 id) {
if (!storage || !storage->data || (storage->size >= id))
return;
storage->data[id] = NULL;
if (id == storage->top_id) {
while (!storage->data[storage->top_id] && storage->top_id)
storage->top_id--;
if (!storage->top_id) {
if(storage->data[storage->top_id]) {
id_storage_reallocate (storage, 2);
} else {
RIDPool *pool;
free (storage->data);
storage->data = NULL;
storage->size = 0;
pool = r_id_pool_new (storage->pool->start_id, storage->pool->last_id);
r_id_pool_free (storage->pool);
storage->pool = pool;
return;
}
} else if ((storage->top_id +1 ) < (storage->size / 2)) {
id_storage_reallocate (storage, storage->size / 2);
}
}
r_id_pool_kick_id (storage->pool, id);
}
R_API void *r_id_storage_take (RIDStorage *storage, ut32 id) {
void *ret = r_id_storage_get (storage, id);
r_id_storage_delete (storage, id);
return ret;
}
R_API bool r_id_storage_foreach (RIDStorage *storage, RIDStorageForeachCb cb, void *user) {
ut32 i;
if (!cb || !storage || !storage->data)
return false;
for (i = 0; i < storage->top_id; i++) {
if (storage->data[i])
if (!cb (user, storage->data[i], i))
return false;
}
if (storage->data[i])
return cb (user, storage->data[i], i);
return true;
}
R_API void r_id_storage_free (RIDStorage *storage) {
if (storage) {
r_id_pool_free (storage->pool);
free (storage->data);
}
free (storage);
}