From 9438280750b89f2e051d1017a3013c760f21278e Mon Sep 17 00:00:00 2001 From: yukkop Date: Fri, 21 Mar 2025 02:54:47 +0000 Subject: [PATCH] fix(libhectic): arena allocators --- package/c/hmpl/default.nix | 6 +- package/c/hmpl/hmpl.c | 24 ++++++- package/c/libhectic/default.nix | 5 +- package/c/libhectic/libhectic.c | 25 +------ package/c/libhectic/libhectic.h | 110 ++++++++++++------------------- package/c/libhectic/test/arena.c | 5 ++ package/c/libhectic/test/test.c | 2 +- 7 files changed, 78 insertions(+), 99 deletions(-) diff --git a/package/c/hmpl/default.nix b/package/c/hmpl/default.nix index 646f298..052ef8b 100644 --- a/package/c/hmpl/default.nix +++ b/package/c/hmpl/default.nix @@ -1,4 +1,4 @@ -{ stdenv, gcc, lib, libhectic }: +{ stdenv, gcc, lib, libhectic, cjson }: stdenv.mkDerivation { pname = "hmpl"; @@ -6,13 +6,13 @@ stdenv.mkDerivation { src = ./.; doCheck = true; - buildInputs = [ libhectic ]; + buildInputs = [ libhectic cjson ]; buildPhase = '' mkdir -p target ${gcc}/bin/cc -Wall -Wextra -g \ -pedantic -fsanitize=address hmpl.c \ - -l:libhectic.a -o target/hmpl + -l:libhectic.a -l:cjson -o target/hmpl ''; checkPhase = '' ''; diff --git a/package/c/hmpl/hmpl.c b/package/c/hmpl/hmpl.c index 33c0756..fb17c45 100644 --- a/package/c/hmpl/hmpl.c +++ b/package/c/hmpl/hmpl.c @@ -1,6 +1,7 @@ #include #include #include +#include //#include "libhmpl.h" #include "libhectic.h" @@ -80,8 +81,25 @@ void render_template(char *text, char *context) { render_template_placeholders(text, context, ""); } -int main(void) { - render_template(text, context); +int main(int argc, char *argv[]) { + char *text = NULL; + char *context = strdup(argc > 1 ? argv[1] : "{}"); - return 0; + if (argc > 2) { + text = strdup(argv[2]); + } else if (!isatty(fileno(stdin))) { + size_t size = 0; + ssize_t len = getdelim(&text, &size, '\0', stdin); + if (len < 0) { + perror("read stdin"); + free(context); + return 1; + } + } + + render_template(text, context); + + free(text); + free(context); + return 0; } diff --git a/package/c/libhectic/default.nix b/package/c/libhectic/default.nix index 39f825f..ba3cb31 100644 --- a/package/c/libhectic/default.nix +++ b/package/c/libhectic/default.nix @@ -8,7 +8,10 @@ stdenv.mkDerivation { buildPhase = '' mkdir -p target - ${gcc}/bin/cc -Wall -Wextra -g -pedantic -fsanitize=address -c libhectic.c -o target/libhectic.o + ${gcc}/bin/cc -Wall -Wextra -g \ + -std=c99 \ + -pedantic -fsanitize=address \ + -c libhectic.c -o target/libhectic.o ${gcc}/bin/ar rcs target/libhectic.a target/libhectic.o ''; diff --git a/package/c/libhectic/libhectic.c b/package/c/libhectic/libhectic.c index a9948d3..62c029e 100644 --- a/package/c/libhectic/libhectic.c +++ b/package/c/libhectic/libhectic.c @@ -52,7 +52,7 @@ void init_logger(void) { current_log_level = log_level_from_string(getenv("LOG_LEVEL")); } -char* log_message(LogLevel level, int line, const char *format, ...) { +char* log_message(LogLevel level, char *file, int line, const char *format, ...) { if (level < current_log_level) { return NULL; } @@ -63,7 +63,7 @@ char* log_message(LogLevel level, int line, const char *format, ...) { static char timeStr[20]; strftime(timeStr, sizeof(timeStr), "%Y-%m-%d %H:%M:%S", &tm_info); - fprintf(stderr, "%s %d %s: ", timeStr, line, log_level_to_string(level)); + fprintf(stderr, "%s %s %s:%d ", timeStr, log_level_to_string(level), file, line); va_list args; va_start(args, format); @@ -89,18 +89,6 @@ Arena arena_init(size_t size) { return arena; } -void *arena_alloc_or_null(Arena *arena, size_t size) { - if (arena->begin == 0) { - *arena = arena_init(ARENA_DEFAULT_SIZE); - } - size_t current = (size_t)arena->current - (size_t)arena->begin; - // TODO(yukkop): maybe -1 - if (arena->capacity <= current && current < size) { - return NULL; - } - return arena; -} - void arena_reset(Arena *arena) { arena->current = arena->begin; } @@ -108,12 +96,3 @@ void arena_reset(Arena *arena) { void arena_free(Arena *arena) { free(arena->begin); } - -void *arena_alloc(Arena *arena, size_t size) { - void *mem = arena_alloc_or_null(arena, size); - if (!mem) { - raise_exception("Arena out of memory"); - exit(1); - } - return mem; -} diff --git a/package/c/libhectic/libhectic.h b/package/c/libhectic/libhectic.h index f6dd2e3..d661397 100644 --- a/package/c/libhectic/libhectic.h +++ b/package/c/libhectic/libhectic.h @@ -14,13 +14,7 @@ // Helper macros for argument counting // NOTE(yukkop): this ugly macroses for avoid all posible warnings -#define PP_CAT(a, b) PP_CAT_I(a, b) -#define PP_CAT_I(a, b) a##b - -#define PP_NARG(...) PP_NARG_(__VA_ARGS__, PP_RSEQ_N()) -#define PP_NARG_(...) PP_ARG_N(__VA_ARGS__) -#define PP_ARG_N(_1,_2,_3,_4,_5,_6,_7,_8,_9,N,...) N -#define PP_RSEQ_N() 9,8,7,6,5,4,3,2,1,0 +#define PP_CAT(a, b) a##b // ------------ // -- Colors -- @@ -51,20 +45,13 @@ void set_output_color_mode(ColorMode mode); // ------------ // Define color macros based on output type -//#define ERROR_PREFIX PP_CAT_I(COLOR_RED, "Error: ") -//#define ERROR_SUFFIX PP_CAT_I(COLOR_RESET, "\n") +//#define ERROR_PREFIX PP_CAT(COLOR_RED, "Error: ") +//#define ERROR_SUFFIX PP_CAT(COLOR_RESET, "\n") #define ERROR_PREFIX (USE_COLOR() ? "\033[1;31mError: " : "Error: ") #define ERROR_SUFFIX (USE_COLOR() ? "\033[0m\n" : "\n") // eprintf handling 1 or more arguments -#define eprintf_1(fmt) \ - fprintf(stderr, "%s" fmt "%s", ERROR_PREFIX, ERROR_SUFFIX) - -#define eprintf_2(fmt, ...) \ - fprintf(stderr, "%s" fmt "%s", ERROR_PREFIX, __VA_ARGS__, ERROR_SUFFIX) - -#define eprintf(...) \ - PP_CAT(eprintf_, PP_NARG(__VA_ARGS__))(__VA_ARGS__) +#define eprintf(fmt, ...) "%s" fmt "%s", ERROR_PREFIX, ##__VA_ARGS__, ERROR_SUFFIX #define todo fprintf(stderr, "%sNot implimented yet%s", COLOR_RED, COLOR_RESET);exit(1) @@ -87,55 +74,14 @@ void logger_level(LogLevel level); LogLevel log_level_from_string(const char *level_str); -char* log_message(LogLevel level, int line, const char *format, ...); +char* log_message(LogLevel level, char *file, int line, const char *format, ...); -// DEBUG level -#define raise_debug_1(fmt) \ - log_message(LOG_LEVEL_DEBUG, __LINE__, fmt) -#define raise_debug_2(fmt, ...) \ - log_message(LOG_LEVEL_DEBUG, __LINE__, fmt, __VA_ARGS__) -#define raise_debug(...) \ - PP_CAT(raise_debug_, PP_NARG(__VA_ARGS__))(__VA_ARGS__) - -// LOG level -#define raise_log_1(fmt) \ - log_message(LOG_LEVEL_LOG, __LINE__, fmt) -#define raise_log_2(fmt, ...) \ - log_message(LOG_LEVEL_LOG, __LINE__, fmt, __VA_ARGS__) -#define raise_log(...) \ - PP_CAT(raise_log_, PP_NARG(__VA_ARGS__))(__VA_ARGS__) - -// INFO level -#define raise_info_1(fmt) \ - log_message(LOG_LEVEL_INFO, __LINE__, fmt) -#define raise_info_2(fmt, ...) \ - log_message(LOG_LEVEL_INFO, __LINE__, fmt, __VA_ARGS__) -#define raise_info(...) \ - PP_CAT(raise_info_, PP_NARG(__VA_ARGS__))(__VA_ARGS__) - -// NOTICE level -#define raise_notice_1(fmt) \ - log_message(LOG_LEVEL_NOTICE, __LINE__, fmt) -#define raise_notice_2(fmt, ...) \ - log_message(LOG_LEVEL_NOTICE, __LINE__, fmt, __VA_ARGS__) -#define raise_notice(...) \ - PP_CAT(raise_notice_, PP_NARG(__VA_ARGS__))(__VA_ARGS__) - -// WARN level -#define raise_warn_1(fmt) \ - log_message(LOG_LEVEL_WARN, __LINE__, fmt) -#define raise_warn_2(fmt, ...) \ - log_message(LOG_LEVEL_WARN, __LINE__, fmt, __VA_ARGS__) -#define raise_warn(...) \ - PP_CAT(raise_warn_, PP_NARG(__VA_ARGS__))(__VA_ARGS__) - -// EXCEPTION level -#define raise_exception_1(fmt) \ - log_message(LOG_LEVEL_EXCEPTION, __LINE__, fmt) -#define raise_exception_2(fmt, ...) \ - log_message(LOG_LEVEL_EXCEPTION, __LINE__, fmt, __VA_ARGS__) -#define raise_exception(...) \ - PP_CAT(raise_exception_, PP_NARG(__VA_ARGS__))(__VA_ARGS__) +#define raise_debug(fmt, ...) log_message(LOG_LEVEL_DEBUG, __FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define raise_log(fmt, ...) log_message(LOG_LEVEL_LOG, __FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define raise_info(fmt, ...) log_message(LOG_LEVEL_INFO, __FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define raise_notice(fmt, ...) log_message(LOG_LEVEL_NOTICE, __FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define raise_warn(fmt, ...) log_message(LOG_LEVEL_WARN, __FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define raise_exception(fmt, ...) log_message(LOG_LEVEL_EXCEPTION, __FILE__, __LINE__, fmt, ##__VA_ARGS__) #endif // EPRINTF_H @@ -151,15 +97,43 @@ typedef struct { size_t capacity; } Arena; -Arena arena_init(size_t size); +// NOTE(yukkop): This macro is used to define procedures so that `__LINE__` and `__FILE__` +// in `raise_debug` reflect the location where the macro is called, not where it's defined. +#define arena_alloc_or_null(arena, size) __extension__ ({ \ + void *mem__ = NULL; \ + if ((arena)->begin == 0) { \ + *(arena) = arena_init(ARENA_DEFAULT_SIZE); \ + } \ + size_t current__ = (size_t)(arena)->current - (size_t)(arena)->begin; \ + if ((arena)->capacity <= current__ || (arena)->capacity - current__ < (size)) {\ + raise_debug("Arena from %d with capacity %d allocated on %d cannot be allocated on %d", \ + (arena)->begin, (arena)->capacity, \ + (arena)->current - (arena)->begin, (size)); \ + } else { \ + raise_debug("Arena from %d with capacity %d allocated on %d will allocate on %d", \ + (arena)->begin, (arena)->capacity, \ + (arena)->begin, (arena)->capacity, (size)); \ + mem__ = (arena)->current; \ + (arena)->current = (char*)(arena)->current + (size); \ + } \ + mem__; \ +}) -void *arena_alloc_or_null(Arena *arena, size_t size); +Arena arena_init(size_t size); void arena_reset(Arena *arena); void arena_free(Arena *arena); -void *arena_alloc(Arena *arena, size_t size); +#define arena_alloc(arena, size) __extension__ ({ \ + void *mem__ = arena_alloc_or_null((arena), (size)); \ + if (!mem__) { \ + raise_exception("Arena out of memory"); \ + exit(1); \ + } \ + mem__; \ +}) + // TODO: mmap // TODO: dynamic array style diff --git a/package/c/libhectic/test/arena.c b/package/c/libhectic/test/arena.c index e302270..dd41cbd 100644 --- a/package/c/libhectic/test/arena.c +++ b/package/c/libhectic/test/arena.c @@ -18,6 +18,7 @@ void test_arena_alloc() { assert(ptr1 != NULL); void *ptr2 = arena_alloc(&arena, 16); assert(ptr2 != NULL); + raise_debug("%d - %d = %d", (size_t)ptr2, (size_t)ptr1, (char *)ptr2 - (char *)ptr1); assert((char *)ptr2 - (char *)ptr1 == 16); arena_free(&arena); } @@ -25,6 +26,7 @@ void test_arena_alloc() { void test_arena_alloc_or_null_out_of_memory() { Arena arena = arena_init(32); void *ptr = arena_alloc_or_null(&arena, 64); + raise_debug("%d %d %d %d", arena.begin, arena.current, arena.capacity, (size_t)ptr); assert(ptr == NULL); arena_free(&arena); } @@ -46,6 +48,9 @@ void test_arena_null_init() { } int main() { + set_output_color_mode(COLOR_MODE_DISABLE); + logger_level(LOG_LEVEL_DEBUG); \ + test_arena_init(); test_arena_alloc(); test_arena_alloc_or_null_out_of_memory(); diff --git a/package/c/libhectic/test/test.c b/package/c/libhectic/test/test.c index aac2aa1..c0d1e7b 100644 --- a/package/c/libhectic/test/test.c +++ b/package/c/libhectic/test/test.c @@ -20,7 +20,7 @@ stderr = orig_stderr; \ fclose(temp); \ char expected_buffer[256]; \ - sprintf(expected_buffer, "%s %d " LEVEL_STR ": message\n", time_str, __LINE__); \ + sprintf(expected_buffer, "%s " LEVEL_STR " " __FILE__ ":%d message\n", time_str, __LINE__); \ printf("DEBUG: [%s] [%s]\n", result_buffer, expected_buffer); \ assert(strcmp(result_buffer, expected_buffer) == 0); \ } while(0)