Revert "Implement Pool Node allocation for RzList (#6203)" (#6313)

This reverts commit d3a97d5ef8.
This commit is contained in:
Giovanni 2026-05-04 22:45:00 +08:00 committed by GitHub
parent 76a41c8166
commit 2f0dcd65b2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 437 additions and 426 deletions

View file

@ -10,8 +10,6 @@ extern "C" {
typedef void (*RzListFree)(void *ptr);
#define RZ_LIST_SLAB_SIZE 256
typedef struct rz_list_iter_t RzListIter;
struct rz_list_iter_t {
@ -20,23 +18,12 @@ struct rz_list_iter_t {
RzListIter *prev;
};
typedef struct rz_list_slab_t {
RzListIter nodes[RZ_LIST_SLAB_SIZE];
struct rz_list_slab_t *next_slab;
} RzListSlab;
typedef struct rz_list_pool_t {
RzListSlab *slabs;
RzListIter *freelist;
} RzListPool;
typedef struct rz_list_t {
RzListIter *head;
RzListIter *tail;
RzListFree free;
ut32 length;
bool sorted;
RzListPool *pool;
} RzList;
// RzListComparator should return -1, 0, 1 to indicate "value < list_data", "value == list_data", "value > list_data".

View file

@ -5,90 +5,6 @@
#include <stdio.h>
#include <rz_util.h>
static void rz_list_pool_free(RzListPool *pool) {
if (!pool) {
return;
}
RzListSlab *slab = pool->slabs;
while (slab) {
RzListSlab *next = slab->next_slab;
free(slab);
slab = next;
}
free(pool);
}
/**
* \brief Allocates an RzListIter from the pool, growing by one slab if needed.
* If \p pool is NULL, falls back to a plain heap allocation.
*/
static inline RzListIter *pool_alloc_node(RzListPool *pool) {
if (!pool) {
return RZ_NEW0(RzListIter);
}
if (!pool->freelist) {
RzListSlab *slab = RZ_NEW0(RzListSlab);
if (!slab) {
return NULL;
}
slab->next_slab = pool->slabs;
pool->slabs = slab;
for (int i = 0; i < RZ_LIST_SLAB_SIZE - 1; i++) {
slab->nodes[i].next = &slab->nodes[i + 1];
}
slab->nodes[RZ_LIST_SLAB_SIZE - 1].next = NULL;
pool->freelist = &slab->nodes[0];
}
RzListIter *n = pool->freelist;
pool->freelist = n->next;
n->next = NULL;
n->prev = NULL;
n->val = NULL;
return n;
}
/**
* \brief Returns an RzListIter node back to the pool freelist so it can be
* reused, without freeing any heap memory.
* If \p pool is NULL, the node was heap-allocated and is freed directly.
*/
static inline void pool_return_node(RzListPool *pool, RzListIter *node) {
if (!node) {
return;
}
if (!pool) {
free(node);
return;
}
node->val = NULL;
node->prev = NULL;
node->next = pool->freelist;
pool->freelist = node;
}
/**
* \brief Returns the RzListIter at position \p n, traversing from whichever
* end is closer. Returns NULL if \p n is out of bounds.
**/
static inline RzListIter *rz_list_iter_at(const RzList *list, ut32 n) {
if (n >= list->length) {
return NULL;
}
RzListIter *it;
if (n < list->length / 2) {
it = list->head;
for (ut32 i = 0; i < n; i++) {
it = it->next;
}
} else {
it = list->tail;
for (ut32 i = list->length - 1; i > n; i--) {
it = it->prev;
}
}
return it;
}
/**
* \brief returns the value stored in the prev RzList iterator
*
@ -128,7 +44,7 @@ RZ_API bool rz_list_iter_swap_data(RZ_NONNULL RzListIter *iter0, RZ_NONNULL RzLi
}
/**
* \brief returns the first RzList iterator in the list
* \brief returns the first RzList iterator int the list
*
**/
RZ_API RZ_BORROW RzListIter *rz_list_iterator(RZ_NONNULL const RzList *list) {
@ -174,7 +90,6 @@ RZ_API void rz_list_init(RZ_NONNULL RzList *list) {
list->free = NULL;
list->length = 0;
list->sorted = false;
list->pool = RZ_NEW0(RzListPool);
}
/**
@ -189,23 +104,21 @@ RZ_API ut32 rz_list_length(RZ_NONNULL const RzList *list) {
}
static void _list_purge_with_free(RzList *list) {
RzListPool *pool = list->pool;
RzListIter *it = list->head;
RzListFree fn = list->free;
while (it) {
RzListIter *next = it->next;
fn(it->val);
pool_return_node(pool, it);
free(it);
it = next;
}
}
static void _list_purge_no_free(RzList *list) {
RzListPool *pool = list->pool;
RzListIter *it = list->head;
while (it) {
RzListIter *next = it->next;
pool_return_node(pool, it);
free(it);
it = next;
}
}
@ -236,7 +149,6 @@ RZ_API void rz_list_free(RZ_NULLABLE RzList *list) {
return;
}
rz_list_purge(list);
rz_list_pool_free(list->pool);
free(list);
}
@ -277,61 +189,32 @@ RZ_API void rz_list_delete(RZ_NONNULL RzList *list, RZ_OWN RZ_NONNULL RzListIter
list->free(iter->val);
}
iter->val = NULL;
pool_return_node(list->pool, iter);
free(iter);
}
/**
* \brief Joins list2 into list1 by copying all values; list2 is left empty
* but its structure (pool, free pointer) is preserved.
* The caller is responsible for freeing list2 afterward.
* \brief Joins 2 list into one (list2 pointer needs to be freed by the user)
*
* \note list2's free callback is NOT called during the join so that values
* transferred to list1 are not prematurely destroyed.
**/
RZ_API bool rz_list_join(RZ_NONNULL RzList *list1, RZ_NONNULL RzList *list2) {
rz_return_val_if_fail(list1 && list2, false);
if (!list2->length) {
rz_return_val_if_fail(list1 && list2, 0);
if (!(list2->length)) {
return false;
}
RzListPool *pool1 = list1->pool;
RzListIter *it = list2->head;
while (it) {
RzListIter *n = pool_alloc_node(pool1);
if (!n) {
return false;
}
n->val = it->val;
n->prev = list1->tail;
n->next = NULL;
if (list1->tail) {
list1->tail->next = n;
}
list1->tail = n;
if (!list1->head) {
list1->head = n;
}
list1->length++;
it = it->next;
if (!(list1->length)) {
list1->head = list2->head;
list1->tail = list2->tail;
} else {
list1->tail->next = list2->head;
list2->head->prev = list1->tail;
list1->tail = list2->tail;
list1->tail->next = NULL;
list1->sorted = false;
}
list1->sorted = false;
/*
* Walk list2's nodes and return each one to list2's pool (or free them
* if list2 has no pool). We must NOT call list2->free on the values
* because ownership of the values has just been transferred to list1.
*/
RzListIter *cur = list2->head;
while (cur) {
RzListIter *next = cur->next;
pool_return_node(list2->pool, cur);
cur = next;
}
list2->head = NULL;
list2->tail = NULL;
list1->length += list2->length;
list2->length = 0;
list2->head = list2->tail = NULL;
return true;
}
@ -403,7 +286,7 @@ RZ_API RZ_OWN RzList *rz_list_new_from_iterator(RZ_BORROW RZ_NONNULL RzIterator
*
**/
RZ_API RZ_OWN RzListIter *rz_list_item_new(RZ_NULLABLE void *data) {
RzListIter *item = pool_alloc_node(NULL);
RzListIter *item = RZ_NEW0(RzListIter);
if (item) {
item->val = data;
}
@ -419,7 +302,7 @@ RZ_API RZ_BORROW RzListIter *rz_list_append(RZ_NONNULL RzList *list, RZ_NONNULL
rz_return_val_if_fail(list, NULL);
item = pool_alloc_node(list->pool);
item = RZ_NEW(RzListIter);
if (!item) {
return item;
}
@ -445,7 +328,7 @@ RZ_API RZ_BORROW RzListIter *rz_list_append(RZ_NONNULL RzList *list, RZ_NONNULL
RZ_API RZ_BORROW RzListIter *rz_list_prepend(RZ_NONNULL RzList *list, RZ_NONNULL void *data) {
rz_return_val_if_fail(list, NULL);
RzListIter *item = pool_alloc_node(list->pool);
RzListIter *item = RZ_NEW0(RzListIter);
if (!item) {
return NULL;
}
@ -469,30 +352,33 @@ RZ_API RZ_BORROW RzListIter *rz_list_prepend(RZ_NONNULL RzList *list, RZ_NONNULL
*
**/
RZ_API RZ_BORROW RzListIter *rz_list_insert(RZ_NONNULL RzList *list, ut32 n, RZ_NONNULL void *data) {
RzListIter *it, *item;
ut32 i;
rz_return_val_if_fail(list, NULL);
if (!list->head || !n) {
return rz_list_prepend(list, data);
}
RzListIter *it = rz_list_iter_at(list, n);
if (!it) {
return rz_list_append(list, data);
for (it = list->head, i = 0; it && it->val; it = it->next, i++) {
if (i == n) {
item = RZ_NEW(RzListIter);
if (!item) {
return NULL;
}
item->val = data;
item->next = it;
item->prev = it->prev;
if (it->prev) {
it->prev->next = item;
}
it->prev = item;
list->length++;
list->sorted = true;
return item;
}
}
RzListIter *item = pool_alloc_node(list->pool);
if (!item) {
return NULL;
}
item->val = data;
item->next = it;
item->prev = it->prev;
if (it->prev) {
it->prev->next = item;
} else {
list->head = item;
}
it->prev = item;
list->length++;
list->sorted = false;
return item;
return rz_list_append(list, data);
}
/**
@ -514,7 +400,7 @@ RZ_API RZ_OWN void *rz_list_pop(RZ_NONNULL RzList *list) {
list->tail->next = NULL;
}
data = iter->val;
pool_return_node(list->pool, iter);
free(iter);
list->length--;
}
return data;
@ -538,7 +424,7 @@ RZ_API RZ_OWN void *rz_list_pop_head(RZ_NONNULL RzList *list) {
list->head->prev = NULL;
}
data = iter->val;
pool_return_node(list->pool, iter);
free(iter);
list->length--;
}
return data;
@ -549,13 +435,30 @@ RZ_API RZ_OWN void *rz_list_pop_head(RZ_NONNULL RzList *list) {
*
**/
RZ_API ut32 rz_list_del_n(RZ_NONNULL RzList *list, ut32 n) {
RzListIter *it;
ut32 i;
rz_return_val_if_fail(list, false);
RzListIter *it = rz_list_iter_at(list, n);
if (!it) {
return false;
for (it = list->head, i = 0; it && it->val; it = it->next, i++) {
if (i == n) {
if (!it->prev && !it->next) {
list->head = list->tail = NULL;
} else if (!it->prev) {
it->next->prev = NULL;
list->head = it->next;
} else if (!it->next) {
it->prev->next = NULL;
list->tail = it->prev;
} else {
it->prev->next = it->next;
it->next->prev = it->prev;
}
rz_list_delete(list, it);
return true;
}
}
rz_list_delete(list, it);
return true;
return false;
}
/**
@ -567,7 +470,7 @@ RZ_API void rz_list_reverse(RZ_NONNULL RzList *list) {
rz_return_if_fail(list);
for (it = list->head; it; it = it->prev) {
for (it = list->head; it && it->val; it = it->prev) {
tmp = it->prev;
it->prev = it->next;
it->next = tmp;
@ -610,7 +513,7 @@ RZ_API RZ_BORROW RzListIter *rz_list_add_sorted(RZ_NONNULL RzList *list, RZ_NONN
for (it = list->head; it && it->val && cmp(data, it->val, user) > 0; it = it->next) {
}
if (it) {
item = pool_alloc_node(list->pool);
item = RZ_NEW0(RzListIter);
if (!item) {
return NULL;
}
@ -636,17 +539,21 @@ RZ_API RZ_BORROW RzListIter *rz_list_add_sorted(RZ_NONNULL RzList *list, RZ_NONN
*
**/
RZ_API ut32 rz_list_set_n(RZ_NONNULL RzList *list, ut32 n, RZ_NONNULL void *data) {
RzListIter *it;
ut32 i;
rz_return_val_if_fail(list, false);
RzListIter *it = rz_list_iter_at(list, n);
if (!it) {
return false;
for (it = list->head, i = 0; it; it = it->next, i++) {
if (i == n) {
if (list->free) {
list->free(it->val);
}
it->val = data;
list->sorted = false;
return true;
}
}
if (list->free) {
list->free(it->val);
}
it->val = data;
list->sorted = false;
return true;
return false;
}
/**
@ -654,9 +561,20 @@ RZ_API ut32 rz_list_set_n(RZ_NONNULL RzList *list, ut32 n, RZ_NONNULL void *data
*
**/
RZ_API RZ_BORROW void *rz_list_get_n(RZ_NONNULL const RzList *list, ut32 n) {
RzListIter *it;
ut32 i;
rz_return_val_if_fail(list, NULL);
RzListIter *it = rz_list_iter_at(list, n);
return it ? it->val : NULL;
if (n >= list->length) {
return NULL;
}
for (it = list->head, i = 0; it && it->val; it = it->next, i++) {
if (i == n) {
return it->val;
}
}
return NULL;
}
/**
@ -869,7 +787,7 @@ RZ_API void rz_list_sorted_uniq(RZ_NONNULL RzList *list, RZ_NONNULL RzListCompar
}
/**
* \brief Casts a RzList containing strings into a concatenated string
* \brief Casts a RzList containg strings into a concatenated string
*
* \param list The list of strings to concatenate.
* \param ch Char to separate the match strings.

View file

@ -1,230 +1,375 @@
// SPDX-FileCopyrightText: 2026 Farhan-25 <shadowfinder1799@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#include "bench_utils.h"
#include <rz_list.h>
#include <rz_util.h>
/**
* \file bench_list.c
* \brief Benchmarks for core RzList operations.
* \brief Benchmarks for `RzList` functions - comparing rz_list_purge implementations
*/
static void _fill(RzList *l, int count) {
for (int j = 0; j < count; j++) {
rz_list_append(l, (void *)(intptr_t)j);
// Helper to populate a list with n non-null elements
static void populate_list(RzList *list, ut32 n) {
for (ut32 j = 0; j < n; ++j) {
rz_list_append(list, (void *)(size_t)(j + 1));
}
}
static void bench_append(RzTable *t_out) {
RZ_BENCH_RUN_I("[append] 10k", i, t_out, 1000, {
RzList *l = rz_list_new();
_fill(l, 10000);
rz_list_free(l);
});
RZ_BENCH_RUN_I("[append] 100k", i, t_out, 100, {
RzList *l = rz_list_new();
_fill(l, 100000);
rz_list_free(l);
});
RZ_BENCH_RUN_I("[append] 1m", i, t_out, 10, {
RzList *l = rz_list_new();
_fill(l, 1000000);
rz_list_free(l);
});
// Helper to populate a list with n heap-allocated elements (for free fn tests)
static void populate_list_alloc(RzList *list, ut32 n) {
for (ut32 j = 0; j < n; ++j) {
ut32 *val = malloc(sizeof(ut32));
*val = j;
rz_list_append(list, val);
}
}
static void bench_prepend(RzTable *t_out) {
RZ_BENCH_RUN_I("[prepend] 10k", i, t_out, 1000, {
RzList *l = rz_list_new();
for (int j = 0; j < 10000; j++) {
rz_list_prepend(l, (void *)(intptr_t)j);
}
rz_list_free(l);
});
RZ_BENCH_RUN_I("[prepend] 100k", i, t_out, 100, {
RzList *l = rz_list_new();
for (int j = 0; j < 100000; j++) {
rz_list_prepend(l, (void *)(intptr_t)j);
}
rz_list_free(l);
});
RZ_BENCH_RUN_I("[prepend] 1m", i, t_out, 10, {
RzList *l = rz_list_new();
for (int j = 0; j < 1000000; j++) {
rz_list_prepend(l, (void *)(intptr_t)j);
}
rz_list_free(l);
});
/**
* v1: Uses rz_list_delete per node (original)
* Has extra overhead: unlinks node, updates prev/next, decrements length
*/
static void purge_v1(RzList *list) {
RzListIter *it = list->head;
while (it) {
RzListIter *next = it->next;
rz_list_delete(list, it);
it = next;
}
list->length = 0;
list->head = list->tail = NULL;
}
static void bench_pop(RzTable *t_out) {
RZ_BENCH_RUN_I("[pop] 1k", i, t_out, 1000, {
RzList *l = rz_list_new();
_fill(l, 1000);
while (l->length) {
rz_list_pop(l);
/**
* v2: Direct free loop (new)
* Tight loop: calls free fn on val, then frees the iter node directly
*/
static void purge_v2(RzList *list) {
RzListIter *it = list->head;
RzListFree fn = list->free;
while (it) {
RzListIter *next = it->next;
if (fn && it->val) {
fn(it->val);
}
rz_list_free(l);
});
RZ_BENCH_RUN_I("[pop] 100k", i, t_out, 100, {
RzList *l = rz_list_new();
_fill(l, 100000);
while (l->length) {
rz_list_pop(l);
}
rz_list_free(l);
});
RZ_BENCH_RUN_I("[pop] 1m", i, t_out, 10, {
RzList *l = rz_list_new();
_fill(l, 1000000);
while (l->length) {
rz_list_pop(l);
}
rz_list_free(l);
});
free(it);
it = next;
}
list->length = 0;
list->head = list->tail = NULL;
}
static void bench_pop_head(RzTable *t_out) {
RZ_BENCH_RUN_I("[pop_head] 1k", i, t_out, 1000, {
RzList *l = rz_list_new();
_fill(l, 1000);
while (l->length) {
rz_list_pop_head(l);
/**
* v3: Hoisted free loop
*/
static void purge_v3(RzList *list) {
RzListIter *it = list->head;
RzListFree fn = list->free;
if (fn) {
while (it) {
RzListIter *next = it->next;
fn(it->val);
free(it);
it = next;
}
rz_list_free(l);
});
RZ_BENCH_RUN_I("[pop_head] 100k", i, t_out, 100, {
RzList *l = rz_list_new();
_fill(l, 100000);
while (l->length) {
rz_list_pop_head(l);
} else {
while (it) {
RzListIter *next = it->next;
free(it);
it = next;
}
rz_list_free(l);
});
RZ_BENCH_RUN_I("[pop_head] 1m", i, t_out, 10, {
RzList *l = rz_list_new();
_fill(l, 1000000);
while (l->length) {
rz_list_pop_head(l);
}
rz_list_free(l);
});
}
list->head = NULL;
list->tail = NULL;
list->length = 0;
}
static void bench_del_n(RzTable *t_out) {
RZ_BENCH_RUN_I("[del_n@0] 1k", i, t_out, 1000, {
RzList *l = rz_list_new();
_fill(l, 1000);
for (int j = 0; j < 1000; j++) {
rz_list_del_n(l, 0);
}
rz_list_free(l);
});
RZ_BENCH_RUN_I("[del_n@0] 100k", i, t_out, 10, {
RzList *l = rz_list_new();
_fill(l, 100000);
for (int j = 0; j < 100000; j++) {
rz_list_del_n(l, 0);
}
rz_list_free(l);
});
RZ_BENCH_RUN_I("[del_n@0] 1m", i, t_out, 1, {
RzList *l = rz_list_new();
_fill(l, 1000000);
for (int j = 0; j < 1000000; j++) {
rz_list_del_n(l, 0);
}
rz_list_free(l);
});
RZ_BENCH_RUN_I("[del_n@tail] 100k", i, t_out, 10, {
RzList *l = rz_list_new();
_fill(l, 100000);
while (l->length) {
rz_list_del_n(l, l->length - 1);
}
rz_list_free(l);
});
RZ_BENCH_RUN_I("[del_n@mid] 10k", i, t_out, 10, {
RzList *l = rz_list_new();
_fill(l, 10000);
while (l->length) {
rz_list_del_n(l, l->length / 2);
}
rz_list_free(l);
});
static void purge_v4_with_free_cb(RzList *list) {
RzListIter *it = list->head;
RzListFree fn = list->free;
while (it) {
RzListIter *next = it->next;
fn(it->val);
free(it);
it = next;
}
}
static void bench_purge(RzTable *t_out) {
RZ_BENCH_RUN_I("[purge] 10k", i, t_out, 1000, {
RzList *l = rz_list_new();
_fill(l, 10000);
rz_list_purge(l);
rz_list_free(l);
});
RZ_BENCH_RUN_I("[purge] 100k", i, t_out, 100, {
RzList *l = rz_list_new();
_fill(l, 100000);
rz_list_purge(l);
rz_list_free(l);
});
RZ_BENCH_RUN_I("[purge] 1m", i, t_out, 10, {
RzList *l = rz_list_new();
_fill(l, 1000000);
rz_list_purge(l);
rz_list_free(l);
});
static void purge_v4_no_free_cb(RzList *list) {
RzListIter *it = list->head;
while (it) {
RzListIter *next = it->next;
free(it);
it = next;
}
}
static void bench_mixed_append_pop(RzTable *t_out) {
RZ_BENCH_RUN_I("[mixed append+pop] 100k", i, t_out, 100, {
RzList *l = rz_list_new();
for (int j = 0; j < 100000; j++) {
rz_list_append(l, (void *)(intptr_t)j);
if (j % 2 == 0)
rz_list_pop(l);
}
rz_list_free(l);
});
RZ_BENCH_RUN_I("[mixed append+pop] 1m", i, t_out, 10, {
RzList *l = rz_list_new();
for (int j = 0; j < 1000000; j++) {
rz_list_append(l, (void *)(intptr_t)j);
if (j % 2 == 0)
rz_list_pop(l);
}
rz_list_free(l);
});
/**
* v4: Direct free loop with hoisted free fn check (split into helpers)
*/
static void purge_v4(RzList *list) {
if (list->free) {
purge_v4_with_free_cb(list);
} else {
purge_v4_no_free_cb(list);
}
list->head = NULL;
list->tail = NULL;
list->length = 0;
}
static void bench_mixed_purge_refill(RzTable *t_out) {
RZ_BENCH_RUN_I("[mixed purge+refill] 10k", i, t_out, 500, {
RzList *l = rz_list_new();
_fill(l, 10000);
rz_list_purge(l);
_fill(l, 10000);
rz_list_free(l);
});
RZ_BENCH_RUN_I("[mixed purge+refill] 100k", i, t_out, 50, {
RzList *l = rz_list_new();
_fill(l, 100000);
rz_list_purge(l);
_fill(l, 100000);
rz_list_free(l);
// --- No free function (pointer-only lists) ---
static void bench_purge_v1_small_no_free(RzTable *t_out) {
RzList *list = rz_list_new();
RZ_BENCH_RUN("purge_v1_1k_no_free", t_out, 1000, {
populate_list(list, 1000);
purge_v1(list);
});
rz_list_free(list);
}
int main(void) {
static void bench_purge_v2_small_no_free(RzTable *t_out) {
RzList *list = rz_list_new();
RZ_BENCH_RUN("purge_v2_1k_no_free", t_out, 1000, {
populate_list(list, 1000);
purge_v2(list);
});
rz_list_free(list);
}
static void bench_purge_v3_small_no_free(RzTable *t_out) {
RzList *list = rz_list_new();
RZ_BENCH_RUN("purge_v3_1k_no_free", t_out, 1000, {
populate_list(list, 1000);
purge_v3(list);
});
rz_list_free(list);
}
static void bench_purge_v4_small_no_free(RzTable *t_out) {
RzList *list = rz_list_new();
RZ_BENCH_RUN("purge_v4_1k_no_free", t_out, 1000, {
populate_list(list, 1000);
purge_v4(list);
});
rz_list_free(list);
}
static void bench_purge_v1_medium_no_free(RzTable *t_out) {
RzList *list = rz_list_new();
RZ_BENCH_RUN("purge_v1_100k_no_free", t_out, 100, {
populate_list(list, 100000);
purge_v1(list);
});
rz_list_free(list);
}
static void bench_purge_v2_medium_no_free(RzTable *t_out) {
RzList *list = rz_list_new();
RZ_BENCH_RUN("purge_v2_100k_no_free", t_out, 100, {
populate_list(list, 100000);
purge_v2(list);
});
rz_list_free(list);
}
static void bench_purge_v3_medium_no_free(RzTable *t_out) {
RzList *list = rz_list_new();
RZ_BENCH_RUN("purge_v3_100k_no_free", t_out, 100, {
populate_list(list, 100000);
purge_v3(list);
});
rz_list_free(list);
}
static void bench_purge_v4_medium_no_free(RzTable *t_out) {
RzList *list = rz_list_new();
RZ_BENCH_RUN("purge_v4_100k_no_free", t_out, 100, {
populate_list(list, 100000);
purge_v4(list);
});
rz_list_free(list);
}
static void bench_purge_v1_large_no_free(RzTable *t_out) {
RzList *list = rz_list_new();
RZ_BENCH_RUN("purge_v1_1m_no_free", t_out, 10, {
populate_list(list, 1000000);
purge_v1(list);
});
rz_list_free(list);
}
static void bench_purge_v2_large_no_free(RzTable *t_out) {
RzList *list = rz_list_new();
RZ_BENCH_RUN("purge_v2_1m_no_free", t_out, 10, {
populate_list(list, 1000000);
purge_v2(list);
});
rz_list_free(list);
}
static void bench_purge_v3_large_no_free(RzTable *t_out) {
RzList *list = rz_list_new();
RZ_BENCH_RUN("purge_v3_1m_no_free", t_out, 10, {
populate_list(list, 1000000);
purge_v3(list);
});
rz_list_free(list);
}
static void bench_purge_v4_large_no_free(RzTable *t_out) {
RzList *list = rz_list_new();
RZ_BENCH_RUN("purge_v4_1m_no_free", t_out, 10, {
populate_list(list, 1000000);
purge_v4(list);
});
rz_list_free(list);
}
static void bench_purge_v1_medium_with_free(RzTable *t_out) {
RzList *list = rz_list_newf(free);
RZ_BENCH_RUN("purge_v1_100k_with_free", t_out, 100, {
populate_list_alloc(list, 100000);
purge_v1(list);
});
rz_list_free(list);
}
static void bench_purge_v2_medium_with_free(RzTable *t_out) {
RzList *list = rz_list_newf(free);
RZ_BENCH_RUN("purge_v2_100k_with_free", t_out, 100, {
populate_list_alloc(list, 100000);
purge_v2(list);
});
rz_list_free(list);
}
static void bench_purge_v3_medium_with_free(RzTable *t_out) {
RzList *list = rz_list_newf(free);
RZ_BENCH_RUN("purge_v3_100k_with_free", t_out, 100, {
populate_list_alloc(list, 100000);
purge_v3(list);
});
rz_list_free(list);
}
static void bench_purge_v4_medium_with_free(RzTable *t_out) {
RzList *list = rz_list_newf(free);
RZ_BENCH_RUN("purge_v4_100k_with_free", t_out, 100, {
populate_list_alloc(list, 100000);
purge_v4(list);
});
rz_list_free(list);
}
static void bench_purge_v1_large_with_free(RzTable *t_out) {
RzList *list = rz_list_newf(free);
RZ_BENCH_RUN("purge_v1_1m_with_free", t_out, 10, {
populate_list_alloc(list, 1000000);
purge_v1(list);
});
rz_list_free(list);
}
static void bench_purge_v2_large_with_free(RzTable *t_out) {
RzList *list = rz_list_newf(free);
RZ_BENCH_RUN("purge_v2_1m_with_free", t_out, 10, {
populate_list_alloc(list, 1000000);
purge_v2(list);
});
rz_list_free(list);
}
static void bench_purge_v3_large_with_free(RzTable *t_out) {
RzList *list = rz_list_newf(free);
RZ_BENCH_RUN("purge_v3_1m_with_free", t_out, 10, {
populate_list_alloc(list, 1000000);
purge_v3(list);
});
rz_list_free(list);
}
static void bench_purge_v4_large_with_free(RzTable *t_out) {
RzList *list = rz_list_newf(free);
RZ_BENCH_RUN("purge_v4_1m_with_free", t_out, 10, {
populate_list_alloc(list, 1000000);
purge_v4(list);
});
rz_list_free(list);
}
// --- Empty list (base overhead) ---
static void bench_purge_v1_empty(RzTable *t_out) {
RzList *list = rz_list_new();
RZ_BENCH_RUN("purge_v1_empty", t_out, 10000, {
purge_v1(list);
});
rz_list_free(list);
}
static void bench_purge_v2_empty(RzTable *t_out) {
RzList *list = rz_list_new();
RZ_BENCH_RUN("purge_v2_empty", t_out, 10000, {
purge_v2(list);
});
rz_list_free(list);
}
static void bench_purge_v3_empty(RzTable *t_out) {
RzList *list = rz_list_new();
RZ_BENCH_RUN("purge_v3_empty", t_out, 10000, {
purge_v3(list);
});
rz_list_free(list);
}
static void bench_purge_v4_empty(RzTable *t_out) {
RzList *list = rz_list_new();
RZ_BENCH_RUN("purge_v4_empty", t_out, 10000, {
purge_v4(list);
});
rz_list_free(list);
}
int main() {
RzTable *t = rz_table_new();
RZ_BENCH_TABLE_INIT(t);
bench_append(t);
bench_prepend(t);
bench_pop(t);
bench_pop_head(t);
bench_del_n(t);
bench_purge(t);
bench_mixed_append_pop(t);
bench_mixed_purge_refill(t);
// Empty list - base overhead
bench_purge_v1_empty(t);
bench_purge_v2_empty(t);
bench_purge_v3_empty(t);
bench_purge_v4_empty(t);
// No free function - pointer-only lists
bench_purge_v1_small_no_free(t);
bench_purge_v2_small_no_free(t);
bench_purge_v3_small_no_free(t);
bench_purge_v4_small_no_free(t);
bench_purge_v1_medium_no_free(t);
bench_purge_v2_medium_no_free(t);
bench_purge_v3_medium_no_free(t);
bench_purge_v4_medium_no_free(t);
bench_purge_v1_large_no_free(t);
bench_purge_v2_large_no_free(t);
bench_purge_v3_large_no_free(t);
bench_purge_v4_large_no_free(t);
// With free function - heap-allocated elements
bench_purge_v1_medium_with_free(t);
bench_purge_v2_medium_with_free(t);
bench_purge_v3_medium_with_free(t);
bench_purge_v4_medium_with_free(t);
bench_purge_v1_large_with_free(t);
bench_purge_v2_large_with_free(t);
bench_purge_v3_large_with_free(t);
bench_purge_v4_large_with_free(t);
RZ_BENCH_TABLE_PRINT_AND_FREE(t);
return 0;
}
}

View file

@ -6,10 +6,6 @@
#include "minunit.h"
#define BUF_LENGTH 100
static void dummy_free(void *ptr) {
// This is just to trigger the code path
}
bool test_rz_list_size(void) {
// Test that rz_list adding and deleting works correctly.
int i;
@ -55,7 +51,7 @@ bool test_rz_list_join(void) {
rz_list_append(list2, (void *)test2);
int joined = rz_list_join(list1, list2);
mu_assert_eq(joined, 1, "rz_list_join of two lists");
mu_assert_eq(rz_list_length(list1), 2, "rz_list_join two single element lists result length is 2");
mu_assert_eq(rz_list_length(list1), 2, "rz_list_join two single element lists result length is 1");
rz_list_free(list1);
rz_list_free(list2);
mu_end;
@ -525,38 +521,6 @@ bool test_rz_list_sorted_uniq() {
mu_end;
}
bool test_rz_list_heavy_growth(void) {
RzList *list = rz_list_new();
const int count = 2000;
for (int i = 0; i < count; i++) {
mu_assert_notnull(rz_list_append(list, (void *)(intptr_t)i), "heavy append failed");
}
mu_assert_eq(rz_list_length(list), count, "length mismatch");
rz_list_free(list);
mu_end;
}
bool test_rz_list_insert_head(void) {
RzList *list = rz_list_new();
rz_list_append(list, (void *)0xAAA);
RzListIter *it = rz_list_insert(list, 0, (void *)0xBBB);
mu_assert_notnull(it, "insert failed");
mu_assert_ptreq(list->head, it, "list->head was not updated correctly");
mu_assert_ptreq(it->next->val, (void *)0xAAA, "original head not shifted");
rz_list_free(list);
mu_end;
}
bool test_rz_list_set_n_free(void) {
RzList *list = rz_list_newf(dummy_free);
rz_list_append(list, (void *)0x111);
rz_list_append(list, (void *)0x222);
mu_assert_eq(rz_list_set_n(list, 1, (void *)0x333), true, "set_n failed");
mu_assert_ptreq(rz_list_get_n(list, 1), (void *)0x333, "val not updated");
rz_list_free(list);
mu_end;
}
int all_tests() {
mu_run_test(test_rz_list_size);
mu_run_test(test_rz_list_values);
@ -577,9 +541,6 @@ int all_tests() {
mu_run_test(test_rz_list_find_val);
mu_run_test(test_rz_list_from_iter);
mu_run_test(test_rz_list_sorted_uniq);
mu_run_test(test_rz_list_heavy_growth);
mu_run_test(test_rz_list_insert_head);
mu_run_test(test_rz_list_set_n_free);
return tests_passed != tests_run;
}