From f2ce18b16d3f1adf4cc4b378d9131d27d3becff0 Mon Sep 17 00:00:00 2001 From: Timerix Date: Mon, 24 Nov 2025 23:41:58 +0500 Subject: [PATCH] implemented doubly linked list --- include/tlibc/collections/HashMap.h | 8 +-- include/tlibc/collections/LList.h | 91 +++++++++++++++++++++++++++++ include/tlibc/collections/List.h | 6 +- include/tlibc/errors.h | 22 +++++-- include/tlibc/std.h | 1 + src/collections/HashMap.c | 2 +- src/collections/LList.c | 58 ++++++++++++++++++ 7 files changed, 175 insertions(+), 13 deletions(-) create mode 100644 include/tlibc/collections/LList.h create mode 100644 src/collections/LList.c diff --git a/include/tlibc/collections/HashMap.h b/include/tlibc/collections/HashMap.h index 660cb98..6e2d5c8 100755 --- a/include/tlibc/collections/HashMap.h +++ b/include/tlibc/collections/HashMap.h @@ -4,8 +4,6 @@ #include "Array.h" #include "List.h" -typedef void (*FreeFunction)(void*); - typedef struct HashMapKeyHash { str key; u32 hash; @@ -20,14 +18,14 @@ typedef struct HashMapBucket { typedef struct HashMap_ { NULLABLE(HashMapBucket*) table; - NULLABLE(FreeFunction) value_destructor; + NULLABLE(Destructor_t) value_destructor; u32 value_t_size; u32 height; u16 height_n; } HashMap_; #define HashMap_construct(SELF, T, VALUE_DESTRUCTOR) HashMap_construct_size(SELF, sizeof(T), VALUE_DESTRUCTOR) -void HashMap_construct_size(HashMap_* self, u32 value_t_size, FreeFunction NULLABLE(value_destructor)); +void HashMap_construct_size(HashMap_* self, u32 value_t_size, Destructor_t NULLABLE(value_destructor)); void HashMap_destroy(HashMap_* self); bool HashMap_tryPush(HashMap_* self, const str key, void* value_ptr); @@ -36,7 +34,7 @@ NULLABLE(void*) HashMap_tryGetPtr(const HashMap_* self, const str key); bool HashMap_tryDelete(HashMap_* self, const str key); -typedef struct { +typedef struct HashMapIter { const HashMap_* map; i32 bucket_n; i32 elem_n; diff --git a/include/tlibc/collections/LList.h b/include/tlibc/collections/LList.h new file mode 100644 index 0000000..8757e62 --- /dev/null +++ b/include/tlibc/collections/LList.h @@ -0,0 +1,91 @@ +#pragma once +#include "../std.h" + +/* +Doubly linked list +*/ + +#define LLNode(T) LLNode_##T +#define LList(T) LList_##T + +#define LList_declare(T) \ +typedef struct LLNode(T) LLNode(T);\ +typedef struct LLNode(T) { \ + LLNode(T)* prev; \ + LLNode(T)* next; \ + T value; \ +} LLNode(T); \ + \ +static inline LLNode(T)* LLNode_##T##_createZero(){ \ + LLNode(T)* n = (LLNode(T)*)malloc(sizeof(LLNode(T))); \ + n->prev = NULL; \ + n->next = NULL; \ + memset(&n->value, 0, sizeof(T)); \ + return n; \ +} \ + \ +typedef struct LList(T) { \ + LLNode(T)* first; \ + LLNode(T)* last; \ + u32 count; \ + NULLABLE(void (*value_destructor)(T*)); \ +} LList(T); \ + \ +/* Peek node from list. Detatched nodes can be inserted in different place. */ \ +static inline LLNode(T)* LList_##T##_detatch(LList(T)* l, LLNode(T)* n) \ +{ return _LList_detatch((void*)l, (void*)n); } \ + \ +/* @param detatched must have null .next and .prev */ \ +/* @param target can be null only if it is l->first or l->last */ \ +static inline void LList_##T##_insertAfter( \ + LList(T)* l, LLNode(T)* target, LLNode(T)* detatched) \ +{ _LList_insertAfter((void*)l, (void*)target, (void*)detatched); } \ + \ +/* @param detatched must have null .next and .prev */ \ +/* @param target can be null only if it is l->first or l->last */ \ +static inline void LList_##T##_insertBefore( \ + LList(T)* l, LLNode(T)* target, LLNode(T)* detatched) \ +{ _LList_insertBefore((void*)l, (void*)target, (void*)detatched); } \ + \ +static inline void LList_##T##_destroy(LList(T)* l){ \ + if(!l) \ + return; \ + LLNode(T)* n = l->first; \ + while(n){ \ + if(l->value_destructor) \ + l->value_destructor(&n->value); \ + LLNode(T)* next = n->next; \ + free(n); \ + n = next; \ + } \ +} \ + +#define LList_construct(T, VALUE_DESTRUCTOR) ((LList(T)){ \ + .first = NULL, .last = NULL, .count = 0, .value_destructor = VALUE_DESTRUCTOR }) + + + +typedef struct LLNode_ LLNode_; +typedef struct LLNode_ { + LLNode_* prev; + LLNode_* next; + /* value of unknown type */ +} LLNode_; + +typedef struct LList_ { + LLNode_* first; + LLNode_* last; + u32 count; + NULLABLE(Destructor_t) value_destructor; +} LList_; + +/* Peek node from list. Detatched nodes can be inserted in different place. */ +LLNode_* _LList_detatch(LList_* l, LLNode_* n); + +/* @param detatched must have null .next and .prev */ +/* @param target can be null only if it is l->first or l->last */ +void _LList_insertAfter(LList_* l, NULLABLE(LLNode_*) target, LLNode_* detatched); + +/* @param detatched must have null .next and .prev */ +/* @param target can be null only if it is l->first or l->last */ +void _LList_insertBefore(LList_* l, NULLABLE(LLNode_*) target, LLNode_* detatched); diff --git a/include/tlibc/collections/List.h b/include/tlibc/collections/List.h index 5308a0f..f7f76f8 100755 --- a/include/tlibc/collections/List.h +++ b/include/tlibc/collections/List.h @@ -20,8 +20,10 @@ static inline List_ List_construct_size(void* data_ptr, u32 occupied_size, u32 a #define List_alloc(T, INITIAL_COUNT) List_alloc_size((INITIAL_COUNT) * sizeof(T)) List_ List_alloc_size(u32 initial_size); -static inline void List_destroy(List_ self){ - free(self.data); +static inline void List_destroy(List_* self){ + if(!self) + return; + free(self->data); } List_ List_copy(List_ src); diff --git a/include/tlibc/errors.h b/include/tlibc/errors.h index ce7ec31..8cb498c 100755 --- a/include/tlibc/errors.h +++ b/include/tlibc/errors.h @@ -84,9 +84,11 @@ typedef struct Result_ { #define _rname(N) __r_##N #define try(VAR, RESULT_FIELD, RSLT_CALL) _try(VAR, RESULT_FIELD, RSLT_CALL, __LINE__) -#define try_void(RSLT_CALL) _try_void(RSLT_CALL, __LINE__) #define try_fatal(VAR, RESULT_FIELD, RSLT_CALL) _try_fatal(VAR, RESULT_FIELD, RSLT_CALL, __LINE__) +#define try_void(RSLT_CALL) _try_void(RSLT_CALL, __LINE__) #define try_fatal_void(RSLT_CALL) _try_fatal_void(RSLT_CALL, __LINE__) +#define try_stderrcode(RSLT_CALL) _try_stderrcode(RSLT_CALL, __LINE__) +#define try_fatal_stderrcode(RSLT_CALL) _try_fatal_stderrcode(RSLT_CALL, __LINE__) #define _try(VAR, RESULT_FIELD, RSLT_CALL, N) \ Result_ _rname(N) = RSLT_CALL;\ @@ -120,10 +122,20 @@ typedef struct Result_ { };\ } while(0) -#define try_stderrcode(CALL) do {\ - int r = CALL;\ - if(r != 0){\ - Return RESULT_ERROR_CODE(LIBC_ERRNO, r, strerror_malloc(r), true);\ +#define _try_stderrcode(CALL, N) do {\ + int _rname(N) = CALL;\ + if(_rname(N) != 0){\ + Return RESULT_ERROR_CODE(LIBC_ERRNO, _rname(N), strerror_malloc(_rname(N)), true);\ + }\ +} while(0) + +#define _try_fatal_stderrcode(CALL, N) do {\ + int _rname(N) = CALL;\ + if(_rname(N) != 0){\ + Error_printAndExit(Error_create(\ + strerror_malloc(_rname(N)), true, ErrorCallPos_here(), \ + ErrorCodePage_name(LIBC_ERRNO), _rname(N)\ + ));\ }\ } while(0) diff --git a/include/tlibc/std.h b/include/tlibc/std.h index 36e0e05..5e64753 100755 --- a/include/tlibc/std.h +++ b/include/tlibc/std.h @@ -31,6 +31,7 @@ typedef u8 bool; #define false 0 #endif +typedef void (*Destructor_t)(void* self); #define FMT_i8 "%"PRIi8 #define FMT_i16 "%"PRIi16 diff --git a/src/collections/HashMap.c b/src/collections/HashMap.c index e962b0b..b82e44d 100755 --- a/src/collections/HashMap.c +++ b/src/collections/HashMap.c @@ -13,7 +13,7 @@ static const Array(u32) __HashMap_heights = ARRAY(u32, { }); -void HashMap_construct_size(HashMap_* self, u32 value_t_size, FreeFunction NULLABLE(value_destructor)){ +void HashMap_construct_size(HashMap_* self, u32 value_t_size, Destructor_t NULLABLE(value_destructor)){ self->value_t_size = value_t_size; self->value_destructor = value_destructor; self->height_n = 0; diff --git a/src/collections/LList.c b/src/collections/LList.c new file mode 100644 index 0000000..cd9d65c --- /dev/null +++ b/src/collections/LList.c @@ -0,0 +1,58 @@ +#include "tlibc/collections/LList.h" + +LLNode_* _LList_detatch(LList_* l, LLNode_* n){ + if(n == l->first){ + l->first = n->next; + } + else { + assert(n->prev != NULL); + n->prev->next = n->next; + } + + if(n == l->last){ + l->last = n->prev; + } + else { + assert(n->next != NULL); + n->next->prev = n->prev; + } + + l->count--; + n->prev = NULL; + n->next = NULL; + return n; +} + +void _LList_insertAfter(LList_* l, NULLABLE(LLNode_*) target, LLNode_* detatched) +{ + if(target == NULL){ + assert(l->first == NULL && l->last == NULL); + l->first = detatched; + l->last = detatched; + return; + } + + detatched->prev = target; + detatched->next = target->next; + target->next = detatched; + if(detatched->next){ + detatched->next->prev = detatched; + } +} + +void _LList_insertBefore(LList_* l, NULLABLE(LLNode_*) target, LLNode_* detatched) +{ + if(target == NULL){ + assert(l->first == NULL && l->last == NULL); + l->first = detatched; + l->last = detatched; + return; + } + + detatched->prev = target->prev; + detatched->next = target; + target->prev = detatched; + if(detatched->prev){ + detatched->prev->next = detatched; + } +} \ No newline at end of file