/* radare - LGPL - Copyright 2007-2022 - pancake, alvarofe */ #define _R_LIST_C_ #include "r_util.h" #include #define MERGE_LIMIT 24 R_API size_t r_list_iter_length(RListIter *iter) { size_t count = 0; while (iter->n) { count++; iter = iter->n; } return count; } inline RListIter *r_list_iter_new(void) { return calloc (1, sizeof (RListIter)); } R_API void r_list_iter_free(RListIter *list) { /* do nothing? */ } R_API RListIter *r_list_iter_get_next(RListIter *list) { r_return_val_if_fail (list, NULL); return list->n; } R_API RListIter *r_list_iter_get_prev(RListIter *list) { r_return_val_if_fail (list, NULL); return list->p; } R_API void *r_list_iter_get_data(RListIter *list) { r_return_val_if_fail (list, NULL); return list->data; } R_API RListIter *r_list_iterator(const RList *list) { r_return_val_if_fail (list, NULL); return list->head; } R_API RListIter *r_list_push(RList *list, void *item) { return r_list_append (list, item); } R_API RListIter *r_list_get_next(RListIter *list) { r_return_val_if_fail (list, NULL); return list->n; } // rename to head/last R_API void *r_list_first(const RList *list) { r_return_val_if_fail (list, NULL); return list->head ? list->head->data : NULL; } R_API void *r_list_last(const RList *list) { r_return_val_if_fail (list, NULL); return list->tail ? list->tail->data : NULL; } R_API void r_list_init(RList *list) { list->head = NULL; list->tail = NULL; list->free = NULL; list->length = 0; list->sorted = false; } R_API int r_list_length(const RList *list) { r_return_val_if_fail (list, 0); return list->length; } /* remove all elements of a list */ R_API void r_list_purge(RList *list) { if (!list) { return; } RListIter *it = list->head; while (it) { RListIter *next = it->n; r_list_delete (list, it); it = next; } list->length = 0; list->head = list->tail = NULL; } /* free the list */ R_API void r_list_free(RList *list) { if (list) { r_list_purge (list); free (list); } } R_API bool r_list_delete_data(RList *list, void *ptr) { void *p; RListIter *iter; r_return_val_if_fail (list, false); r_list_foreach (list, iter, p) { if (ptr == p) { r_list_delete (list, iter); return true; } } return false; } R_API void r_list_delete(RList *list, RListIter *iter) { r_return_if_fail (list && iter); r_list_split_iter (list, iter); if (list->free && iter->data) { list->free (iter->data); } iter->data = NULL; free (iter); } R_API void r_list_split(RList *list, void *ptr) { r_return_if_fail (list); RListIter *iter = r_list_iterator (list); while (iter) { void *item = iter->data; if (ptr == item) { r_list_split_iter (list, iter); free (iter); break; } iter = iter->n; } } R_API void r_list_split_iter(RList *list, RListIter *iter) { r_return_if_fail (list); if (list->head == iter) { list->head = iter->n; } if (list->tail == iter) { list->tail = iter->p; } if (iter->p) { iter->p->n = iter->n; } if (iter->n) { iter->n->p = iter->p; } list->length--; } //Warning: free functions must be compatible R_API int r_list_join(RList *list1, RList *list2) { r_return_val_if_fail (list1 && list2, 0); if (!(list2->length)) { return 0; } if (!(list1->length)) { list1->head = list2->head; list1->tail = list2->tail; } else { list1->tail->n = list2->head; list2->head->p = list1->tail; list1->tail = list2->tail; list1->tail->n = NULL; list1->sorted = false; } list1->length += list2->length; list2->length = 0; list2->head = list2->tail = NULL; return 1; } R_API RList *r_list_new(void) { RList *list = R_NEW0 (RList); if (!list) { return NULL; } r_list_init (list); return list; } R_API RList *r_list_newf(RListFree f) { RList *l = r_list_new (); if (l) { l->free = f; } return l; } R_API RListIter *r_list_item_new(void *data) { RListIter *item = R_NEW0 (RListIter); if (item) { item->data = data; } return item; } R_API RListIter *r_list_append(RList *list, void *data) { r_return_val_if_fail (list, NULL); RListIter *item = r_list_item_new (data); if (!item) { return NULL; } if (list->tail) { list->tail->n = item; } item->p = list->tail; list->tail = item; if (!list->head) { list->head = item; } list->length++; list->sorted = false; return item; } R_API RListIter *r_list_prepend(RList *list, void *data) { r_return_val_if_fail (list, NULL); RListIter *item = r_list_item_new (data); if (!item) { return NULL; } if (list->head) { list->head->p = item; } item->n = list->head; list->head = item; if (!list->tail) { list->tail = item; } list->length++; list->sorted = false; return item; } R_API RListIter *r_list_insert(RList *list, ut32 n, void *data) { r_return_val_if_fail (list, NULL); if (!list->head || !n) { return r_list_prepend (list, data); } RListIter *it; ut32 i; for (it = list->head, i = 0; it && it->data; it = it->n, i++) { if (i == n) { RListIter *item = r_list_item_new (data); if (!item) { return NULL; } item->n = it; item->p = it->p; if (it->p) { it->p->n = item; } it->p = item; list->length++; list->sorted = false; return item; } } return r_list_append (list, data); } R_API void *r_list_pop(RList *list) { void *data = NULL; RListIter *iter; r_return_val_if_fail (list, NULL); if (list->tail) { iter = list->tail; if (list->head == list->tail) { list->head = list->tail = NULL; } else { list->tail = iter->p; list->tail->n = NULL; } data = iter->data; free (iter); list->length--; } return data; } R_API void *r_list_pop_head(RList *list) { void *data = NULL; r_return_val_if_fail (list, NULL); if (list->head) { RListIter *iter = list->head; if (list->head == list->tail) { list->head = list->tail = NULL; } else { list->head = iter->n; list->head->p = NULL; } data = iter->data; free (iter); list->length--; } return data; } R_API int r_list_del_n(RList *list, int n) { RListIter *it; int i; r_return_val_if_fail (list, false); for (it = list->head, i = 0; it && it->data; it = it->n, i++) { if (i == n) { if (!it->p && !it->n) { list->head = list->tail = NULL; } else if (!it->p) { it->n->p = NULL; list->head = it->n; } else if (!it->n) { it->p->n = NULL; list->tail = it->p; } else { it->p->n = it->n; it->n->p = it->p; } free (it); list->length--; return true; } } return false; } R_API void *r_list_get_top(const RList *list) { r_return_val_if_fail (list, NULL); return list->tail ? list->tail->data : NULL; } R_API void *r_list_get_bottom(const RList *list) { r_return_val_if_fail (list, NULL); return list->head ? list->head->data : NULL; } // Moves an iter to the top(tail) of the list // There is an underlying assumption here, that iter is an RListIter of this RList R_API void r_list_iter_to_top(RList *list, RListIter *iter) { r_return_if_fail (list && iter); if (list->tail == iter) { return; } iter->n->p = iter->p; if (list->head == iter) { list->head = iter->n; } else { iter->p->n = iter->n; } iter->p = list->tail; list->tail->n = iter; iter->n = NULL; list->tail = iter; list->sorted = false; } R_API void r_list_reverse(RList *list) { RListIter *it, *tmp; r_return_if_fail (list); for (it = list->head; it && it->data; it = it->p) { tmp = it->p; it->p = it->n; it->n = tmp; } tmp = list->head; list->head = list->tail; list->tail = tmp; } R_API RList *r_list_clone(const RList *list) { RListIter *iter; void *data; r_return_val_if_fail (list, NULL); RList *l = r_list_new (); if (!l) { return NULL; } l->free = NULL; r_list_foreach (list, iter, data) { r_list_append (l, data); } l->sorted = list->sorted; return l; } R_API RListIter *r_list_add_sorted(RList *list, void *data, RListComparator cmp) { RListIter *it, *item = NULL; r_return_val_if_fail (list && data && cmp, NULL); for (it = list->head; it && it->data && cmp (data, it->data) > 0; it = it->n) { ; } if (it) { item = R_NEW0 (RListIter); if (!item) { return NULL; } item->n = it; item->p = it->p; item->data = data; item->n->p = item; if (!item->p) { list->head = item; } else { item->p->n = item; } list->length++; } else { r_list_append (list, data); } list->sorted = true; return item; } R_API int r_list_set_n(RList *list, int n, void *p) { RListIter *it; int i; r_return_val_if_fail (list, false); for (it = list->head, i = 0; it ; it = it->n, i++) { if (i == n) { if (list->free) { list->free (it->data); } it->data = p; list->sorted = false; return true; } } return false; } R_API void *r_list_get_n(const RList *list, int n) { RListIter *it; int i; r_return_val_if_fail (list, NULL); for (it = list->head, i = 0; it && it->data; it = it->n, i++) { if (i == n) { return it->data; } } return NULL; } R_API RListIter *r_list_contains(const RList *list, const void *p) { void *q; RListIter *iter; r_return_val_if_fail (list, NULL); r_list_foreach (list, iter, q) { if (p == q) { return iter; } } return NULL; } R_API RListIter *r_list_find(const RList *list, const void *p, RListComparator cmp) { void *q; RListIter *iter; r_return_val_if_fail (list, NULL); r_list_foreach (list, iter, q) { if (!cmp (p, q)) { return iter; } } return NULL; } static RListIter *_merge(RListIter *first, RListIter *second, RListComparator cmp) { RListIter *next = NULL, *result = NULL, *head = NULL; while (first || second) { if (!second) { next = first; first = first->n; } else if (!first) { next = second; second = second->n; } else if (cmp (first->data, second->data) <= 0) { next = first; first = first->n; } else { next = second; second = second->n; } if (!head) { result = next; head = result; head->p = NULL; } else { result->n = next; next->p = result; result = result->n; } } head->p = NULL; next->n = NULL; return head; } static RListIter *_r_list_half_split(RListIter *head) { RListIter *tmp; RListIter *fast; RListIter *slow; if (!head || !head->n) { return head; } slow = head; fast = head; int count = 0; while (fast && fast->n && fast->n->n) { fast = fast->n->n; slow = slow->n; count++; } if (count < MERGE_LIMIT) { return NULL; } tmp = slow->n; slow->n = NULL; return tmp; } static void list_insertion_sort_iter(RListIter *iter, RListComparator cmp) { RListIter *it, *it2; for (it = iter; it && it->data; it = it->n) { for (it2 = it->n; it2 && it2->data; it2 = it2->n) { if (cmp (it->data, it2->data) > 0) { void *t = it->data; it->data = it2->data; it2->data = t; } } } } static RListIter *_merge_sort(RListIter *head, RListComparator cmp) { RListIter *second; if (!head || !head->n) { return head; } second = _r_list_half_split (head); if (second) { head = _merge_sort (head, cmp); second = _merge_sort (second, cmp); return _merge (head, second, cmp); } list_insertion_sort_iter (head, cmp); return head; } R_API void r_list_merge_sort(RList *list, RListComparator cmp) { r_return_if_fail (list); if (!list->sorted && list->head && cmp) { RListIter *iter; list->head = _merge_sort (list->head, cmp); //update tail reference iter = list->head; while (iter && iter->n) { iter = iter->n; } list->tail = iter; } list->sorted = true; } R_API void r_list_insertion_sort(RList *list, RListComparator cmp) { r_return_if_fail (list); if (!list->sorted) { RListIter *it; RListIter *it2; if (cmp) { for (it = list->head; it && it->data; it = it->n) { for (it2 = it->n; it2 && it2->data; it2 = it2->n) { if (cmp (it->data, it2->data) > 0) { void *t = it->data; it->data = it2->data; it2->data = t; } } } } list->sorted = true; } } //chose wisely based on length R_API void r_list_sort(RList *list, RListComparator cmp) { r_return_if_fail (list); if (list->length > MERGE_LIMIT) { r_list_merge_sort (list, cmp); } else { r_list_insertion_sort (list, cmp); } } R_API RList *r_list_uniq(const RList *list, RListComparatorItem cmp) { RListIter *iter, *iter2; void *item; int deleted = 0; r_return_val_if_fail (list && cmp, 0); RList *rlist = r_list_newf (list->free); SetU *s = set_u_new (); r_list_foreach_safe (list, iter, iter2, item) { ut64 v = cmp (item); if (set_u_contains (s, v)) { deleted ++; } else { set_u_add (s, v); r_list_append (rlist, item); } } set_u_free (s); return rlist; } R_API int r_list_uniq_inplace(RList *list, RListComparatorItem cmp) { RListIter *iter, *iter2; void *item; int deleted = 0; r_return_val_if_fail (list && cmp, 0); SetU *s = set_u_new (); r_list_foreach_safe (list, iter, iter2, item) { ut64 v = cmp (item); if (set_u_contains (s, v)) { r_list_delete (list, iter); deleted ++; } else { set_u_add (s, v); } } set_u_free (s); return deleted; } R_API char *r_list_to_str(RList *list, char ch) { RListIter *iter; RStrBuf *buf = r_strbuf_new (""); if (!buf) { return NULL; } char *item; r_list_foreach (list, iter, item) { r_strbuf_appendf (buf, "%s%c", item, ch); } return r_strbuf_drain (buf); }