initial commit
This commit is contained in:
commit
bb3f9a0bc6
18 files changed
+1053
No files matched your search
@@ -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)
|
||||
@@ -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)); \
|
||||
})
|
||||
@@ -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)
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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)); })
|
||||
@@ -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()
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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; \
|
||||
})
|
||||
Reference in new issue
Block a user