implemented doubly linked list

This commit is contained in:
Timerix 2025-11-24 23:41:58 +05:00
parent 3a7f09bb49
commit f2ce18b16d
7 changed files with 175 additions and 13 deletions

View File

@ -4,8 +4,6 @@
#include "Array.h" #include "Array.h"
#include "List.h" #include "List.h"
typedef void (*FreeFunction)(void*);
typedef struct HashMapKeyHash { typedef struct HashMapKeyHash {
str key; str key;
u32 hash; u32 hash;
@ -20,14 +18,14 @@ typedef struct HashMapBucket {
typedef struct HashMap_ { typedef struct HashMap_ {
NULLABLE(HashMapBucket*) table; NULLABLE(HashMapBucket*) table;
NULLABLE(FreeFunction) value_destructor; NULLABLE(Destructor_t) value_destructor;
u32 value_t_size; u32 value_t_size;
u32 height; u32 height;
u16 height_n; u16 height_n;
} HashMap_; } HashMap_;
#define HashMap_construct(SELF, T, VALUE_DESTRUCTOR) HashMap_construct_size(SELF, sizeof(T), VALUE_DESTRUCTOR) #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); void HashMap_destroy(HashMap_* self);
bool HashMap_tryPush(HashMap_* self, const str key, void* value_ptr); 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); bool HashMap_tryDelete(HashMap_* self, const str key);
typedef struct { typedef struct HashMapIter {
const HashMap_* map; const HashMap_* map;
i32 bucket_n; i32 bucket_n;
i32 elem_n; i32 elem_n;

View File

@ -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);

View File

@ -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)) #define List_alloc(T, INITIAL_COUNT) List_alloc_size((INITIAL_COUNT) * sizeof(T))
List_ List_alloc_size(u32 initial_size); List_ List_alloc_size(u32 initial_size);
static inline void List_destroy(List_ self){ static inline void List_destroy(List_* self){
free(self.data); if(!self)
return;
free(self->data);
} }
List_ List_copy(List_ src); List_ List_copy(List_ src);

View File

@ -84,9 +84,11 @@ typedef struct Result_ {
#define _rname(N) __r_##N #define _rname(N) __r_##N
#define try(VAR, RESULT_FIELD, RSLT_CALL) _try(VAR, RESULT_FIELD, RSLT_CALL, __LINE__) #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_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_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) \ #define _try(VAR, RESULT_FIELD, RSLT_CALL, N) \
Result_ _rname(N) = RSLT_CALL;\ Result_ _rname(N) = RSLT_CALL;\
@ -120,10 +122,20 @@ typedef struct Result_ {
};\ };\
} while(0) } while(0)
#define try_stderrcode(CALL) do {\ #define _try_stderrcode(CALL, N) do {\
int r = CALL;\ int _rname(N) = CALL;\
if(r != 0){\ if(_rname(N) != 0){\
Return RESULT_ERROR_CODE(LIBC_ERRNO, r, strerror_malloc(r), true);\ 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) } while(0)

View File

@ -31,6 +31,7 @@ typedef u8 bool;
#define false 0 #define false 0
#endif #endif
typedef void (*Destructor_t)(void* self);
#define FMT_i8 "%"PRIi8 #define FMT_i8 "%"PRIi8
#define FMT_i16 "%"PRIi16 #define FMT_i16 "%"PRIi16

View File

@ -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_t_size = value_t_size;
self->value_destructor = value_destructor; self->value_destructor = value_destructor;
self->height_n = 0; self->height_n = 0;

58
src/collections/LList.c Normal file
View File

@ -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;
}
}