From fd358f0fa669c81bf5d6a34233bd05923c21367f Mon Sep 17 00:00:00 2001 From: DualFroz Date: Tue, 1 Sep 2026 20:05:02 +0200 Subject: [PATCH] feat: add ListNode --- include/klib.h | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/list.h | 43 ++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 include/klib.h create mode 100644 include/list.h diff --git a/include/klib.h b/include/klib.h new file mode 100644 index 0000000..9deade1 --- /dev/null +++ b/include/klib.h @@ -0,0 +1,71 @@ +#ifndef FROSTBYTE_KLIB_H +#define FROSTBYTE_KLIB_H + +#include "types.h" +#include + +/* + * klib: freestanding string/number utilities that build on top of the + * primitive mem-family and str-family routines in string.h. No libc, no + * heap dependency (callers pass their own buffers), safe to use before the + * heap is set up. + */ + +/* ---- character classification -------------------------------------- */ + +bool isDigit(int c); +bool isAlpha(int c); +bool isAlnum(int c); +bool isSpace(int c); +bool isUpper(int c); +bool isLower(int c); +bool isHexDigit(int c); +int toUpper(int c); +int toLower(int c); + +/* ---- string manipulation -------------------------------------------- + Semantics match the C standard library equivalents (including the + footguns: strcpy/strcat assume a big-enough destination). */ + +char* strcpy(char* dest, const char* src); +char* strncpy(char* dest, const char* src, usize count); +char* strcat(char* dest, const char* src); +char* strncat(char* dest, const char* src, usize count); +char* strchr(const char* str, int c); +char* strrchr(const char* str, int c); +char* strstr(const char* haystack, const char* needle); +usize strspn(const char* str, const char* accept); +usize strcspn(const char* str, const char* reject); + +/* Reentrant tokenizer (no hidden static state, safe across threads). + Pass str on the first call, nullptr on subsequent calls; *savePtr + carries the position between calls (caller owns the storage). */ +char* strTokR(char* str, const char* delim, char** savePtr); + +/* ---- number parsing --------------------------------------------------- */ + +int32 atoi(const char* str); +int64 atol(const char* str); + +/* base 0 means auto-detect: "0x"/"0X" prefix -> 16, leading "0" -> 8, + otherwise 10. base must be 0 or in [2, 36] otherwise. If endPtr is + non-null, *endPtr is set to the first unconsumed character. */ +int64 strtol(const char* str, char** endPtr, int base); +uint64 strtoul(const char* str, char** endPtr, int base); + +/* ---- formatted output into a caller-owned buffer ---------------------- + Same contract as C99 snprintf: writes at most size-1 characters plus a + terminating nul (unless size == 0), and returns the number of characters + that *would* have been written given an unbounded buffer. Supports + %c %s %d %i %u %x %X %p %%, an 'l' length modifier for 64-bit args, and + a zero-padded/space-padded minimum field width. */ +int snprintf(char* buf, usize size, const char* format, ...); +int vsnprintf(char* buf, usize size, const char* format, va_list args); + +/* ---- generic sorting / searching -------------------------------------- + Same contract as C's qsort/bsearch: cmp returns <0, 0, >0. */ +void qsort(void* base, usize count, usize size, int (*cmp)(const void*, const void*)); +void* bsearch(const void* key, const void* base, usize count, usize size, + int (*cmp)(const void*, const void*)); + +#endif diff --git a/include/list.h b/include/list.h new file mode 100644 index 0000000..a01efb6 --- /dev/null +++ b/include/list.h @@ -0,0 +1,43 @@ +#ifndef FROSTBYTE_LIST_H +#define FROSTBYTE_LIST_H + +#include "types.h" +#include + +/* + * List: an intrusive circular doubly-linked list, Linux-kernel style. The + * list head and every node share the same ListNode type; a sentinel node + * (passed to listInit) acts as both head and tail so insert/remove never + * need a null check. Embed a ListNode in your own struct and use + * listEntry() to recover the containing struct pointer -- no allocation, + * no element copying, just pointer relinking. + */ + +typedef struct ListNode { + struct ListNode* next; + struct ListNode* prev; +} ListNode; + +#define listEntry(ptr, type, member) \ + ((type*)((uint8*)(ptr) - offsetof(type, member))) + +#define listForEach(cursor, head) \ + for ((cursor) = (head)->next; (cursor) != (head); (cursor) = (cursor)->next) + +void listInit(ListNode* head); +bool listEmpty(const ListNode* head); + +void listInsertAfter(ListNode* pos, ListNode* newNode); +void listInsertBefore(ListNode* pos, ListNode* newNode); +void listPushBack(ListNode* head, ListNode* newNode); +void listPushFront(ListNode* head, ListNode* newNode); + +/* Unlinks node from whatever list it is in. Safe to call again on an + already-removed node (it becomes its own trivial one-element list). */ +void listRemove(ListNode* node); + +usize listLen(const ListNode* head); +ListNode* listFront(const ListNode* head); +ListNode* listBack(const ListNode* head); + +#endif