From 56345064331b94b13b3f05e15a51b75fc85034c9 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Fri, 27 Jun 2025 21:43:57 +0100 Subject: [PATCH] object: add b_list object b_list behaves exactly like b_queue, with two key differences: 1) it is memory-managed like other b_objects, which means it is stored on the heap and ref-counted. 2) it is not an invasive data structure, and will automatically create and manage list nodes that contain pointers to the list items. --- object/include/blue/object/list.h | 67 ++++++ object/include/blue/object/type.h | 1 + object/list.c | 342 ++++++++++++++++++++++++++++++ object/list.h | 19 ++ 4 files changed, 429 insertions(+) create mode 100644 object/include/blue/object/list.h create mode 100644 object/list.c create mode 100644 object/list.h diff --git a/object/include/blue/object/list.h b/object/include/blue/object/list.h new file mode 100644 index 0000000..4872849 --- /dev/null +++ b/object/include/blue/object/list.h @@ -0,0 +1,67 @@ +#ifndef BLUE_OBJECT_LIST_H_ +#define BLUE_OBJECT_LIST_H_ + +#include +#include + +#define B_LIST(p) ((b_list *)(p)) + +typedef struct b_list b_list; +typedef struct b_list_entry b_list_entry; + +#define b_list_foreach(it, q) \ + for (int z__b_unique_name() = b_list_iterator_begin(q, it); \ + (it)->entry != NULL; b_list_iterator_next(it)) + +typedef struct b_list_iterator { + b_queue_iterator _base; + const b_list *_q; + size_t i; + void *item; + b_list_entry *entry; +} b_list_iterator; + +BLUE_API b_list *b_list_create(void); + +static inline b_list *b_list_retain(b_list *str) +{ + return B_LIST(b_retain(B_OBJECT(str))); +} +static inline void b_list_release(b_list *str) +{ + b_release(B_OBJECT(str)); +} + +BLUE_API bool b_list_empty(b_list *q); +BLUE_API void *b_list_first_item(const b_list *q); +BLUE_API void *b_list_last_item(const b_list *q); +BLUE_API b_list_entry *b_list_first_entry(const b_list *q); +BLUE_API b_list_entry *b_list_last_entry(const b_list *q); +BLUE_API b_list_entry *b_list_next(const b_list_entry *entry); +BLUE_API b_list_entry *b_list_prev(const b_list_entry *entry); + +BLUE_API size_t b_list_length(const b_list *q); + +BLUE_API b_list_entry *b_list_insert_before( + b_list *q, void *ptr, b_list_entry *before); +BLUE_API b_list_entry *b_list_insert_after( + b_list *q, void *ptr, b_list_entry *after); + +BLUE_API b_list_entry *b_list_push_front(b_list *q, void *ptr); +BLUE_API b_list_entry *b_list_push_back(b_list *q, void *ptr); + +BLUE_API void *b_list_pop_front(b_list *q); +BLUE_API void *b_list_pop_back(b_list *q); + +BLUE_API b_status b_list_delete_item(b_list *q, void *ptr); +BLUE_API b_status b_list_delete_entry(b_list *q, b_list_entry *entry); +BLUE_API void b_list_delete_all(b_list *q); + +BLUE_API int b_list_iterator_begin(const b_list *q, b_list_iterator *it); +BLUE_API bool b_list_iterator_next(b_list_iterator *it); +BLUE_API b_status b_list_iterator_erase(b_list_iterator *it); +BLUE_API bool b_list_iterator_is_valid(const b_list_iterator *it); + +BLUE_API void *b_list_entry_value(const b_list_entry *entry); + +#endif diff --git a/object/include/blue/object/type.h b/object/include/blue/object/type.h index 2062e4c..0b35340 100644 --- a/object/include/blue/object/type.h +++ b/object/include/blue/object/type.h @@ -17,6 +17,7 @@ typedef uintptr_t b_object_type_id; typedef enum b_fundamental_type_id { B_OBJECT_TYPE_NONE = 0, B_OBJECT_TYPE_ANY, + B_OBJECT_TYPE_LIST, B_OBJECT_TYPE_ARRAY, B_OBJECT_TYPE_BUFFER, B_OBJECT_TYPE_DICT, diff --git a/object/list.c b/object/list.c new file mode 100644 index 0000000..5b7beba --- /dev/null +++ b/object/list.c @@ -0,0 +1,342 @@ +#include "list.h" + +#include +#include +#include + +static void list_release(struct b_object *obj); + +static struct b_object_type list_type = { + .t_name = "corelib::list", + .t_flags = B_OBJECT_FUNDAMENTAL, + .t_id = B_OBJECT_TYPE_LIST, + .t_instance_size = sizeof(struct b_list), + .t_release = list_release, +}; + +struct b_list *b_list_create(void) +{ + struct b_list *list + = (struct b_list *)b_object_type_instantiate(&list_type); + if (!list) { + return NULL; + } + + return list; +} + +bool b_list_empty(struct b_list *q) +{ + return q->l_len == 0; +} + +void *b_list_first_item(const struct b_list *q) +{ + struct b_queue_entry *entry = b_queue_first(&q->l_queue); + + if (!entry) { + return NULL; + } + + struct b_list_entry *list_entry + = b_unbox(struct b_list_entry, entry, e_entry); + + return list_entry->e_data; +} + +void *b_list_last_item(const struct b_list *q) +{ + struct b_queue_entry *entry = b_queue_last(&q->l_queue); + + if (!entry) { + return NULL; + } + + struct b_list_entry *list_entry + = b_unbox(struct b_list_entry, entry, e_entry); + + return list_entry->e_data; +} + +struct b_list_entry *b_list_first_entry(const struct b_list *q) +{ + struct b_queue_entry *entry = b_queue_first(&q->l_queue); + + if (!entry) { + return NULL; + } + + struct b_list_entry *list_entry + = b_unbox(struct b_list_entry, entry, e_entry); + + return list_entry; +} + +struct b_list_entry *b_list_last_entry(const struct b_list *q) +{ + struct b_queue_entry *entry = b_queue_last(&q->l_queue); + + if (!entry) { + return NULL; + } + + struct b_list_entry *list_entry + = b_unbox(struct b_list_entry, entry, e_entry); + + return list_entry; +} + +struct b_list_entry *b_list_next(const struct b_list_entry *entry) +{ + if (!entry) { + return NULL; + } + + struct b_queue_entry *next = b_queue_next(&entry->e_entry); + + if (!next) { + return NULL; + } + + return b_unbox(struct b_list_entry, next, e_entry); +} + +struct b_list_entry *b_list_prev(const struct b_list_entry *entry) +{ + if (!entry) { + return NULL; + } + + struct b_queue_entry *next = b_queue_prev(&entry->e_entry); + + if (!next) { + return NULL; + } + + return b_unbox(struct b_list_entry, next, e_entry); +} + +size_t b_list_length(const struct b_list *q) +{ + return q->l_len; +} + +static struct b_list_entry *make_entry(void *item) +{ + struct b_list_entry *entry = malloc(sizeof *entry); + if (!entry) { + return NULL; + } + + memset(entry, 0x0, sizeof *entry); + + entry->e_data = item; + + return entry; +} + +struct b_list_entry *b_list_insert_before( + struct b_list *q, void *ptr, struct b_list_entry *before) +{ + struct b_list_entry *entry = make_entry(ptr); + if (!entry) { + return NULL; + } + + b_queue_insert_before(&q->l_queue, &entry->e_entry, &before->e_entry); + q->l_len++; + return entry; +} + +struct b_list_entry *b_list_insert_after( + struct b_list *q, void *ptr, struct b_list_entry *after) +{ + struct b_list_entry *entry = make_entry(ptr); + if (!entry) { + return NULL; + } + + b_queue_insert_after(&q->l_queue, &entry->e_entry, &after->e_entry); + q->l_len++; + return entry; +} + +struct b_list_entry *b_list_push_front(struct b_list *q, void *ptr) +{ + struct b_list_entry *entry = make_entry(ptr); + if (!entry) { + return NULL; + } + + b_queue_push_front(&q->l_queue, &entry->e_entry); + q->l_len++; + return entry; +} + +struct b_list_entry *b_list_push_back(struct b_list *q, void *ptr) +{ + struct b_list_entry *entry = make_entry(ptr); + if (!entry) { + return NULL; + } + + b_queue_push_back(&q->l_queue, &entry->e_entry); + q->l_len++; + return entry; +} + +void *b_list_pop_front(struct b_list *q) +{ + struct b_queue_entry *entry = b_queue_pop_front(&q->l_queue); + if (!entry) { + return NULL; + } + + struct b_list_entry *list_entry + = b_unbox(struct b_list_entry, entry, e_entry); + + void *item = list_entry->e_data; + free(list_entry); + + q->l_len--; + + return item; +} + +void *b_list_pop_back(struct b_list *q) +{ + struct b_queue_entry *entry = b_queue_pop_back(&q->l_queue); + if (!entry) { + return NULL; + } + + struct b_list_entry *list_entry + = b_unbox(struct b_list_entry, entry, e_entry); + + void *item = list_entry->e_data; + free(list_entry); + + q->l_len--; + + return item; +} + +static struct b_list_entry *find_item(struct b_list *list, void *item) +{ + struct b_queue_iterator it; + b_queue_foreach (&it, &list->l_queue) { + struct b_list_entry *entry + = b_unbox(struct b_list_entry, it.entry, e_entry); + + if (entry->e_data == item) { + return entry; + } + } + + return NULL; +} + +b_status b_list_delete_item(struct b_list *q, void *ptr) +{ + struct b_list_entry *entry = find_item(q, ptr); + if (!entry) { + return B_ERR_NO_ENTRY; + } + + b_queue_delete(&q->l_queue, &entry->e_entry); + q->l_len--; + + free(entry); + + return B_SUCCESS; +} + +b_status b_list_delete_entry(struct b_list *q, struct b_list_entry *entry) +{ + b_queue_delete(&q->l_queue, &entry->e_entry); + q->l_len--; + + free(entry); + + return B_SUCCESS; +} + +void b_list_delete_all(struct b_list *q) +{ + struct b_queue_iterator it; + b_queue_iterator_begin(&q->l_queue, &it); + + while (b_queue_iterator_is_valid(&it)) { + struct b_list_entry *entry + = b_unbox(struct b_list_entry, it.entry, e_entry); + b_queue_iterator_erase(&it); + + free(entry); + } + + q->l_len = 0; +} + +int b_list_iterator_begin(const struct b_list *q, struct b_list_iterator *it) +{ + b_queue_iterator_begin(&q->l_queue, &it->_base); + it->_q = q; + it->i = 0; + it->entry = b_unbox(struct b_list_entry, it->_base.entry, e_entry); + if (it->entry) { + it->item = it->entry->e_data; + } + + return 0; +} + +bool b_list_iterator_next(struct b_list_iterator *it) +{ + bool ok = b_queue_iterator_next(&it->_base); + if (!ok) { + it->entry = NULL; + it->item = NULL; + return false; + } + + it->i++; + it->entry = b_unbox(struct b_list_entry, it->_base.entry, e_entry); + if (it->entry) { + it->item = it->entry->e_data; + } + + return it->entry != NULL; +} + +b_status b_list_iterator_erase(struct b_list_iterator *it) +{ + if (!it->entry) { + return B_ERR_OUT_OF_BOUNDS; + } + + b_queue_iterator_erase(&it->_base); + free(it->entry); + + it->entry = b_unbox(struct b_list_entry, it->_base.entry, e_entry); + if (it->entry) { + it->item = it->entry->e_data; + } + + return B_SUCCESS; +} + +bool b_list_iterator_is_valid(const struct b_list_iterator *it) +{ + return it->entry != NULL; +} + +void *b_list_entry_value(const struct b_list_entry *entry) +{ + return entry ? entry->e_data : NULL; +} + +static void list_release(struct b_object *obj) +{ + struct b_list *list = B_LIST(obj); + b_list_delete_all(list); +} diff --git a/object/list.h b/object/list.h new file mode 100644 index 0000000..8a0f507 --- /dev/null +++ b/object/list.h @@ -0,0 +1,19 @@ +#ifndef _BLUELIB_LIST_H_ +#define _BLUELIB_LIST_H_ + +#include "object.h" + +#include + +struct b_list { + struct b_object l_base; + struct b_queue l_queue; + size_t l_len; +}; + +struct b_list_entry { + struct b_queue_entry e_entry; + void *e_data; +}; + +#endif