]> www.git.momoyon.org Git - commonlib.git/commitdiff
Implement c_da_remove()...
authormomoyon <momoyon@momoyon.org>
Fri, 30 May 2025 03:43:15 +0000 (08:43 +0500)
committermomoyon <momoyon@momoyon.org>
Fri, 30 May 2025 03:43:50 +0000 (08:43 +0500)
- [tests/dynamic_array.c] Update test.

commonlib.h
tests/.dynamic_array.out.expected
tests/dynamic_array.c

index c11e0afac09157b6f022b955cbc8850c2ce9f65a..0a5e01ae3f6a17a6443832960269f2828fe53f5d 100644 (file)
-#ifndef _COMMONLIB_H_\r
-#define _COMMONLIB_H_\r
-#include <stdio.h>\r
-#include <stdbool.h>\r
-#include <stdarg.h>\r
-#include <stdint.h>\r
-#include <stdlib.h>\r
-#include <string.h>\r
-#include <ctype.h>\r
-#include <assert.h>\r
-#include <limits.h>\r
-\r
-#if defined(_WIN32) && defined(_MSC_VER)\r
-// NOTE: Don't include unwanted files to speed up compilation\r
-#define WIN32_LEAN_AND_MEAN\r
-#define NOCOMM\r
-#include <windows.h>\r
-#undef C_ASSERT // Bruh\r
-#endif\r
-\r
-// Remove Prefix\r
-#ifdef COMMONLIB_REMOVE_PREFIX\r
-#define ASSERT C_ASSERT\r
-#define ARRAY_LEN C_ARRAY_LEN\r
-\r
-#define da_append c_da_append\r
-#define da_free c_da_free\r
-#define da_shift c_da_shift\r
-#define DYNAMIC_ARRAY_INITIAL_CAPACITY c_DYNAMIC_ARRAY_INITIAL_CAPACITY\r
-// #define c_DYNAMIC_ARRAY_INITIAL_CAPACITY\r
-\r
-#define os_get_timedate c_os_get_timedate\r
-#define os_file_exists c_os_file_exists\r
-\r
-#define log_error c_log_error\r
-#define log_info c_log_info\r
-#define log_warning c_log_warning\r
-#define log_debug c_log_debug\r
-\r
-#define read_file c_read_file\r
-#define touch_file_if_doesnt_exist c_touch_file_if_doesnt_exist\r
-\r
-#define Arena c_Arena\r
-#define arena_make c_arena_make\r
-#define arena_alloc c_arena_alloc\r
-#define arena_reset c_arena_reset\r
-#define arena_free c_arena_free\r
-#define arena_alloc_str c_arena_alloc_str\r
-#define arena_alloc_wstr c_arena_alloc_wstr\r
-\r
-#define String_view c_String_view\r
-\r
-#define shift_args c_shift_args\r
-\r
-#define SV_FMT c_SV_FMT\r
-#define SV_ARG c_SV_ARG\r
-\r
-#define SV c_SV\r
-\r
-#define sv_print_dumb c_sv_print_dumb\r
-#define sv_from_cstr c_sv_from_cstr\r
-#define sv_lpop c_sv_lpop\r
-#define sv_lpop_until_predicate c_sv_lpop_until_predicate\r
-#define sv_lpop_until_string c_sv_lpop_until_string\r
-#define sv_rpop_until_predicate c_sv_rpop_until_predicate\r
-#define sv_lpop_until_char c_sv_lpop_until_char\r
-#define sv_rpop_until_char c_sv_rpop_until_char\r
-#define sv_lremove c_sv_lremove\r
-#define sv_rremove c_sv_rremove\r
-#define sv_lremove_until_char c_sv_lremove_until_char\r
-#define sv_rremove_until_char c_sv_rremove_until_char\r
-#define sv_lremove_until_char_after c_sv_lremove_until_char_after\r
-#define sv_rremove_until_char_after c_sv_rremove_until_char_after\r
-#define sv_ltrim c_sv_ltrim\r
-#define sv_rtrim c_sv_rtrim\r
-#define sv_trim c_sv_trim\r
-#define sv_to_cstr c_sv_to_cstr\r
-#define sv_to_int c_sv_to_int\r
-#define sv_to_uint c_sv_to_uint\r
-#define sv_to_uint8_hex c_sv_to_uint8_hex\r
-#define sv_to_float c_sv_to_float\r
-#define sv_contains_char c_sv_contains_char\r
-#define sv_is_hex_numbers c_sv_is_hex_numbers\r
-#define sv_equals c_sv_equals\r
-#define sv_get_part c_sv_get_part\r
-\r
-\r
-#endif // COMMONLIB_REMOVE_PREFIX\r
-\r
-// Memory allocation\r
-#ifndef C_MALLOC\r
-#define C_MALLOC malloc\r
-#endif\r
-#ifndef C_FREE\r
-#define C_FREE free\r
-#endif\r
-#ifndef C_REALLOC\r
-#define C_REALLOC realloc\r
-#endif\r
-#ifndef C_MEMCPY\r
-#define C_MEMCPY memcpy\r
-#endif\r
-\r
-\r
-// typedefs\r
-typedef unsigned int uint;\r
-typedef uint8_t      uint8;\r
-typedef uint16_t     uint16;\r
-typedef uint32_t     uint32;\r
-typedef uint64_t     uint64;\r
-\r
-typedef int8_t  int8;\r
-typedef int16_t int16;\r
-typedef int32_t int32;\r
-typedef int64_t int64;\r
-\r
-typedef float  float32;\r
-typedef double float64;\r
-\r
-typedef wchar_t wchar;\r
-\r
-typedef const char*  cstr;\r
-typedef const wchar* wstr;\r
-\r
-\r
-// Macros\r
-#if defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER)\r
-#define C_ASSERT(condition, msg) do {\\r
-                if (!(condition)) {\\r
-                        fprintf(stderr, "%s:%d:0 [ASSERTION FAILED] %s: %s", __FILE__, __LINE__, #condition, msg);\\r
-                        DebugBreak();\\r
-                }\\r
-        } while (0)\r
-#else\r
-#define C_ASSERT(condition, msg) do {\\r
-                if (!(condition)) {\\r
-                        fprintf(stderr, "%s:%d:0 [ASSERTION FAILED] %s: %s", __FILE__, __LINE__, #condition, msg);\\r
-                        exit(1);\\r
-                }\\r
-        } while (0)\r
-#endif // defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER)\r
-\r
-#define C_ARRAY_LEN(arr) (sizeof(arr) / sizeof(arr[0]))\r
-\r
-#define c_shift(xs, xsz) (assert(xsz > 0 && "Array is empty"), xsz--, *xs++)\r
-#define c_shift_args c_shift\r
-\r
-//\r
-// Math\r
-//\r
-\r
-int clampi(int v, int min, int max);\r
-float clampf(float v, float min, float max);\r
-\r
-//\r
-// Struct pre-decls\r
-//\r
-\r
-typedef struct c_Arena c_Arena;\r
-\r
-//\r
-// ## Data Structures\r
-//\r
-\r
-//\r
-// Dynamic-Array\r
-//\r
-\r
-// NOTE: To use c_da_append() the Dynamic-Array struct should be defined using\r
-// DEFINE_DYNAMIC_ARRAY or have the same members as below!\r
-// NOTE!!!: We actually don't want this since this makes the user want to\r
-// use this macro to define dynamic arrays. But the user might want extra fields\r
-// in the struct; So we recommend defining da structs manually like:\r
-// ```C\r
-// typedef struct {\r
-//    <item-type> items;\r
-//    size_t count;\r
-//    size_t capacity;\r
-//    [extra fields...];\r
-// }\r
-// ```\r
-// #define DEFINE_DYNAMIC_ARRAY(struct_name, elm_type) typedef struct {\r
-//         elm_type *items;\r
-//         size_t count;\r
-//         size_t capacity;\r
-//     }\r
-\r
-#define c_DYNAMIC_ARRAY_INITIAL_CAPACITY (sizeof(size_t))\r
-\r
-#define c_da_append(da, elm) do {\\r
-               if ((da).items == NULL) {\\r
-                       (da).capacity = c_DYNAMIC_ARRAY_INITIAL_CAPACITY;\\r
-                       (da).count = 0;\\r
-                       (da).items = C_MALLOC(sizeof(elm) * (da).capacity);\\r
-               }\\r
-               if ((da).count >= (da).capacity) {\\r
-                       (da).capacity *= 2;\\r
-                        (da).items = C_REALLOC((da).items, (da).capacity * sizeof(elm));\\r
-                       C_ASSERT((da).items != NULL, "TODO: Log error instead of asserting");\\r
-               }\\r
-               (da).items[(da).count++] = elm;\\r
-       } while (0)\r
-\r
-// NOTE: We cant do C_ASSERT() here because it aint one expression...\r
-#define c_da_shift(da) (assert((da).count > 0 && "Array is empty"), (da).count--, *(da).items++)\r
-#define c_da_free(da) C_FREE((da).items)\r
-\r
-//\r
-// OS\r
-//\r
-\r
-#if defined(__linux__)\r
-#include <sys/stat.h>\r
-#endif\r
-\r
-void c_os_get_timedate(c_Arena* a);\r
-bool c_os_file_exists(cstr filename);\r
-\r
-//\r
-// Logging\r
-//\r
-\r
-#define c_log_error(fmt, ...) do {\\r
-               fprintf(stderr, "%s"fmt"\n", "[ERROR] ", ##__VA_ARGS__);\\r
-       } while (0)\r
-#define c_log_info(fmt, ...) do {\\r
-               fprintf(stdout, "%s"fmt"\n", "[INFO] ", ##__VA_ARGS__);\\r
-       } while (0)\r
-#define c_log_warning(fmt, ...) do {\\r
-               fprintf(stdout, "%s"fmt"\n", "[WARNING] ", ##__VA_ARGS__);\\r
-       } while (0)\r
-#ifdef DEBUG\r
-#define c_log_debug(fmt, ...) do {\\r
-               fprintf(stdout, "%s"fmt"\n", "[DEBUG] ", ##__VA_ARGS__);\\r
-       } while (0)\r
-#else\r
-#define c_log_debug(...)\r
-#endif // DEBUG\r
-//\r
-// File\r
-//\r
-\r
-// reads entire file and gives back the file content and filesize in bytes. (caller must be responsible for freeing the string!)\r
-const char* c_read_file(const char* filename, int *file_size);\r
-void c_touch_file_if_doesnt_exist(cstr file);\r
-\r
-//\r
-// ### Allocators ###\r
-//\r
-\r
-//\r
-// c_Arena\r
-//\r
-\r
-#define ARENA_BUFF_INITIAL_SIZE (1024*4)\r
-\r
-struct c_Arena {\r
-    void* buff;\r
-    uint64 buff_size;\r
-    void* ptr;\r
-};\r
-\r
-// pass size 0 to get ARENA_BUFF_INITIAL_SIZE\r
-c_Arena c_arena_make(size_t size);\r
-void* c_arena_alloc(c_Arena* a, size_t size);\r
-void c_arena_reset(c_Arena* a);\r
-void c_arena_free(c_Arena* a);\r
-\r
-// TODO: Do we embed stb_snprintf to use stbsp_snprintf?\r
-#define c_arena_alloc_str(a, fmt, ...)    c_arena_alloc(&(a), sizeof(char)*snprintf((a).ptr, (int)((a).buff_size - ((uint8*)(a).ptr - (uint8*)(a).buff)), (fmt), __VA_ARGS__)+1)\r
-#define c_arena_alloc_wstr(a, fmt, ...) c_arena_alloc(&a, sizeof(char)*wprintf(a.ptr, a.buff_size - ((uint8*)a.ptr - (uint8*)a.buff), (fmt), __VA_ARGS__)+1)\r
-\r
-//\r
-// String Builder\r
-//\r
-\r
-typedef struct {\r
-    char* data;\r
-    size_t size;\r
-    size_t capacity;\r
-} c_String_builder;\r
-\r
-void c_sb_append(c_String_builder* sb, char* data);\r
-\r
-//\r
-// String view\r
-//\r
-\r
-typedef struct {\r
-    char *data;\r
-    size_t count;\r
-} c_String_view;\r
-\r
-#define c_SV_FMT "%.*s"\r
-#define c_SV_ARG(sv) (int)(sv).count, (sv).data\r
-\r
-#define c_SV(cstr) (c_String_view){.data = (char*)cstr, strlen(cstr)}\r
-\r
-void c_sv_print_dumb(c_String_view sv);\r
-c_String_view c_sv_from_cstr(const char* cstr); // Actually just use SV(cstr) macro...\r
-c_String_view c_sv_lpop(c_String_view* sv, uint32 n);\r
-c_String_view c_sv_lpop_until_predicate(c_String_view* sv, int(*predicate)(int));\r
-c_String_view c_sv_lpop_until_string(c_String_view* sv, const char *string);\r
-c_String_view c_sv_rpop_until_predicate(c_String_view* sv, int(*predicate)(int));\r
-c_String_view c_sv_lpop_until_char(c_String_view* sv, char ch);\r
-c_String_view c_sv_rpop_until_char(c_String_view* sv, char ch);\r
-void c_sv_lremove(c_String_view* sv, size_t n);\r
-void c_sv_rremove(c_String_view* sv, size_t n);\r
-void c_sv_lremove_until_char(c_String_view* sv, char ch);\r
-void c_sv_rremove_until_char(c_String_view* sv, char ch);\r
-void c_sv_lremove_until_char_after(c_String_view* sv, char ch);\r
-void c_sv_rremove_until_char_after(c_String_view* sv, char ch);\r
-void c_sv_ltrim(c_String_view* sv);\r
-void c_sv_rtrim(c_String_view* sv);\r
-void c_sv_trim(c_String_view* sv);\r
-char* c_sv_to_cstr(c_String_view sv);\r
-int64 c_sv_to_int(c_String_view sv, int *count, int base);\r
-uint64 c_sv_to_uint(c_String_view sv, int *count, int base);\r
-float64 c_sv_to_float(c_String_view sv, int *count);\r
-bool c_sv_contains_char(c_String_view sv, char ch);\r
-bool c_sv_is_hex_numbers(c_String_view sv);\r
-bool c_sv_equals(c_String_view sv1, c_String_view sv2);\r
-c_String_view c_sv_get_part(c_String_view sv, int from, int to);\r
-\r
-#endif /* _COMMONLIB_H_ */\r
-\r
-//////////////////////////////////////////////////\r
-#ifdef COMMONLIB_IMPLEMENTATION\r
-#include <string.h>\r
-#include <errno.h>\r
-#include <stdlib.h>\r
-#include <assert.h>\r
-\r
-// My things implementation:\r
-\r
-//\r
-// Math\r
-//\r
-\r
-int clampi(int v, int min, int max) {\r
-    v = v < min ? min : v;\r
-    v = v > max ? max : v;\r
-    return v;\r
-}\r
-\r
-float clampf(float v, float min, float max) {\r
-    v = v < min ? min : v;\r
-    v = v > max ? max : v;\r
-    return v;\r
-}\r
-\r
-//\r
-// OS\r
-//\r
-\r
-#if defined(_WIN32) || defined(__CYGWIN__)\r
-void c_os_get_timedate(c_Arena* a) {\r
-        (void)a;\r
-        C_ASSERT(false, "Unimplemented!");\r
-}\r
-\r
-bool c_os_file_exists(cstr filename) {\r
-        (void) filename;\r
-        C_ASSERT(false, "Unimplemented!");\r
-        return false;\r
-}\r
-\r
-#elif defined(__linux__)\r
-void c_os_get_timedate(c_Arena* a) {\r
-        (void)a;\r
-        C_ASSERT(false, "Unimplemented!");\r
-}\r
-\r
-bool c_os_file_exists(cstr filename) {\r
-        struct stat buf;\r
-        return stat(filename, &buf) == 0;\r
-}\r
-#endif\r
-\r
-// simple and dirty way to have defering in C (not recommended to use!)\r
-#define defer(ret_val) \\r
-    result = ret_val;\\r
-    goto defer\r
-\r
-const char *c_read_file(const char* filename, int *file_size) {\r
-    FILE* f = fopen(filename, "r");\r
-    char* result = NULL;\r
-\r
-    if (f == NULL){\r
-        // TODO: Replace every strerror with strerror_s\r
-        c_log_error("'%s': %s", filename, strerror(errno));\r
-        defer(NULL);\r
-    }\r
-\r
-    if (fseek(f, 0, SEEK_END) < 0) {\r
-        c_log_error("'%s': %s", filename, strerror(errno));\r
-        defer(NULL);\r
-    }\r
-\r
-    size_t fsize = ftell(f);\r
-\r
-    if (fsize == (size_t)-1){\r
-        c_log_error("'%s': %s", filename, strerror(errno));\r
-        defer(NULL);\r
-    }\r
-\r
-    result = C_MALLOC(sizeof(char)*(fsize+1));\r
-\r
-    if (result == NULL){\r
-        c_log_error("'%s': %s", filename, strerror(errno));\r
-        defer(NULL);\r
-    }\r
-\r
-    if (fseek(f, 0, SEEK_SET) < 0) {\r
-        c_log_error("'%s': %s", filename, strerror(errno));\r
-        defer(NULL);\r
-    }\r
-\r
-    size_t read = fread((char*)result, sizeof(char), fsize, f);\r
-\r
-    // Process the result to remove '\r' characters\r
-    char* cleaned_result = malloc(read + 1); // Allocate memory for cleaned result\r
-    if (cleaned_result == NULL) {\r
-        fprintf(stderr, "Memory allocation failed\n");\r
-        free(result);\r
-        return NULL;\r
-    }\r
-\r
-    size_t j = 0; // Index for cleaned_result\r
-    for (size_t i = 0; i < read; i++) {\r
-        if (result[i] != '\r') { // Skip '\r' characters\r
-            cleaned_result[j++] = result[i];\r
-        }\r
-    }\r
-    cleaned_result[j] = '\0'; // Null-terminate the cleaned result\r
-\r
-    free(result); // Free the original result\r
-    *file_size = (int)j; // Update the file size without '\r'\r
-    return cleaned_result; // Return the cleaned result\r
-\r
-    *file_size = (int)read;\r
-\r
- defer:\r
-    if (f) fclose(f);\r
-    if (result == NULL) *file_size = -1;\r
-    return result;\r
-}\r
-\r
-void c_touch_file_if_doesnt_exist(cstr filename) {\r
-        if (c_os_file_exists(filename)) return;\r
-        FILE* file = fopen(filename, "w");\r
-        if (file) fclose(file);\r
-}\r
-\r
-//\r
-// ### Allocators ###\r
-//\r
-\r
-// c_Arena\r
-\r
-c_Arena c_arena_make(size_t size) {\r
-    c_Arena res = {0};\r
-    res.buff_size = size == 0 ? ARENA_BUFF_INITIAL_SIZE : size;\r
-    res.buff = C_MALLOC(res.buff_size);\r
-    res.ptr = res.buff;\r
-\r
-    C_ASSERT(res.buff, "Malloc failed?");\r
-\r
-    return res;\r
-}\r
-\r
-void* c_arena_alloc(c_Arena* a, size_t size) {\r
-    C_ASSERT(a->buff, "Bro pass an initialized arena!");\r
-\r
-    void* res = a->ptr;\r
-    a->ptr = (uint8*)a->ptr + size;\r
-\r
-    size_t diff = (size_t)((uint8*)a->ptr - (uint8*)a->buff);\r
-    if (diff > a->buff_size) {\r
-        c_log_info("c_Arena resized from %zu to %zu", a->buff_size, a->buff_size*2);\r
-        a->buff_size *= 2;\r
-        a->buff = C_REALLOC(a->buff, a->buff_size);\r
-        a->ptr = (uint8*)a->buff + diff;\r
-        res = a->ptr;\r
-        a->ptr = (uint8*)a->ptr + size;\r
-    }\r
-    /* C_ASSERT((size_t)((uint8*)a->ptr - (uint8*)a->buff) <= a->buff_size); */\r
-\r
-    return res;\r
-}\r
-\r
-void c_arena_reset(c_Arena* a) {\r
-    a->ptr = a->buff;\r
-}\r
-\r
-void c_arena_free(c_Arena* a) {\r
-    C_FREE(a->buff);\r
-}\r
-\r
-//\r
-// String Builder\r
-//\r
-\r
-void c_sb_append(c_String_builder* sb, char* data) {\r
-    size_t data_size = strlen(data);\r
-    if (sb->size + data_size > sb->capacity) {\r
-        sb->capacity *= 2;\r
-        sb->data = C_REALLOC(sb->data, sb->capacity);\r
-    }\r
-\r
-    // void *memcpy(void dest[restrict .n], const void src[restrict .n],\r
-    C_MEMCPY((void *)((uintptr_t)sb->data + (uintptr_t)sb->data), data, data_size);\r
-    sb->size += data_size;\r
-}\r
-\r
-//\r
-// String view\r
-//\r
-\r
-void c_sv_print_dumb(c_String_view sv){\r
-    for (size_t i = 0; i < (size_t)sv.count; ++i){\r
-        putc(*(sv.data+i), stdout);\r
-    }\r
-}\r
-\r
-c_String_view c_sv_from_cstr(const char* cstr){\r
-    return (c_String_view){\r
-        .data = (char *)cstr,\r
-        .count = strlen(cstr),\r
-    };\r
-}\r
-\r
-c_String_view c_sv_lpop(c_String_view* sv, uint32 n) {\r
-    c_String_view res = {0};\r
-    if (sv->count < n) return res;\r
-    res.data = sv->data;\r
-    res.count = n;\r
-\r
-    sv->data += n;\r
-    sv->count -= n;\r
-\r
-    return res;\r
-}\r
-\r
-c_String_view c_sv_lpop_until_predicate(c_String_view* sv, int(*predicate)(int)){\r
-    const char* old_sv_data = sv->data;\r
-    while (sv->count > 0 && !predicate(*sv->data)){\r
-        sv->data++;\r
-        sv->count--;\r
-    }\r
-\r
-    return (c_String_view){\r
-        .data = sv->data - (sv->data - old_sv_data),\r
-        .count = (sv->data - old_sv_data),\r
-    };\r
-}\r
-\r
-c_String_view c_sv_lpop_until_string(c_String_view* sv, const char *string) {\r
-    size_t string_len = strlen(string);\r
-\r
-    char *old_sv_data = sv->data;\r
-\r
-    while (sv->count > string_len) {\r
-        bool matched = true;\r
-        for (size_t i = 0; i < string_len; ++i) {\r
-            if (sv->data[i] != string[i]) matched = false;\r
-        }\r
-        if (matched) break;\r
-        sv->data++;\r
-        sv->count--;\r
-    }\r
-\r
-    return (c_String_view) {\r
-        .data = old_sv_data,\r
-        .count = (sv->data - old_sv_data),\r
-    };\r
-}\r
-\r
-c_String_view c_sv_rpop_until_predicate(c_String_view* sv, int(*predicate)(int)){\r
-    size_t old_sv_count = sv->count;\r
-    while (sv->count > 0 && !predicate(*(sv->data+sv->count-1))){\r
-        sv->count--;\r
-    }\r
-\r
-    return (c_String_view){\r
-        .data = sv->data + sv->count,\r
-        .count = old_sv_count - sv->count,\r
-    };\r
-}\r
-\r
-c_String_view c_sv_lpop_until_char(c_String_view* sv, char ch){\r
-    const char* old_sv_data = sv->data;\r
-    while (sv->count > 0 && *sv->data != ch){\r
-        sv->data++;\r
-        sv->count--;\r
-    }\r
-\r
-    return (c_String_view){\r
-        .data = sv->data - (sv->data - old_sv_data),\r
-        .count = (sv->data - old_sv_data),\r
-    };\r
-}\r
-\r
-c_String_view c_sv_rpop_until_char(c_String_view* sv, char ch){\r
-    size_t old_sv_count = sv->count;\r
-    while (sv->count > 0 && *(sv->data+sv->count-1) != ch){\r
-        sv->count--;\r
-    }\r
-\r
-    return (c_String_view){\r
-        .data = sv->data + sv->count,\r
-        .count = old_sv_count - sv->count,\r
-    };\r
-}\r
-\r
-void c_sv_lremove(c_String_view* sv, size_t n){\r
-    if (n > sv->count) n = sv->count;\r
-\r
-    sv->data += n;\r
-    sv->count -= n;\r
-}\r
-\r
-void c_sv_rremove(c_String_view* sv, size_t n){\r
-    if (n > sv->count)\r
-        sv->count = 0;\r
-    else\r
-        sv->count -= n;\r
-}\r
-\r
-void c_sv_lremove_until_char(c_String_view* sv, char ch){\r
-    while (sv->count > 0 && *sv->data != ch){\r
-        sv->data++;\r
-        sv->count--;\r
-    }\r
-}\r
-\r
-void c_sv_rremove_until_char(c_String_view* sv, char ch){\r
-    while (sv->count > 0 && *(sv->data+sv->count-1) != ch){\r
-        sv->count--;\r
-    }\r
-}\r
-\r
-void c_sv_lremove_until_char_after(c_String_view* sv, char ch){\r
-    while (sv->count > 0 && *(sv->data-1) != ch){\r
-        sv->data++;\r
-        sv->count--;\r
-    }\r
-}\r
-\r
-void c_sv_rremove_until_char_after(c_String_view* sv, char ch){\r
-    while (sv->count > 0 && *(sv->data+sv->count) != ch){\r
-        sv->count--;\r
-    }\r
-}\r
-\r
-void c_sv_ltrim(c_String_view* sv){\r
-    while (sv->count > 0 && isspace(*sv->data)){\r
-        sv->data++;\r
-        sv->count--;\r
-    }\r
-}\r
-\r
-void c_sv_rtrim(c_String_view* sv){\r
-    while (sv->count > 0 && isspace(*(sv->data+sv->count-1))){\r
-        sv->count--;\r
-    }\r
-}\r
-\r
-void c_sv_trim(c_String_view* sv){\r
-    c_sv_ltrim(sv);\r
-    c_sv_rtrim(sv);\r
-}\r
-\r
-char* c_sv_to_cstr(c_String_view sv){\r
-    char* res = (char*)malloc(sizeof(char)*(sv.count + 1));\r
-    if (res == NULL) {\r
-        C_ASSERT(false, "Buy more RAM bruh");\r
-    }\r
-    C_MEMCPY(res, sv.data, sv.count);\r
-    res[sv.count] = '\0';\r
-    return res;\r
-}\r
-\r
-int64 c_sv_to_int(c_String_view sv, int *count_out, int base) {\r
-    char *str = c_sv_to_cstr(sv);\r
-\r
-    char *endptr = NULL;\r
-\r
-    int64 res = strtol(str, &endptr, base);\r
-\r
-    if (endptr == str) {\r
-        *count_out = -1;\r
-        return res;\r
-    }\r
-\r
-    *count_out = (int)(endptr - str);\r
-\r
-    C_FREE(str);\r
-    return res;\r
-}\r
-\r
-uint64 c_sv_to_uint(c_String_view sv, int *count, int base) {\r
-    char* str = c_sv_to_cstr(sv);\r
-\r
-    char *endptr = NULL;\r
-    uint64 res = strtoul(str, &endptr, base);\r
-\r
-    if (endptr == str) {\r
-        *count = -1;\r
-        return res;\r
-    }\r
-\r
-    *count = (int)(endptr - str);\r
-\r
-    C_FREE(str);\r
-    return res;\r
-}\r
-\r
-float64 c_sv_to_float(c_String_view sv, int *count) {\r
-    char* str = c_sv_to_cstr(sv);\r
-\r
-    char *endptr = NULL;\r
-    float64 res = strtod(str, &endptr);\r
-\r
-    if (endptr == str) {\r
-        *count = -1;\r
-        return res;\r
-    }\r
-\r
-    *count = (int)(endptr - str);\r
-\r
-    C_FREE(str);\r
-    return res;\r
-}\r
-\r
-bool c_sv_contains_char(c_String_view sv, char ch){\r
-    for (size_t i = 0; i < sv.count; ++i){\r
-        if (sv.data[i] == ch) return true;\r
-    }\r
-    return false;\r
-}\r
-\r
-bool c_sv_is_hex_numbers(c_String_view sv) {\r
-    char hex[] = {\r
-        '0', '1', '2', '3', '4', '5', '6', '7',\r
-        '8', '9', '0', 'a', 'b', 'c', 'd', 'e', 'f',\r
-        'A', 'B', 'C', 'D', 'E', 'F'\r
-    };\r
-    bool found = false;\r
-    for (size_t i = 0; i < sv.count; ++i) {\r
-        char c = sv.data[i];\r
-        for (size_t j = 0; j < C_ARRAY_LEN(hex); ++j) {\r
-            if (hex[j] == c) {\r
-       found = true;\r
-            }\r
-        }\r
-    }\r
-\r
-    return found;\r
-}\r
-\r
-bool c_sv_equals(c_String_view sv1, c_String_view sv2) {\r
-    if (sv1.count != sv2.count) return false;\r
-    for (size_t i = 0; i < sv1.count; ++i) {\r
-        if (sv1.data[i] != sv2.data[i]) {\r
-            return false;\r
-        }\r
-    }\r
-\r
-    return true;\r
-}\r
-\r
-c_String_view c_sv_get_part(c_String_view sv, int from, int to) {\r
-    from = clampi(from, 0, sv.count);\r
-    to   = clampi(to, from, sv.count);\r
-\r
-    c_String_view range = {\r
-        .data = (char*)(sv.data + from),\r
-        .count = (size_t)(to - from),\r
-    };\r
-\r
-    return range;\r
-}\r
-#endif\r
+#ifndef _COMMONLIB_H_
+#define _COMMONLIB_H_
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <limits.h>
+
+#if defined(_WIN32) && defined(_MSC_VER)
+// NOTE: Don't include unwanted files to speed up compilation
+#define WIN32_LEAN_AND_MEAN
+#define NOCOMM
+#include <windows.h>
+#undef C_ASSERT // Bruh
+#endif
+
+// Remove Prefix
+#ifdef COMMONLIB_REMOVE_PREFIX
+#define ASSERT C_ASSERT
+#define ARRAY_LEN C_ARRAY_LEN
+
+#define da_append c_da_append
+#define da_free c_da_free
+#define da_shift c_da_shift
+#define DYNAMIC_ARRAY_INITIAL_CAPACITY c_DYNAMIC_ARRAY_INITIAL_CAPACITY
+// #define c_DYNAMIC_ARRAY_INITIAL_CAPACITY
+
+#define os_get_timedate c_os_get_timedate
+#define os_file_exists c_os_file_exists
+
+#define log_error c_log_error
+#define log_info c_log_info
+#define log_warning c_log_warning
+#define log_debug c_log_debug
+
+#define read_file c_read_file
+#define touch_file_if_doesnt_exist c_touch_file_if_doesnt_exist
+
+#define Arena c_Arena
+#define arena_make c_arena_make
+#define arena_alloc c_arena_alloc
+#define arena_reset c_arena_reset
+#define arena_free c_arena_free
+#define arena_alloc_str c_arena_alloc_str
+#define arena_alloc_wstr c_arena_alloc_wstr
+
+#define String_view c_String_view
+
+#define shift_args c_shift_args
+
+#define SV_FMT c_SV_FMT
+#define SV_ARG c_SV_ARG
+
+#define SV c_SV
+
+#define sv_print_dumb c_sv_print_dumb
+#define sv_from_cstr c_sv_from_cstr
+#define sv_lpop c_sv_lpop
+#define sv_lpop_until_predicate c_sv_lpop_until_predicate
+#define sv_lpop_until_string c_sv_lpop_until_string
+#define sv_rpop_until_predicate c_sv_rpop_until_predicate
+#define sv_lpop_until_char c_sv_lpop_until_char
+#define sv_rpop_until_char c_sv_rpop_until_char
+#define sv_lremove c_sv_lremove
+#define sv_rremove c_sv_rremove
+#define sv_lremove_until_char c_sv_lremove_until_char
+#define sv_rremove_until_char c_sv_rremove_until_char
+#define sv_lremove_until_char_after c_sv_lremove_until_char_after
+#define sv_rremove_until_char_after c_sv_rremove_until_char_after
+#define sv_ltrim c_sv_ltrim
+#define sv_rtrim c_sv_rtrim
+#define sv_trim c_sv_trim
+#define sv_to_cstr c_sv_to_cstr
+#define sv_to_int c_sv_to_int
+#define sv_to_uint c_sv_to_uint
+#define sv_to_uint8_hex c_sv_to_uint8_hex
+#define sv_to_float c_sv_to_float
+#define sv_contains_char c_sv_contains_char
+#define sv_is_hex_numbers c_sv_is_hex_numbers
+#define sv_equals c_sv_equals
+#define sv_get_part c_sv_get_part
+
+
+#endif // COMMONLIB_REMOVE_PREFIX
+
+// Memory allocation
+#ifndef C_MALLOC
+#define C_MALLOC malloc
+#endif
+#ifndef C_FREE
+#define C_FREE free
+#endif
+#ifndef C_REALLOC
+#define C_REALLOC realloc
+#endif
+#ifndef C_MEMCPY
+#define C_MEMCPY memcpy
+#endif
+
+
+// typedefs
+typedef unsigned int uint;
+typedef uint8_t      uint8;
+typedef uint16_t     uint16;
+typedef uint32_t     uint32;
+typedef uint64_t     uint64;
+
+typedef int8_t  int8;
+typedef int16_t int16;
+typedef int32_t int32;
+typedef int64_t int64;
+
+typedef float  float32;
+typedef double float64;
+
+typedef wchar_t wchar;
+
+typedef const char*  cstr;
+typedef const wchar* wstr;
+
+
+// Macros
+#if defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER)
+#define C_ASSERT(condition, msg) do {\
+                if (!(condition)) {\
+                        fprintf(stderr, "%s:%d:0 [ASSERTION FAILED] %s: %s", __FILE__, __LINE__, #condition, msg);\
+                        DebugBreak();\
+                }\
+        } while (0)
+#else
+#define C_ASSERT(condition, msg) do {\
+                if (!(condition)) {\
+                        fprintf(stderr, "%s:%d:0 [ASSERTION FAILED] %s: %s", __FILE__, __LINE__, #condition, msg);\
+                        exit(1);\
+                }\
+        } while (0)
+#endif // defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER)
+
+#define C_ARRAY_LEN(arr) (sizeof(arr) / sizeof(arr[0]))
+
+#define c_shift(xs, xsz) (assert(xsz > 0 && "Array is empty"), xsz--, *xs++)
+#define c_shift_args c_shift
+
+//
+// Math
+//
+
+int clampi(int v, int min, int max);
+float clampf(float v, float min, float max);
+
+//
+// Struct pre-decls
+//
+
+typedef struct c_Arena c_Arena;
+
+//
+// ## Data Structures
+//
+
+//
+// Dynamic-Array
+//
+
+// NOTE: To use c_da_append() the Dynamic-Array struct should be defined using
+// DEFINE_DYNAMIC_ARRAY or have the same members as below!
+// NOTE!!!: We actually don't want this since this makes the user want to
+// use this macro to define dynamic arrays. But the user might want extra fields
+// in the struct; So we recommend defining da structs manually like:
+// ```C
+// typedef struct {
+//    <item-type> items;
+//    size_t count;
+//    size_t capacity;
+//    [extra fields...];
+// }
+// ```
+// #define DEFINE_DYNAMIC_ARRAY(struct_name, elm_type) typedef struct {
+//         elm_type *items;
+//         size_t count;
+//         size_t capacity;
+//     }
+
+#define c_DYNAMIC_ARRAY_INITIAL_CAPACITY (sizeof(size_t))
+
+#define c_da_append(da, elm) do {\
+               if ((da).items == NULL) {\
+                       (da).capacity = c_DYNAMIC_ARRAY_INITIAL_CAPACITY;\
+                       (da).count = 0;\
+                       (da).items = C_MALLOC(sizeof(elm) * (da).capacity);\
+               }\
+               if ((da).count >= (da).capacity) {\
+                       (da).capacity *= 2;\
+                        (da).items = C_REALLOC((da).items, (da).capacity * sizeof(elm));\
+                       C_ASSERT((da).items != NULL, "TODO: Log error instead of asserting");\
+               }\
+               (da).items[(da).count++] = elm;\
+       } while (0)
+
+// NOTE: We cant do C_ASSERT() here because it aint one expression...
+// NOTE: da_shift will make the da loose its ptr, so store the ptr elsewhere if you want to free it later!!!
+#define c_da_shift(da) (assert((da).count > 0 && "Array is empty"), (da).count--, *(da).items++)
+#define c_da_free(da) C_FREE((da).items)
+#define c_da_remove(da, type, elm_ptr, idx) do {\
+        if ((idx) >= 0 && (idx) <= (da).count-1) {\
+            type temp = (da).items[(idx)];\
+            (da).items[(idx)] = (da).items[(da).count-1];\
+            (da).items[(da).count-1] = temp;\
+            if ((elm_ptr)) *(elm_ptr) = temp;\
+            (da).count--;\
+        }\
+    } while (0)
+
+//
+// OS
+//
+
+#if defined(__linux__)
+#include <sys/stat.h>
+#endif
+
+void c_os_get_timedate(c_Arena* a);
+bool c_os_file_exists(cstr filename);
+
+//
+// Logging
+//
+
+#define c_log_error(fmt, ...) do {\
+               fprintf(stderr, "%s"fmt"\n", "[ERROR] ", ##__VA_ARGS__);\
+       } while (0)
+#define c_log_info(fmt, ...) do {\
+               fprintf(stdout, "%s"fmt"\n", "[INFO] ", ##__VA_ARGS__);\
+       } while (0)
+#define c_log_warning(fmt, ...) do {\
+               fprintf(stdout, "%s"fmt"\n", "[WARNING] ", ##__VA_ARGS__);\
+       } while (0)
+#ifdef DEBUG
+#define c_log_debug(fmt, ...) do {\
+               fprintf(stdout, "%s"fmt"\n", "[DEBUG] ", ##__VA_ARGS__);\
+       } while (0)
+#else
+#define c_log_debug(...)
+#endif // DEBUG
+//
+// File
+//
+
+// reads entire file and gives back the file content and filesize in bytes. (caller must be responsible for freeing the string!)
+const char* c_read_file(const char* filename, int *file_size);
+void c_touch_file_if_doesnt_exist(cstr file);
+
+//
+// ### Allocators ###
+//
+
+//
+// c_Arena
+//
+
+#define ARENA_BUFF_INITIAL_SIZE (1024*4)
+
+struct c_Arena {
+    void* buff;
+    uint64 buff_size;
+    void* ptr;
+};
+
+// pass size 0 to get ARENA_BUFF_INITIAL_SIZE
+c_Arena c_arena_make(size_t size);
+void* c_arena_alloc(c_Arena* a, size_t size);
+void c_arena_reset(c_Arena* a);
+void c_arena_free(c_Arena* a);
+
+// TODO: Do we embed stb_snprintf to use stbsp_snprintf?
+#define c_arena_alloc_str(a, fmt, ...)    c_arena_alloc(&(a), sizeof(char)*snprintf((a).ptr, (int)((a).buff_size - ((uint8*)(a).ptr - (uint8*)(a).buff)), (fmt), __VA_ARGS__)+1)
+#define c_arena_alloc_wstr(a, fmt, ...) c_arena_alloc(&a, sizeof(char)*wprintf(a.ptr, a.buff_size - ((uint8*)a.ptr - (uint8*)a.buff), (fmt), __VA_ARGS__)+1)
+
+//
+// String Builder
+//
+
+typedef struct {
+    char* data;
+    size_t size;
+    size_t capacity;
+} c_String_builder;
+
+void c_sb_append(c_String_builder* sb, char* data);
+
+//
+// String view
+//
+
+typedef struct {
+    char *data;
+    size_t count;
+} c_String_view;
+
+#define c_SV_FMT "%.*s"
+#define c_SV_ARG(sv) (int)(sv).count, (sv).data
+
+#define c_SV(cstr) (c_String_view){.data = (char*)cstr, strlen(cstr)}
+
+void c_sv_print_dumb(c_String_view sv);
+c_String_view c_sv_from_cstr(const char* cstr); // Actually just use SV(cstr) macro...
+c_String_view c_sv_lpop(c_String_view* sv, uint32 n);
+c_String_view c_sv_lpop_until_predicate(c_String_view* sv, int(*predicate)(int));
+c_String_view c_sv_lpop_until_string(c_String_view* sv, const char *string);
+c_String_view c_sv_rpop_until_predicate(c_String_view* sv, int(*predicate)(int));
+c_String_view c_sv_lpop_until_char(c_String_view* sv, char ch);
+c_String_view c_sv_rpop_until_char(c_String_view* sv, char ch);
+void c_sv_lremove(c_String_view* sv, size_t n);
+void c_sv_rremove(c_String_view* sv, size_t n);
+void c_sv_lremove_until_char(c_String_view* sv, char ch);
+void c_sv_rremove_until_char(c_String_view* sv, char ch);
+void c_sv_lremove_until_char_after(c_String_view* sv, char ch);
+void c_sv_rremove_until_char_after(c_String_view* sv, char ch);
+void c_sv_ltrim(c_String_view* sv);
+void c_sv_rtrim(c_String_view* sv);
+void c_sv_trim(c_String_view* sv);
+char* c_sv_to_cstr(c_String_view sv);
+int64 c_sv_to_int(c_String_view sv, int *count, int base);
+uint64 c_sv_to_uint(c_String_view sv, int *count, int base);
+float64 c_sv_to_float(c_String_view sv, int *count);
+bool c_sv_contains_char(c_String_view sv, char ch);
+bool c_sv_is_hex_numbers(c_String_view sv);
+bool c_sv_equals(c_String_view sv1, c_String_view sv2);
+c_String_view c_sv_get_part(c_String_view sv, int from, int to);
+
+#endif /* _COMMONLIB_H_ */
+
+//////////////////////////////////////////////////
+#ifdef COMMONLIB_IMPLEMENTATION
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+
+// My things implementation:
+
+//
+// Math
+//
+
+int clampi(int v, int min, int max) {
+    v = v < min ? min : v;
+    v = v > max ? max : v;
+    return v;
+}
+
+float clampf(float v, float min, float max) {
+    v = v < min ? min : v;
+    v = v > max ? max : v;
+    return v;
+}
+
+//
+// OS
+//
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+void c_os_get_timedate(c_Arena* a) {
+        (void)a;
+        C_ASSERT(false, "Unimplemented!");
+}
+
+bool c_os_file_exists(cstr filename) {
+        (void) filename;
+        C_ASSERT(false, "Unimplemented!");
+        return false;
+}
+
+#elif defined(__linux__)
+void c_os_get_timedate(c_Arena* a) {
+        (void)a;
+        C_ASSERT(false, "Unimplemented!");
+}
+
+bool c_os_file_exists(cstr filename) {
+        struct stat buf;
+        return stat(filename, &buf) == 0;
+}
+#endif
+
+// simple and dirty way to have defering in C (not recommended to use!)
+#define defer(ret_val) \
+    result = ret_val;\
+    goto defer
+
+const char *c_read_file(const char* filename, int *file_size) {
+    FILE* f = fopen(filename, "r");
+    char* result = NULL;
+
+    if (f == NULL){
+        // TODO: Replace every strerror with strerror_s
+        c_log_error("'%s': %s", filename, strerror(errno));
+        defer(NULL);
+    }
+
+    if (fseek(f, 0, SEEK_END) < 0) {
+        c_log_error("'%s': %s", filename, strerror(errno));
+        defer(NULL);
+    }
+
+    size_t fsize = ftell(f);
+
+    if (fsize == (size_t)-1){
+        c_log_error("'%s': %s", filename, strerror(errno));
+        defer(NULL);
+    }
+
+    result = C_MALLOC(sizeof(char)*(fsize+1));
+
+    if (result == NULL){
+        c_log_error("'%s': %s", filename, strerror(errno));
+        defer(NULL);
+    }
+
+    if (fseek(f, 0, SEEK_SET) < 0) {
+        c_log_error("'%s': %s", filename, strerror(errno));
+        defer(NULL);
+    }
+
+    size_t read = fread((char*)result, sizeof(char), fsize, f);
+
+    // Process the result to remove '\r' characters
+    char* cleaned_result = malloc(read + 1); // Allocate memory for cleaned result
+    if (cleaned_result == NULL) {
+        fprintf(stderr, "Memory allocation failed\n");
+        free(result);
+        return NULL;
+    }
+
+    size_t j = 0; // Index for cleaned_result
+    for (size_t i = 0; i < read; i++) {
+        if (result[i] != '\r') { // Skip '\r' characters
+            cleaned_result[j++] = result[i];
+        }
+    }
+    cleaned_result[j] = '\0'; // Null-terminate the cleaned result
+
+    free(result); // Free the original result
+    *file_size = (int)j; // Update the file size without '\r'
+    return cleaned_result; // Return the cleaned result
+
+    *file_size = (int)read;
+
+ defer:
+    if (f) fclose(f);
+    if (result == NULL) *file_size = -1;
+    return result;
+}
+
+void c_touch_file_if_doesnt_exist(cstr filename) {
+        if (c_os_file_exists(filename)) return;
+        FILE* file = fopen(filename, "w");
+        if (file) fclose(file);
+}
+
+//
+// ### Allocators ###
+//
+
+// c_Arena
+
+c_Arena c_arena_make(size_t size) {
+    c_Arena res = {0};
+    res.buff_size = size == 0 ? ARENA_BUFF_INITIAL_SIZE : size;
+    res.buff = C_MALLOC(res.buff_size);
+    res.ptr = res.buff;
+
+    C_ASSERT(res.buff, "Malloc failed?");
+
+    return res;
+}
+
+void* c_arena_alloc(c_Arena* a, size_t size) {
+    C_ASSERT(a->buff, "Bro pass an initialized arena!");
+
+    void* res = a->ptr;
+    a->ptr = (uint8*)a->ptr + size;
+
+    size_t diff = (size_t)((uint8*)a->ptr - (uint8*)a->buff);
+    if (diff > a->buff_size) {
+        c_log_info("c_Arena resized from %zu to %zu", a->buff_size, a->buff_size*2);
+        a->buff_size *= 2;
+        a->buff = C_REALLOC(a->buff, a->buff_size);
+        a->ptr = (uint8*)a->buff + diff;
+        res = a->ptr;
+        a->ptr = (uint8*)a->ptr + size;
+    }
+    /* C_ASSERT((size_t)((uint8*)a->ptr - (uint8*)a->buff) <= a->buff_size); */
+
+    return res;
+}
+
+void c_arena_reset(c_Arena* a) {
+    a->ptr = a->buff;
+}
+
+void c_arena_free(c_Arena* a) {
+    C_FREE(a->buff);
+}
+
+//
+// String Builder
+//
+
+void c_sb_append(c_String_builder* sb, char* data) {
+    size_t data_size = strlen(data);
+    if (sb->size + data_size > sb->capacity) {
+        sb->capacity *= 2;
+        sb->data = C_REALLOC(sb->data, sb->capacity);
+    }
+
+    // void *memcpy(void dest[restrict .n], const void src[restrict .n],
+    C_MEMCPY((void *)((uintptr_t)sb->data + (uintptr_t)sb->data), data, data_size);
+    sb->size += data_size;
+}
+
+//
+// String view
+//
+
+void c_sv_print_dumb(c_String_view sv){
+    for (size_t i = 0; i < (size_t)sv.count; ++i){
+        putc(*(sv.data+i), stdout);
+    }
+}
+
+c_String_view c_sv_from_cstr(const char* cstr){
+    return (c_String_view){
+        .data = (char *)cstr,
+        .count = strlen(cstr),
+    };
+}
+
+c_String_view c_sv_lpop(c_String_view* sv, uint32 n) {
+    c_String_view res = {0};
+    if (sv->count < n) return res;
+    res.data = sv->data;
+    res.count = n;
+
+    sv->data += n;
+    sv->count -= n;
+
+    return res;
+}
+
+c_String_view c_sv_lpop_until_predicate(c_String_view* sv, int(*predicate)(int)){
+    const char* old_sv_data = sv->data;
+    while (sv->count > 0 && !predicate(*sv->data)){
+        sv->data++;
+        sv->count--;
+    }
+
+    return (c_String_view){
+        .data = sv->data - (sv->data - old_sv_data),
+        .count = (sv->data - old_sv_data),
+    };
+}
+
+c_String_view c_sv_lpop_until_string(c_String_view* sv, const char *string) {
+    size_t string_len = strlen(string);
+
+    char *old_sv_data = sv->data;
+
+    while (sv->count > string_len) {
+        bool matched = true;
+        for (size_t i = 0; i < string_len; ++i) {
+            if (sv->data[i] != string[i]) matched = false;
+        }
+        if (matched) break;
+        sv->data++;
+        sv->count--;
+    }
+
+    return (c_String_view) {
+        .data = old_sv_data,
+        .count = (sv->data - old_sv_data),
+    };
+}
+
+c_String_view c_sv_rpop_until_predicate(c_String_view* sv, int(*predicate)(int)){
+    size_t old_sv_count = sv->count;
+    while (sv->count > 0 && !predicate(*(sv->data+sv->count-1))){
+        sv->count--;
+    }
+
+    return (c_String_view){
+        .data = sv->data + sv->count,
+        .count = old_sv_count - sv->count,
+    };
+}
+
+c_String_view c_sv_lpop_until_char(c_String_view* sv, char ch){
+    const char* old_sv_data = sv->data;
+    while (sv->count > 0 && *sv->data != ch){
+        sv->data++;
+        sv->count--;
+    }
+
+    return (c_String_view){
+        .data = sv->data - (sv->data - old_sv_data),
+        .count = (sv->data - old_sv_data),
+    };
+}
+
+c_String_view c_sv_rpop_until_char(c_String_view* sv, char ch){
+    size_t old_sv_count = sv->count;
+    while (sv->count > 0 && *(sv->data+sv->count-1) != ch){
+        sv->count--;
+    }
+
+    return (c_String_view){
+        .data = sv->data + sv->count,
+        .count = old_sv_count - sv->count,
+    };
+}
+
+void c_sv_lremove(c_String_view* sv, size_t n){
+    if (n > sv->count) n = sv->count;
+
+    sv->data += n;
+    sv->count -= n;
+}
+
+void c_sv_rremove(c_String_view* sv, size_t n){
+    if (n > sv->count)
+        sv->count = 0;
+    else
+        sv->count -= n;
+}
+
+void c_sv_lremove_until_char(c_String_view* sv, char ch){
+    while (sv->count > 0 && *sv->data != ch){
+        sv->data++;
+        sv->count--;
+    }
+}
+
+void c_sv_rremove_until_char(c_String_view* sv, char ch){
+    while (sv->count > 0 && *(sv->data+sv->count-1) != ch){
+        sv->count--;
+    }
+}
+
+void c_sv_lremove_until_char_after(c_String_view* sv, char ch){
+    while (sv->count > 0 && *(sv->data-1) != ch){
+        sv->data++;
+        sv->count--;
+    }
+}
+
+void c_sv_rremove_until_char_after(c_String_view* sv, char ch){
+    while (sv->count > 0 && *(sv->data+sv->count) != ch){
+        sv->count--;
+    }
+}
+
+void c_sv_ltrim(c_String_view* sv){
+    while (sv->count > 0 && isspace(*sv->data)){
+        sv->data++;
+        sv->count--;
+    }
+}
+
+void c_sv_rtrim(c_String_view* sv){
+    while (sv->count > 0 && isspace(*(sv->data+sv->count-1))){
+        sv->count--;
+    }
+}
+
+void c_sv_trim(c_String_view* sv){
+    c_sv_ltrim(sv);
+    c_sv_rtrim(sv);
+}
+
+char* c_sv_to_cstr(c_String_view sv){
+    char* res = (char*)malloc(sizeof(char)*(sv.count + 1));
+    if (res == NULL) {
+        C_ASSERT(false, "Buy more RAM bruh");
+    }
+    C_MEMCPY(res, sv.data, sv.count);
+    res[sv.count] = '\0';
+    return res;
+}
+
+int64 c_sv_to_int(c_String_view sv, int *count_out, int base) {
+    char *str = c_sv_to_cstr(sv);
+
+    char *endptr = NULL;
+
+    int64 res = strtol(str, &endptr, base);
+
+    if (endptr == str) {
+        *count_out = -1;
+        return res;
+    }
+
+    *count_out = (int)(endptr - str);
+
+    C_FREE(str);
+    return res;
+}
+
+uint64 c_sv_to_uint(c_String_view sv, int *count, int base) {
+    char* str = c_sv_to_cstr(sv);
+
+    char *endptr = NULL;
+    uint64 res = strtoul(str, &endptr, base);
+
+    if (endptr == str) {
+        *count = -1;
+        return res;
+    }
+
+    *count = (int)(endptr - str);
+
+    C_FREE(str);
+    return res;
+}
+
+float64 c_sv_to_float(c_String_view sv, int *count) {
+    char* str = c_sv_to_cstr(sv);
+
+    char *endptr = NULL;
+    float64 res = strtod(str, &endptr);
+
+    if (endptr == str) {
+        *count = -1;
+        return res;
+    }
+
+    *count = (int)(endptr - str);
+
+    C_FREE(str);
+    return res;
+}
+
+bool c_sv_contains_char(c_String_view sv, char ch){
+    for (size_t i = 0; i < sv.count; ++i){
+        if (sv.data[i] == ch) return true;
+    }
+    return false;
+}
+
+bool c_sv_is_hex_numbers(c_String_view sv) {
+    char hex[] = {
+        '0', '1', '2', '3', '4', '5', '6', '7',
+        '8', '9', '0', 'a', 'b', 'c', 'd', 'e', 'f',
+        'A', 'B', 'C', 'D', 'E', 'F'
+    };
+    bool found = false;
+    for (size_t i = 0; i < sv.count; ++i) {
+        char c = sv.data[i];
+        for (size_t j = 0; j < C_ARRAY_LEN(hex); ++j) {
+            if (hex[j] == c) {
+       found = true;
+            }
+        }
+    }
+
+    return found;
+}
+
+bool c_sv_equals(c_String_view sv1, c_String_view sv2) {
+    if (sv1.count != sv2.count) return false;
+    for (size_t i = 0; i < sv1.count; ++i) {
+        if (sv1.data[i] != sv2.data[i]) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+c_String_view c_sv_get_part(c_String_view sv, int from, int to) {
+    from = clampi(from, 0, sv.count);
+    to   = clampi(to, from, sv.count);
+
+    c_String_view range = {
+        .data = (char*)(sv.data + from),
+        .count = (size_t)(to - from),
+    };
+
+    return range;
+}
+#endif
index 1b98073b5d1b0b1323203fb2db588b6291cfef77..99b9b9ca99133b046e83ac1a166b8388b42d7e22 100644 (file)
@@ -1,52 +1,11 @@
 [INFO] Even numbers:
-[INFO] 6
 [INFO] 0
 [INFO] 2
 [INFO] 4
 [INFO] 6
 [INFO] 8
-[INFO] 10
-[INFO] 12
-[INFO] 14
-[INFO] 16
-[INFO] 18
-[INFO] 20
-[INFO] 22
-[INFO] 24
-[INFO] 26
-[INFO] 28
-[INFO] 30
-[INFO] 32
-[INFO] 34
-[INFO] 36
-[INFO] 38
-[INFO] 40
-[INFO] 42
-[INFO] 44
-[INFO] 46
-[INFO] 48
-[INFO] 50
-[INFO] 52
-[INFO] 54
-[INFO] 56
-[INFO] 58
-[INFO] 60
-[INFO] 62
-[INFO] 64
-[INFO] 66
-[INFO] 68
-[INFO] 70
-[INFO] 72
-[INFO] 74
-[INFO] 76
-[INFO] 78
-[INFO] 80
-[INFO] 82
-[INFO] 84
-[INFO] 86
-[INFO] 88
-[INFO] 90
-[INFO] 92
-[INFO] 94
-[INFO] 96
-[INFO] 98
+[INFO] da count before remove: 5
+[INFO] Third element: 4
+[INFO] da count after remove: 4
+[INFO] outofbound_value : -1
+[INFO] da count after trying to remove outofbounds_value: 4
index 73376f60e09ec6ddf410186d0cb5f83d7791aef9..343ede92f5e71300250530d0a00c9b0d1fff1a78 100644 (file)
@@ -12,19 +12,30 @@ int main(void) {
 
     c_da_append(da, 6);
 
-    for (int i = 0; i < 100; ++i) {
+    for (int i = 0; i < 10; ++i) {
         if (i % 2 == 0) c_da_append(da, i);
     }
+    // NOTE: da_shift will make the da loose its ptr, so store the ptr elsewhere if you want to free it later!!!
+    int a = c_da_shift(da);
+
+    C_ASSERT(a == 6, "da_shift did not return correct value");
 
     c_log_info("Even numbers:");
     for (int i = 0; i < da.count; ++i) {
         c_log_info("%d", da.items[i]);
     }
 
+    int third = 0;
+    c_log_info("da count before remove: %zu", da.count);
+    c_da_remove(da, int, &third, 2);
 
-    // NOTE: da_shift
-    int a = c_da_shift(da);
+    c_log_info("Third element: %d", third);
+    c_log_info("da count after remove: %zu", da.count);
+
+    int outofbound_value = -1;
+    c_da_remove(da, int, &outofbound_value, 50);
+    c_log_info("outofbound_value : %d", outofbound_value);
+    c_log_info("da count after trying to remove outofbounds_value: %zu", da.count);
 
-    C_ASSERT(a == 6, "da_shift did not return correct value");
     return 0;
 }