Rizin
unix-like reverse engineering framework and cli tools
skiplist.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2016 Jeffrey Crowell
2 // SPDX-FileCopyrightText: 2016 ret2libc <sirmy15@gmail.com>
3 // SPDX-License-Identifier: BSD-3-Clause
4 
5 // Skiplists are a probabilistic datastructure than can be used as a k-v store
6 // with average case O(lg n) lookup time, and worst case O(n).
7 
8 // https://en.wikipedia.org/wiki/Skip_list
9 
10 #include <rz_skiplist.h>
11 
12 #define SKIPLIST_MAX_DEPTH 31
13 
14 static RzSkipListNode *rz_skiplist_node_new(void *data, int level) {
16  if (!res) {
17  return NULL;
18  }
19  res->forward = RZ_NEWS0(RzSkipListNode *, level + 1);
20  if (!res->forward) {
21  free(res);
22  return NULL;
23  }
24  res->data = data;
25  return res;
26 }
27 
29  if (node) {
30  if (list->freefn && node->data) {
31  list->freefn(node->data);
32  }
33  free(node->forward);
34  free(node);
35  }
36 }
37 
38 static void init_head(RzSkipListNode *head) {
39  int i;
40  for (i = 0; i <= SKIPLIST_MAX_DEPTH; i++) {
41  head->forward[i] = head;
42  }
43 }
44 
45 // Find the insertion/deletion point for the element `data` in the list.
46 // The array `updates`, if provided, is filled with the nodes that need to be
47 // updated for each layer.
48 //
49 // NOTE: `updates` should be big enough to contain `list->list_level + 1`
50 // elements, when provided.
51 static RzSkipListNode *find_insertpoint(RzSkipList *list, void *data, RzSkipListNode **updates, bool by_data) {
52  RzSkipListNode *x = list->head;
53  int i;
54 
55  for (i = list->list_level; i >= 0; i--) {
56  if (by_data) {
57  while (x->forward[i] != list->head && list->compare(x->forward[i]->data, data) < 0) {
58  x = x->forward[i];
59  }
60  } else {
61  while (x->forward[i] != list->head && x->forward[i] != data) {
62  x = x->forward[i];
63  }
64  }
65  if (updates) {
66  updates[i] = x;
67  }
68  }
69  x = x->forward[0];
70  return x;
71 }
72 
73 static bool delete_element(RzSkipList *list, void *data, bool by_data) {
74  int i;
76 
77  // locate delete points in the lists of all levels
78  x = find_insertpoint(list, data, update, by_data);
79  // do nothing if the element is not present in the list
80  if (x == list->head || list->compare(x->data, data) != 0) {
81  return false;
82  }
83 
84  // update forward links for all `update` points,
85  // by removing the element from the list in each level
86  for (i = 0; i <= list->list_level; i++) {
87  if (update[i]->forward[i] != x) {
88  break;
89  }
90  update[i]->forward[i] = x->forward[i];
91  }
93 
94  // update the level of the list
95  while ((list->list_level > 0) &&
96  (list->head->forward[list->list_level] == list->head)) {
97  list->list_level--;
98  }
99  list->size--;
100  return true;
101 }
102 
103 // Takes in a pointer to the function to free a list element, and a pointer to
104 // a function that returns 0 on equality between two elements, and -1 or 1
105 // when unequal (for sorting).
106 // Returns a new heap-allocated skiplist.
109  if (!list) {
110  return NULL;
111  }
112 
114  if (!list->head) {
115  free(list);
116  return NULL;
117  }
118 
119  init_head(list->head);
120  list->list_level = 0;
121  list->size = 0;
122  list->freefn = freefn;
123  list->compare = comparefn;
124  return list;
125 }
126 
127 // Remove all elements from the list
129  RzSkipListNode *n;
130  if (!list) {
131  return;
132  }
133  n = list->head->forward[0];
134  while (n != list->head) {
135  RzSkipListNode *x = n;
136  n = n->forward[0];
138  }
139  init_head(list->head);
140  list->size = 0;
141  list->list_level = 0;
142 }
143 
144 // Free the entire list and it's element (if freefn is specified)
146  if (!list) {
147  return;
148  }
151  free(list);
152 }
153 
154 // Inserts an element to the skiplist, and returns a pointer to the element's
155 // node.
158  RzSkipListNode *x;
159  int i, x_level, new_level;
160 
161  // locate insertion points in the lists of all levels
162  x = find_insertpoint(list, data, update, true);
163  // check whether the element is already in the list
164  if (x != list->head && !list->compare(x->data, data)) {
165  return x;
166  }
167 
168  // randomly choose the number of levels the new node will be put in
169  for (x_level = 0; rand() < RAND_MAX / 2 && x_level < SKIPLIST_MAX_DEPTH; x_level++) {
170  ;
171  }
172 
173  // update the `update` array with default values when the current node
174  // has a level greater than the current one
175  new_level = list->list_level;
176  if (x_level > list->list_level) {
177  for (i = list->list_level + 1; i <= x_level; i++) {
178  update[i] = list->head;
179  }
180  new_level = x_level;
181  }
182 
183  x = rz_skiplist_node_new(data, x_level);
184  if (!x) {
185  return NULL;
186  }
187 
188  // update forward links for all `update` points,
189  // by inserting the new element in the list in each level
190  for (i = 0; i <= x_level; i++) {
191  x->forward[i] = update[i]->forward[i];
192  update[i]->forward[i] = x;
193  }
194 
195  list->list_level = new_level;
196  list->size++;
197  return x;
198 }
199 
200 // Delete node with data as it's payload.
202  return delete_element(list, data, true);
203 }
204 
205 // Delete the given RzSkipListNode from the skiplist
207  return delete_element(list, node, false);
208 }
209 
211  RzSkipListNode *x = find_insertpoint(list, data, NULL, true);
212  if (x != list->head && list->compare(x->data, data) == 0) {
213  return x;
214  }
215  return NULL;
216 }
217 
219  RzSkipListNode *x = find_insertpoint(list, data, NULL, true);
220  return x != list->head ? x : NULL;
221 }
222 
224  RzSkipListNode *x = list->head;
225  int i;
226 
227  for (i = list->list_level; i >= 0; i--) {
228  while (x->forward[i] != list->head && list->compare(x->forward[i]->data, data) <= 0) {
229  x = x->forward[i];
230  }
231  }
232  return x != list->head ? x : NULL;
233 }
234 
235 // Move all the elements of `l2` in `l1`.
237  RzSkipListNode *it;
238  void *data;
239 
240  rz_skiplist_foreach (l2, it, data) {
241  (void)rz_skiplist_insert(l1, data);
242  }
243 
244  rz_skiplist_purge(l2);
245 }
246 
247 // Returns the first data element in the list, if present, NULL otherwise
249  if (!list) {
250  return NULL;
251  }
252  RzSkipListNode *res = list->head->forward[0];
253  return res == list->head ? NULL : res->data;
254 }
255 
256 // Returns the nth data element in the list, if present, NULL otherwise
258  int count = 0;
259  RzSkipListNode *node;
260  void *data;
261  if (!list || n < 0) {
262  return NULL;
263  }
264  rz_skiplist_foreach (list, node, data) {
265  if (count == n) {
266  return data;
267  }
268  ++count;
269  }
270  return NULL;
271 }
272 
275  return x ? x->data : NULL;
276 }
277 
280  return x ? x->data : NULL;
281 }
282 
283 // Return true if the list is empty
285  return list->size == 0;
286 }
287 
288 // Return a new allocated RzList representing the given `list`
289 //
290 // NOTE: the data will be shared between the two lists. The user of this
291 // function should choose which list will "own" the data pointers.
293  RzList *res = rz_list_new();
294  RzSkipListNode *n;
295  void *data;
296 
297  rz_skiplist_foreach (list, n, data) {
298  rz_list_append(res, data);
299  }
300 
301  return res;
302 }
lzma_index ** i
Definition: index.h:629
#define RZ_API
#define NULL
Definition: cris-opc.c:27
static bool update(RzCrypto *cry, const ut8 *buf, int len)
Definition: crypto_aes.c:92
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void count
Definition: sflib.h:98
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
static void freefn(HtName_(Ht) *ht, HT_(Kv) *kv)
Definition: ht_inc.c:46
static void list(RzEgg *egg)
Definition: rz-gg.c:52
RZ_API RZ_OWN RzList * rz_list_new(void)
Returns a new initialized RzList pointer (free method is not initialized)
Definition: list.c:235
RZ_API RZ_BORROW RzListIter * rz_list_append(RZ_NONNULL RzList *list, void *data)
Appends at the end of the list a new element.
Definition: list.c:288
int x
Definition: mipsasm.c:20
int n
Definition: mipsasm.c:19
void(* RzListFree)(void *ptr)
Definition: rz_list.h:11
int(* RzListComparator)(const void *value, const void *list_data)
Definition: rz_list.h:33
#define rz_skiplist_foreach(list, it, pos)
Definition: rz_skiplist.h:48
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_NEWS0(x, y)
Definition: rz_types.h:282
RZ_API void * rz_skiplist_get_n(RzSkipList *list, int n)
Definition: skiplist.c:257
static RzSkipListNode * rz_skiplist_node_new(void *data, int level)
Definition: skiplist.c:14
static void init_head(RzSkipListNode *head)
Definition: skiplist.c:38
RZ_API bool rz_skiplist_delete_node(RzSkipList *list, RzSkipListNode *node)
Definition: skiplist.c:206
RZ_API void * rz_skiplist_get_geq(RzSkipList *list, void *data)
Definition: skiplist.c:273
RZ_API RzSkipListNode * rz_skiplist_find(RzSkipList *list, void *data)
Definition: skiplist.c:210
RZ_API bool rz_skiplist_delete(RzSkipList *list, void *data)
Definition: skiplist.c:201
RZ_API void * rz_skiplist_get_first(RzSkipList *list)
Definition: skiplist.c:248
RZ_API void rz_skiplist_purge(RzSkipList *list)
Definition: skiplist.c:128
static bool delete_element(RzSkipList *list, void *data, bool by_data)
Definition: skiplist.c:73
RZ_API void * rz_skiplist_get_leq(RzSkipList *list, void *data)
Definition: skiplist.c:278
RZ_API RzList * rz_skiplist_to_list(RzSkipList *list)
Definition: skiplist.c:292
RZ_API RzSkipList * rz_skiplist_new(RzListFree freefn, RzListComparator comparefn)
Definition: skiplist.c:107
RZ_API void rz_skiplist_join(RzSkipList *l1, RzSkipList *l2)
Definition: skiplist.c:236
RZ_API RzSkipListNode * rz_skiplist_find_geq(RzSkipList *list, void *data)
Definition: skiplist.c:218
static void rz_skiplist_node_free(RzSkipList *list, RzSkipListNode *node)
Definition: skiplist.c:28
RZ_API RzSkipListNode * rz_skiplist_find_leq(RzSkipList *list, void *data)
Definition: skiplist.c:223
#define SKIPLIST_MAX_DEPTH
Definition: skiplist.c:12
static RzSkipListNode * find_insertpoint(RzSkipList *list, void *data, RzSkipListNode **updates, bool by_data)
Definition: skiplist.c:51
RZ_API bool rz_skiplist_empty(RzSkipList *list)
Definition: skiplist.c:284
RZ_API void rz_skiplist_free(RzSkipList *list)
Definition: skiplist.c:145
RZ_API RzSkipListNode * rz_skiplist_insert(RzSkipList *list, void *data)
Definition: skiplist.c:156
struct rz_skiplist_node_t ** forward
Definition: rz_skiplist.h:16
static int level
Definition: vmenus.c:2424