2017-02-06 15:27:43 +00:00
|
|
|
/* radare2 - LGPL - Copyright 2017 - condret */
|
|
|
|
|
|
|
|
#include <r_util.h>
|
|
|
|
#include <r_types.h>
|
|
|
|
|
2017-02-08 23:01:42 +01:00
|
|
|
ut32 get_msb(ut32 v) {
|
2017-02-06 15:27:43 +00:00
|
|
|
int i;
|
|
|
|
for (i = 31; i > (-1); i--) {
|
2017-02-08 23:01:42 +01:00
|
|
|
if (v & (0x1 << i)) {
|
2017-02-06 15:27:43 +00:00
|
|
|
return (v & (0x1 << i));
|
2017-02-08 23:01:42 +01:00
|
|
|
}
|
2017-02-06 15:27:43 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-02-08 23:01:42 +01:00
|
|
|
R_API RIDPool *r_id_pool_new(ut32 start_id, ut32 last_id) {
|
2017-02-06 15:27:43 +00:00
|
|
|
RIDPool *pool = NULL;
|
|
|
|
if (start_id < last_id) {
|
|
|
|
pool = R_NEW0 (RIDPool);
|
2017-02-08 23:01:42 +01:00
|
|
|
if (!pool) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2017-02-06 15:27:43 +00:00
|
|
|
pool->next_id = pool->start_id = start_id;
|
|
|
|
pool->last_id = last_id;
|
|
|
|
}
|
|
|
|
return pool;
|
|
|
|
}
|
|
|
|
|
2017-02-08 23:01:42 +01:00
|
|
|
R_API bool r_id_pool_grab_id(RIDPool *pool, ut32 *grabber) {
|
|
|
|
if (!pool || !grabber) {
|
2017-02-06 15:27:43 +00:00
|
|
|
return false;
|
2017-02-08 23:01:42 +01:00
|
|
|
}
|
2017-02-06 15:27:43 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-02-08 23:01:42 +01:00
|
|
|
R_API bool r_id_pool_kick_id(RIDPool *pool, ut32 kick) {
|
|
|
|
if (!pool || (kick < pool->start_id) || (pool->start_id == pool->next_id)) {
|
2017-02-06 15:27:43 +00:00
|
|
|
return false;
|
2017-02-08 23:01:42 +01:00
|
|
|
}
|
2017-02-06 15:27:43 +00:00
|
|
|
if (kick == (pool->next_id - 1)) {
|
|
|
|
pool->next_id--;
|
|
|
|
return true;
|
|
|
|
}
|
2017-02-08 23:01:42 +01:00
|
|
|
if (!pool->freed_ids) {
|
2017-02-06 15:27:43 +00:00
|
|
|
pool->freed_ids = r_queue_new (2);
|
2017-02-08 23:01:42 +01:00
|
|
|
}
|
2017-02-10 02:05:58 +01:00
|
|
|
r_queue_enqueue (pool->freed_ids, (void *)(size_t)kick);
|
2017-02-06 15:27:43 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-02-08 23:01:42 +01:00
|
|
|
R_API void r_id_pool_free(RIDPool *pool) {
|
2017-02-06 15:27:43 +00:00
|
|
|
if (pool && pool->freed_ids) {
|
|
|
|
r_queue_free (pool->freed_ids);
|
|
|
|
}
|
|
|
|
free (pool);
|
|
|
|
}
|
|
|
|
|
2017-02-08 23:01:42 +01:00
|
|
|
R_API RIDStorage *r_id_storage_new(ut32 start_id, ut32 last_id) {
|
2017-02-06 15:27:43 +00:00
|
|
|
RIDPool *pool;
|
|
|
|
RIDStorage *storage = NULL;
|
|
|
|
if ((start_id < 16) && (pool = r_id_pool_new (start_id, last_id))) {
|
|
|
|
storage = R_NEW0 (RIDStorage);
|
2017-02-08 23:01:42 +01:00
|
|
|
if (!storage) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2017-02-06 15:27:43 +00:00
|
|
|
storage->pool = pool;
|
|
|
|
}
|
|
|
|
return storage;
|
|
|
|
}
|
|
|
|
|
2017-02-08 23:01:42 +01:00
|
|
|
static bool id_storage_reallocate(RIDStorage *storage, ut32 size) {
|
2017-02-06 15:27:43 +00:00
|
|
|
void *data;
|
2017-02-08 23:01:42 +01:00
|
|
|
if (!storage) {
|
2017-02-06 15:27:43 +00:00
|
|
|
return false;
|
2017-02-08 23:01:42 +01:00
|
|
|
}
|
|
|
|
if (storage->size == size) {
|
2017-02-06 15:27:43 +00:00
|
|
|
return true;
|
2017-02-08 23:01:42 +01:00
|
|
|
}
|
2017-02-06 15:27:43 +00:00
|
|
|
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) {
|
2017-02-12 19:28:53 +00:00
|
|
|
memcpy (storage->data, data, storage->size*sizeof(void *));
|
2017-02-06 15:27:43 +00:00
|
|
|
}
|
|
|
|
storage->size = size;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-02-08 23:01:42 +01:00
|
|
|
R_API bool r_id_storage_set(RIDStorage *storage, void *data, ut32 id) {
|
2017-02-06 15:27:43 +00:00
|
|
|
ut32 n;
|
2017-02-08 23:01:42 +01:00
|
|
|
if (!storage || !storage->pool || (id >= storage->pool->next_id)) {
|
2017-02-06 15:27:43 +00:00
|
|
|
return false;
|
2017-02-08 23:01:42 +01:00
|
|
|
}
|
2017-02-06 15:27:43 +00:00
|
|
|
n = get_msb (id + 1);
|
2017-02-12 17:38:39 +00:00
|
|
|
if (n > (storage->size - (storage->size / 4))) {
|
2017-02-06 15:27:43 +00:00
|
|
|
if (n < (storage->pool->last_id / 2)) {
|
2017-02-08 23:01:42 +01:00
|
|
|
if (!id_storage_reallocate (storage, n * 2)) {
|
2017-02-06 15:27:43 +00:00
|
|
|
return false;
|
2017-02-08 23:01:42 +01:00
|
|
|
}
|
2017-02-06 15:27:43 +00:00
|
|
|
} else if (n != (storage->pool->last_id)) {
|
2017-02-08 23:01:42 +01:00
|
|
|
if (!id_storage_reallocate (storage, storage->pool->last_id)) {
|
2017-02-06 15:27:43 +00:00
|
|
|
return false;
|
2017-02-08 23:01:42 +01:00
|
|
|
}
|
2017-02-06 15:27:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
storage->data[id] = data;
|
2017-02-08 23:01:42 +01:00
|
|
|
if (id > storage->top_id) {
|
2017-02-06 15:27:43 +00:00
|
|
|
storage->top_id = id;
|
2017-02-08 23:01:42 +01:00
|
|
|
}
|
2017-02-06 15:27:43 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-02-08 23:01:42 +01:00
|
|
|
R_API bool r_id_storage_add(RIDStorage *storage, void *data, ut32 *id) {
|
2017-02-09 00:31:40 +01:00
|
|
|
if (!storage || !r_id_pool_grab_id (storage->pool, id)) {
|
2017-02-06 15:27:43 +00:00
|
|
|
return false;
|
2017-02-08 23:01:42 +01:00
|
|
|
}
|
2017-02-06 15:27:43 +00:00
|
|
|
return r_id_storage_set (storage, data, *id);
|
|
|
|
}
|
|
|
|
|
2017-02-08 23:01:42 +01:00
|
|
|
R_API void *r_id_storage_get(RIDStorage *storage, ut32 id) {
|
2017-02-12 17:38:39 +00:00
|
|
|
if (!storage || !storage->data || (storage->size <= id)) {
|
2017-02-06 15:27:43 +00:00
|
|
|
return NULL;
|
2017-02-08 23:01:42 +01:00
|
|
|
}
|
2017-02-06 15:27:43 +00:00
|
|
|
return storage->data[id];
|
|
|
|
}
|
|
|
|
|
2017-02-08 23:01:42 +01:00
|
|
|
R_API void r_id_storage_delete(RIDStorage *storage, ut32 id) {
|
2017-02-12 17:38:39 +00:00
|
|
|
if (!storage || !storage->data || (storage->size <= id)) {
|
2017-02-06 15:27:43 +00:00
|
|
|
return;
|
2017-02-08 23:01:42 +01:00
|
|
|
}
|
2017-02-06 15:27:43 +00:00
|
|
|
storage->data[id] = NULL;
|
|
|
|
if (id == storage->top_id) {
|
2017-02-08 23:01:42 +01:00
|
|
|
while (storage->top_id && !storage->data[storage->top_id]) {
|
2017-02-06 15:27:43 +00:00
|
|
|
storage->top_id--;
|
2017-02-08 23:01:42 +01:00
|
|
|
}
|
2017-02-06 15:27:43 +00:00
|
|
|
if (!storage->top_id) {
|
|
|
|
if(storage->data[storage->top_id]) {
|
|
|
|
id_storage_reallocate (storage, 2);
|
2017-02-12 16:13:41 +01:00
|
|
|
} else {
|
|
|
|
RIDPool *pool = r_id_pool_new (storage->pool->start_id,
|
|
|
|
storage->pool->last_id);
|
|
|
|
R_FREE (storage->data);
|
|
|
|
storage->size = 0;
|
|
|
|
r_id_pool_free (storage->pool);
|
|
|
|
storage->pool = pool;
|
|
|
|
return;
|
|
|
|
}
|
2017-02-12 17:38:39 +00:00
|
|
|
} else if ((storage->top_id + 1 ) < (storage->size / 4)) {
|
2017-02-06 15:27:43 +00:00
|
|
|
id_storage_reallocate (storage, storage->size / 2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
r_id_pool_kick_id (storage->pool, id);
|
|
|
|
}
|
|
|
|
|
2017-02-08 23:01:42 +01:00
|
|
|
R_API void *r_id_storage_take(RIDStorage *storage, ut32 id) {
|
2017-02-06 15:27:43 +00:00
|
|
|
void *ret = r_id_storage_get (storage, id);
|
|
|
|
r_id_storage_delete (storage, id);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-02-08 23:01:42 +01:00
|
|
|
R_API bool r_id_storage_foreach(RIDStorage *storage, RIDStorageForeachCb cb, void *user) {
|
2017-02-06 15:27:43 +00:00
|
|
|
ut32 i;
|
2017-02-08 23:01:42 +01:00
|
|
|
if (!cb || !storage || !storage->data) {
|
2017-02-06 15:27:43 +00:00
|
|
|
return false;
|
2017-02-08 23:01:42 +01:00
|
|
|
}
|
2017-02-06 15:27:43 +00:00
|
|
|
for (i = 0; i < storage->top_id; i++) {
|
2017-02-08 23:01:42 +01:00
|
|
|
if (storage->data[i]) {
|
|
|
|
if (!cb (user, storage->data[i], i)) {
|
2017-02-06 15:27:43 +00:00
|
|
|
return false;
|
2017-02-08 23:01:42 +01:00
|
|
|
}
|
|
|
|
}
|
2017-02-06 15:27:43 +00:00
|
|
|
}
|
2017-02-08 23:01:42 +01:00
|
|
|
if (storage->data[i]) {
|
2017-02-06 15:27:43 +00:00
|
|
|
return cb (user, storage->data[i], i);
|
2017-02-08 23:01:42 +01:00
|
|
|
}
|
2017-02-06 15:27:43 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-02-12 16:13:41 +01:00
|
|
|
R_API void r_id_storage_free(RIDStorage *storage) {
|
2017-02-06 15:27:43 +00:00
|
|
|
if (storage) {
|
|
|
|
r_id_pool_free (storage->pool);
|
|
|
|
free (storage->data);
|
|
|
|
}
|
|
|
|
free (storage);
|
|
|
|
}
|