Skip to content

Commit

Permalink
start adding skiplist
Browse files Browse the repository at this point in the history
  • Loading branch information
crowell committed Jun 29, 2016
1 parent 5317508 commit dc4edf1
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 1 deletion.
4 changes: 3 additions & 1 deletion libr/include/r_anal.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <r_io.h>
#include <r_reg.h>
#include <r_list.h>
#include <r_skiplist.h>
#include <r_util.h>
#include <r_syscall.h>
#include <r_flags.h>
Expand Down Expand Up @@ -312,7 +313,8 @@ typedef struct r_anal_type_function_t {
RAnalDiff *diff;
RList *locs; // list of local variables
//RList *locals; // list of local labels -> moved to anal->sdb_fcns
RList *bbs;
//RList *bbs;
RSkipList *bbs_sl;

This comment has been minimized.

Copy link
@radare

radare Jun 29, 2016

Collaborator

this will break bindings once again. aka, native bindings will not be able to iterate over the basic blocks

This comment has been minimized.

Copy link
@radare

radare Jun 29, 2016

Collaborator

i have an idea for not breaking the bindings. Adding a getter method like:

R_API RList *r_fcn_get_bbs(RAnalFunction *fcn) {
 /* convert RSkipList to RList here, but setting ->free to NULL to avoid dblfrees, because the ownership of the data stored by the rlist shouldnt be transfered */
  return list;
}

This comment has been minimized.

Copy link
@radare

radare Jun 29, 2016

Collaborator

this way we can make bindings safe and work again and fix that issue radare/valabind#37

RList *vars;
#if FCN_OLD
RList *refs;
Expand Down
34 changes: 34 additions & 0 deletions libr/include/r_skiplist.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// (c) 2016 Jeffrey Crowell
// BSD 3 Clause License
// radare2

// Skiplists are a probabilistic datastructure than can be used as a k-v store
// with average case O(lg n) lookup time, and worst case O(n).

// https://en.wikipedia.org/wiki/Skip_list

#ifndef R2_SKIP_LIST_H
#define R2_SKIP_LIST_H

#include <r_list.h>

typedef struct r_skiplist_node_t {
void *data; // pointer to the value
struct r_skiplist_node_t *forward[1]; // forward pointer

This comment has been minimized.

Copy link
@radare

radare Jun 29, 2016

Collaborator

[1] ???

} r_skiplist_node;

typedef struct r_skiplist_t {
r_skiplist_node *head; // list header
int list_level; // current level of the list.
RListFree freefn;
RListComparator compare;
} r_skiplist;

typedef r_skiplist RSkipList;

R_API r_skiplist* r_skiplist_new(RListFree freefn, RListComparator comparefn);
R_API r_skiplist_node* r_skiplist_insert(r_skiplist* list, void* data);
R_API void r_skiplist_delete(r_skiplist* list, void* data);
R_API r_skiplist_node* r_skiplist_find(r_skiplist* list, void* data);

#endif // R2_SKIP_LIST_H
1 change: 1 addition & 0 deletions libr/include/r_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <r_list.h> // radare linked list
#include <r_flist.h> // radare fixed pointer array iterators
#include <list.h> // kernel linked list
#include <r_skiplist.h> // skiplist
#include <r_th.h>
#include <dirent.h>
#include <sys/time.h>
Expand Down
131 changes: 131 additions & 0 deletions libr/util/r_skiplist.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// (c) 2016 Jeffrey Crowell

This comment has been minimized.

Copy link
@radare

radare Jun 29, 2016

Collaborator

follow the same oneliner copyright used in other r2 .c files (grep friendly)

// BSD 3 Clause License
// radare2

// Skiplists are a probabilistic datastructure than can be used as a k-v store
// with average case O(lg n) lookup time, and worst case O(n).

// https://en.wikipedia.org/wiki/Skip_list

#include <r_skiplist.h>

const int kSkipListDepth = 15; // max depth

This comment has been minimized.

Copy link
@radare

radare Jun 29, 2016

Collaborator

what about define instead of const? and use uppercase naming


// Takes in a pointer to the function to free a list element, and a pointer to
// a function that retruns 0 on equality between two elements, and -1 or 1
// when unequal (for sorting).
// Returns a new heap-allocated skiplist.
R_API r_skiplist* r_skiplist_new(RListFree freefn, RListComparator comparefn) {
int i;
r_skiplist* list = calloc (1, sizeof (r_skiplist));

This comment has been minimized.

Copy link
@radare

radare Jun 29, 2016

Collaborator

use R_NEW0

if ((list->head =
calloc (1,

This comment has been minimized.

Copy link
@radare

radare Jun 29, 2016

Collaborator

wtf creepy indent

This comment has been minimized.

Copy link
@radare

radare Jun 29, 2016

Collaborator

wrong usage of calloc(1,foo*bar) must be calloc(foo,bar)

sizeof (r_skiplist_node) +
kSkipListDepth * sizeof (r_skiplist_node*))) == NULL) {

This comment has been minimized.

Copy link
@radare

radare Jun 29, 2016

Collaborator

use ! instead of NULL

eprintf ("can't init skiplist...");
return NULL;
}
for (i = 0; i <= kSkipListDepth; i++) {
list->head->forward[i] = list->head;
}
list->list_level = 0;
return list;
}

// Inserts an element to the skiplist, and returns a pointer to the element's
// node.
R_API r_skiplist_node* r_skiplist_insert(r_skiplist* list, void* data) {
int i, new_level;
r_skiplist_node* update [kSkipListDepth + 1];

This comment has been minimized.

Copy link
@radare

radare Jun 29, 2016

Collaborator

you can define nnode in the same line and put int i, newlevel after it

r_skiplist_node* nnode;

This comment has been minimized.

Copy link
@radare

radare Jun 29, 2016

Collaborator

assign and define in a single line


// Find the spot for it.
nnode = list->head;
for (i = list->list_level; i >= 0; i--) {
while ((nnode->forward[i] != list->head) &&

This comment has been minimized.

Copy link
@radare

radare Jun 29, 2016

Collaborator

maybe move this logic into a separate static inline function to make the loop condition more readable?

(list->compare (nnode->forward[i]->data, data) < 1)) {
nnode = nnode->forward[i];
}
update[i] = nnode;
}
nnode = nnode->forward[0];
if (nnode != list->head && list->compare (nnode->data, data) == 0) {
return nnode;
}

// Determine the level "randomly".
// Skiplists are a probabilistic datastructure.
for (new_level = 0; rand() % 2 && new_level < kSkipListDepth; new_level++);

This comment has been minimized.

Copy link
@radare

radare Jun 29, 2016

Collaborator

use {\n/* empty body */\n} instead of ; not sure if rand() is completely a good idea


if (new_level < list->list_level) {
for (i = list->list_level + 1; i <= new_level; i++) {
update[i] = list->head;
}
}

// Okie, now make the node actually...
if ((nnode = calloc (1,

This comment has been minimized.

Copy link
@radare

radare Jun 29, 2016

Collaborator

wtf indent here

sizeof (r_skiplist_node) +

This comment has been minimized.

Copy link
@radare

radare Jun 29, 2016

Collaborator

dont calloc (1, foo*bar).. calloc is suposed tob e used like this: calloc(foo,bar)

new_level * sizeof (r_skiplist_node*))) == NULL) {

This comment has been minimized.

Copy link
@radare

radare Jun 29, 2016

Collaborator

use ! instead of == NULL

eprintf ("can't calloc new node for skiplist");
return NULL;
}
nnode->data = data;

// update fwd links.
for (i = 0; i <= new_level; i++) {
nnode->forward[i] = update[i]->forward[i];
}
return nnode;
}

R_API void r_skiplist_delete(r_skiplist* list, void* data) {

This comment has been minimized.

Copy link
@radare

radare Jun 29, 2016

Collaborator

what about return bool here

int i;
r_skiplist_node *update[kSkipListDepth + 1], *node;

// Delete node with data as it's payload.
node = list->head;
for (i = list->list_level; i >=0; i--) {
while (node->forward[i] != list->head &&
list->compare (node->forward[i]->data, data) < 1) {
node = node->forward[i];
}
update[i] = node;
}
node = node->forward[0];
if (node == list->head || !list->compare(node->data, data)) {
return;
}

This comment has been minimized.

Copy link
@radare

radare Jun 29, 2016

Collaborator

empty line

// Update the fwd pointers.
for (i = 0; i <= list->list_level; i++) {
if (update[i]->forward[i] != node) {
break;
} else {

This comment has been minimized.

Copy link
@radare

radare Jun 29, 2016

Collaborator

there's no need to else after break

update[i]->forward[i] = node->forward[i];
}
}
free (node);

// Update the level.
while ((list->list_level > 0) &&
(list->head->forward[list->list_level] == list->head)) {
list->list_level--;
}
}

R_API r_skiplist_node* r_skiplist_find(r_skiplist* list, void* data) {
int i;
r_skiplist_node* node = list->head;
for (i = list->list_level; i >= 0; i--) {
while (node->forward[i] != list->head &&
list->compare (node->forward[i]->data, data) < 0) {
node = node->forward[i];
}
}
node = node->forward[0];
if (node != list->head && list->compare (node->data, data)) {

This comment has been minimized.

Copy link
@radare

radare Jun 29, 2016

Collaborator

use ternary operator here

return node;
}
return NULL;
}

1 comment on commit dc4edf1

@ret2libc
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@crowell Just to be consistent with the other files, we probably don't need the r_ prefix in the filename of the .c

Please sign in to comment.