initial commit

This commit is contained in:
pantonshire committed 2026-05-25 06:49:18 +01:00
commit bb3f9a0bc6
18 files changed
+1053

No files matched your search

+54
View File
@@ -0,0 +1,54 @@
#pragma once
#include <stdint.h>
#include "scoped.h"
#define ARRAY_LIST_EMPTY ((struct array_list) { NULL, 0, 0 })
struct array_list {
void *buf;
size_t len;
size_t cap;
};
int array_list_raw_alloc(struct array_list *al, size_t cap, size_t elem_size);
void array_list_raw_cleanup(struct array_list *al);
#define DEF_ARRAY_LIST_TYPE(NAME, TYPE, UNOCCUPIED, CLEANUP_FN) \
static inline TYPE *array_list_##NAME##_get(struct array_list *al, size_t i) { \
if (i >= al->len) \
return NULL; \
return &((TYPE *)al->buf)[i]; \
} \
static inline const TYPE *array_list_##NAME##_cget(const struct array_list *al, size_t i) { \
if (i >= al->len) \
return NULL; \
return &((const TYPE *)al->buf)[i]; \
} \
static inline void array_list_##NAME##_cleanup(struct array_list *al) { \
size_t i; \
for (i = 0; i < al->len; i++) \
CLEANUP_FN(array_list_##NAME##_get(al, i)); \
array_list_raw_cleanup(al); \
} \
static inline int array_list_##NAME##_alloc(struct array_list *al, size_t cap) { \
size_t i; \
if (cap < al->len) { \
for (i = cap; i < al->len; i++) \
CLEANUP_FN(array_list_##NAME##_get(al, i)); \
al->len = cap; \
} \
return array_list_raw_alloc(al, cap, sizeof(TYPE)); \
} \
static inline int array_list_##NAME##_push_noalloc_byval(struct array_list *al, TYPE elem) { \
if (al->len >= al->cap) \
return -1; \
((TYPE *)al->buf)[al->len++] = elem; \
return 0; \
} \
DEF_SCOPED_TYPE( \
array_list_##NAME, \
struct array_list, \
ARRAY_LIST_EMPTY, \
array_list_##NAME##_cleanup)
+10
View File
@@ -0,0 +1,10 @@
#pragma once
#include <stddef.h>
#include "typecheck.h"
#define TLSL_CONTAINER_OF(PTR, TYPE, MEMBER) ({ \
TLSL_TYPEOFS_EQ(((TYPE *)NULL)->MEMBER, *(PTR)); \
(TYPE *)((char *)(PTR) - offsetof(TYPE, MEMBER)); \
})
+51
View File
@@ -0,0 +1,51 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <time.h>
#include "list.h"
#include "scoped.h"
#define TLSL_EVENT_READABLE (1 << 0)
#define TLSL_EVENT_WRITABLE (1 << 1)
enum tlsl_event_source {
TLSL_EVENT_SOURCE_FD,
TLSL_EVENT_SOURCE_TIMER,
};
typedef struct {
uintptr_t obj;
enum tlsl_event_source source;
} tlsl_event_id_t;
struct tlsl_event {
tlsl_event_id_t id;
struct intrusive_list list;
char _platform[16] __attribute__((aligned));
};
struct tlsl_eventloop {
struct intrusive_list event_list;
bool valid;
char _platform[16] __attribute__((aligned));
};
static inline bool tlsl_event_id_eq(tlsl_event_id_t eid1, tlsl_event_id_t eid2) {
return (eid1.obj == eid2.obj) && (eid1.source == eid2.source);
}
int tlsl_eventloop_init(struct tlsl_eventloop *el);
void tlsl_eventloop_cleanup(struct tlsl_eventloop *el);
int tlsl_eventloop_wait(struct tlsl_eventloop *el, tlsl_event_id_t *id_out, uint32_t *flags_out, int timeout_ms);
int tlsl_eventloop_clear(struct tlsl_eventloop *el, struct tlsl_event *e);
void tlsl_eventloop_remove(struct tlsl_eventloop *el, struct tlsl_event *e);
int tlsl_eventloop_add_timer(struct tlsl_eventloop *el, struct tlsl_event *e, uint64_t millis, bool oneshot);
int tlsl_eventloop_add_fd(struct tlsl_eventloop *el, struct tlsl_event *e, int fd, uint32_t flags);
DEF_SCOPED_TYPE(eventloop_stack, struct tlsl_eventloop, (struct tlsl_eventloop) { .valid = false }, tlsl_eventloop_cleanup)
#define EVENTLOOP_STACK_SCOPED(VAL) SCOPED(eventloop_stack, struct tlsl_eventloop, VAL)
#define EVENTLOOP_STACK_CLOSE(EL) _scoped_eventloop_stack_cleanup(EL)
+21
View File
@@ -0,0 +1,21 @@
#pragma once
#include <unistd.h>
#include <sys/socket.h>
#include "scoped.h"
static inline void _tlsl_close_if_nonnegative(int *fd) {
if (*fd >= 0)
close(*fd);
}
DEF_SCOPED_TYPE(fd, int, -1, _tlsl_close_if_nonnegative)
#define FD_SCOPED(VAL) SCOPED(fd, int, VAL)
#define FD_CLOSE(FD) _tlsl_scoped_fd_cleanup(FD)
#define FD_RELEASE(FD) _tlsl_scoped_fd_release(FD)
static inline int setsockopt_int(int fd, int level, int option, int val) {
return setsockopt(fd, level, option, &val, sizeof(val));
}
+46
View File
@@ -0,0 +1,46 @@
#pragma once
#include "typecheck.h"
struct intrusive_list {
struct intrusive_list *next;
struct intrusive_list *prev;
};
static inline void intrusive_list_init_empty(struct intrusive_list *head) {
head->next = head;
head->prev = head;
}
static inline void intrusive_list_del(struct intrusive_list *node) {
struct intrusive_list old_node;
old_node = *node;
node->prev->next = old_node.next;
node->next->prev = old_node.prev;
}
static inline void intrusive_list_add(
struct intrusive_list *add_after,
struct intrusive_list *new_node)
{
new_node->prev = add_after;
new_node->next = add_after->next;
new_node->prev->next = new_node;
new_node->next->prev = new_node;
}
#define INTRUSIVE_LIST_FOR_EACH(ITER, NEXT, HEAD) \
for ( \
(void)TLSL_CHECK_TYPE(struct intrusive_list *, HEAD), \
(ITER) = (HEAD)->next, \
(NEXT) = (ITER)->next; \
(ITER) != (HEAD); \
(ITER) = (NEXT), (NEXT) = (ITER)->next)
#define INTRUSIVE_LIST_FOR_EACH_NO_REMOVE(ITER, HEAD) \
for ( \
(void)TLSL_CHECK_TYPE(struct intrusive_list *, HEAD), \
(ITER) = (HEAD)->next; \
(ITER) != (HEAD); \
(ITER) = (ITER)->next)
+16
View File
@@ -0,0 +1,16 @@
#pragma once
#include <stdlib.h>
#include "scoped.h"
#include "typecheck.h"
static inline void _tlsl_mem_free(void **p) {
free(*p);
}
DEF_SCOPED_TYPE(mem, void *, NULL, _tlsl_mem_free)
#define MEM_SCOPED(TYPE, VAL) SCOPED(mem, TYPE *, VAL)
#define MEM_FREE(TYPE, MEM) ({ TLSL_CHECK_TYPE(TYPE **, MEM), (TYPE *)_scoped_mem_cleanup((void **)(MEM)); })
#define MEM_RELEASE(TYPE, MEM) ({ TLSL_CHECK_TYPE(TYPE **, MEM), (TYPE *)_scoped_mem_release((void **)(MEM)); })
+22
View File
@@ -0,0 +1,22 @@
#pragma once
#define DEF_SCOPED_TYPE(NAME, TYPE, UNOCCUPIED, CLEANUP_FN) \
static inline TYPE _tlsl_scoped_##NAME##_unoccupied(void) { \
return (UNOCCUPIED); \
} \
static inline void _tlsl_scoped_##NAME##_cleanup(TYPE *_val) { \
CLEANUP_FN(_val); \
*_val = (UNOCCUPIED); \
} \
static inline void _tlsl_scoped_##NAME##_cleanup_raw(void *_val) { \
_tlsl_scoped_##NAME##_cleanup((TYPE *)_val); \
} \
static inline TYPE _tlsl_scoped_##NAME##_release(TYPE *_val) { \
TYPE _released = *_val; \
*_val = (UNOCCUPIED); \
return _released; \
}
#define SCOPED(NAME, TYPE, VAL) \
TYPE VAL __attribute__((cleanup(_tlsl_scoped_##NAME##_cleanup_raw))) \
= _tlsl_scoped_##NAME##_unoccupied()
+88
View File
@@ -0,0 +1,88 @@
#pragma once
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#define SVIEW_LIT(S) ((void)(S "LITERAL_CHECK"), (str_view_t) { S, sizeof(S) - 1 })
#define SVIEW_NULL ((str_view_t) { NULL, 0 })
#define SBUF_NULL ((str_buf_t) { NULL, 0 })
#define SBUF_SCOPED(NAME) str_buf_t NAME __attribute__((cleanup(sb_free))) = SB_NULL
#define SVIEW_PRI "%.*s"
#define SVIEW_PRI_ARGS(S) (int)((S).len), (S).ptr
// String which is:
// - Not owned
// - Not necessarily heap-allocated
// - Not necessarily nul-terminated
typedef struct {
const char *ptr;
size_t len;
} str_view_t;
// String which is:
// - Owned
// - Heap-allocated
// - Nul-terminated
// The length does not include the nul terminator.
typedef struct {
char *ptr;
size_t len;
} str_buf_t;
static inline bool sview_is_null(str_view_t s) {
return !s.ptr;
}
static inline bool sview_is_empty(str_view_t s) {
return !s.len;
}
static inline bool sbuf_is_null(str_buf_t buf) {
return !buf.ptr;
}
static inline bool sbuf_is_empty(str_buf_t buf) {
return !buf.len;
}
static inline str_view_t sview_from_parts(const char *ptr, size_t len) {
return (str_view_t) { ptr, len };
}
static inline str_view_t sview_from_cstr(const char *ptr, size_t maxlen) {
size_t len;
len = strnlen(ptr, maxlen);
return sview_from_parts(ptr, len);
}
static inline str_view_t sview_from_cstr_unbounded(const char *ptr) {
size_t len = strlen(ptr);
return sview_from_parts(ptr, len);
}
static inline bool sview_eq(str_view_t s1, str_view_t s2) {
return (s1.len == s2.len) && ((!s1.ptr || !s2.ptr)
? (s1.ptr == s2.ptr)
: !memcmp(s1.ptr, s2.ptr, s1.len));
}
static inline str_view_t sview_substr(str_view_t s, size_t start, size_t end) {
if ((start > end) || (start > s.len) || (end > s.len))
return SVIEW_NULL;
return sview_from_parts(s.ptr + start, end - start);
}
static inline str_view_t sbuf_view(str_buf_t buf) {
return sview_from_parts(buf.ptr, buf.len);
}
str_buf_t sbuf_from_sview(str_view_t s);
static inline void sbuf_free(str_buf_t *buf) {
free(buf->ptr);
buf->ptr = NULL;
buf->len = 0;
}
+17
View File
@@ -0,0 +1,17 @@
#pragma once
#define TLSL_TYPES_EQ(TYPE_LHS, TYPE_RHS) ({ \
_Static_assert(__builtin_types_compatible_p(TYPE_LHS, TYPE_RHS), \
"types mismatch"); \
1; \
})
#define TLSL_TYPEOFS_EQ(VAL_LHS, VAL_RHS) TLSL_TYPES_EQ(typeof(VAL_LHS), typeof(VAL_RHS))
#define TLSL_CHECK_TYPE(TYPE, VAL) TLSL_TYPES_EQ(TYPE, typeof(VAL))
#define TLSL_CHECK_ARRAY(VAL) ({ \
_Static_assert(!__builtin_types_compatible_p(typeof(VAL), typeof(&(VAL)[0])), \
"not an array"); \
1; \
})