#ifndef CORE_H #define CORE_H // cstdlib includes #include "stdbool.h" #include "stdint.h" // necessary for int type sizes #include "time.h" // TODO(djledda): try not to depend on this one // ### Misc macros ### #if DJSTDLIB_DEBUG #define Assert(expression) if (!(expression)) {*(volatile int *)0 = 0;} #else #define Assert(expression) #endif #define function static #define global static #define local_persist static #define forever for (;;) #define DeferLoop(begin_stmnt, end_stmnt) for(int __defer_i = ((begin_stmnt), 0); __defer_i < 1; (++__defer_i, (end_stmnt))) // ### Types ### typedef int8_t int8; typedef int16_t int16; typedef int32_t int32; typedef int64_t int64; typedef uint8_t uint8; typedef uint16_t uint16; typedef uint32_t uint32; typedef uint64_t uint64; typedef char byte; typedef float real32; typedef double real64; typedef struct string string; // ### Sizes and Numbers ### #define Bytes(n) (n) #define Kilobytes(n) (n << 10) #define Megabytes(n) (n << 20) #define Gigabytes(n) (((uint64)n) << 30) #define Terabytes(n) (((uint64)n) << 40) #define Thousand(n) ((n)*1000) #define Million(n) ((n)*1000000) #define Billion(n) ((n)*1000000000LL) #define ArrayCount(arr) (sizeof(arr) / sizeof((arr)[0])) #define MemberSize(type, memberName) sizeof(((type *)0)->memberName) #define MemberSizeUnderlying(type, memberName) sizeof(*((type *)0)->memberName) // ### Arenas ### typedef struct Arena Arena; struct Arena { void *memory; size_t capacity; size_t head; }; typedef struct Scratch Scratch; struct Scratch { Arena *arena; size_t start; }; void *pushSize(Arena *arena, size_t bytes); void *pushSizeFill(Arena *arena, size_t bytes, byte fill); Arena *arenaAlloc(size_t capacity); void arenaFree(Arena *arena); void arenaFreeFrom(Arena *arena, size_t pos); void arenaPopTo(Arena *arena, void *pos); void initialiseDjStdCore(); Scratch scratchStart(Arena **conflicts, size_t conflictCount); void scratchEnd(Scratch scratch); #define PushArray(arena, type, size) (type *)pushSize(arena, sizeof(type) * (size)) #define PushArrayZero(arena, type, size) (type *)pushSizeFill(arena, sizeof(type) * (size), 0) #define PushStruct(arena, type) (type *)pushSize(arena, sizeof(type)) #define PushStructZero(arena, type) (type *)pushSizeFill(arena, sizeof(type), 0) #define WithScratch(scratchName) Scratch scratchName; DeferLoop(scratchName = scratchStart(0, 0), scratchEnd(scratchName)) // ### Vectors ### typedef union Vec2 Vec2; union Vec2 { struct { real32 x; real32 y; }; real32 vec[2]; }; inline function Vec2 vec2(real32 x, real32 y) { Vec2 result = {0}; result.x = x; result.y = y; return result; } typedef union Vec3 Vec3; union Vec3 { struct { real32 x; real32 y; real32 z; }; real32 vec[3]; }; inline function Vec3 vec3(real32 x, real32 y, real32 z) { Vec3 result = {0}; result.x = x; result.y = y; result.z = z; return result; } typedef union Vec4 Vec4; union Vec4 { struct { real32 r; real32 g; real32 b; real32 a; }; struct { real32 x; real32 y; real32 z; real32 w; }; real32 vec[4]; }; inline function Vec4 vec4(real32 x, real32 y, real32 z, real32 w) { Vec4 result = {0}; result.x = x; result.y = y; result.z = z; result.w = w; return result; } // ### Lists ### #define DefineList(type, prefix) \ typedef struct prefix ## List prefix ## List;\ struct prefix ## List {\ type *data;\ size_t length;\ size_t capacity;\ };\ typedef type prefix ## List ## _underlying #define ListElementSize(list) MemberSizeUnderlying(list, data) DefineList(string, String); #define PushList(arena, type, size) (type){ .data=pushSize(arena, ListElementSize(type)*(size)), .length=0, .capacity=(size) } #define PushListZero(arena, type, size) (type){ .data=pushSizeFill(arena, ListElementSize(type)*(size), 0), .length=0, .capacity=(size) } #define PushFullList(arena, type, size) (type){ .data=pushSize(arena, ListElementSize(type)*size), .length=(size), .capacity=(size) } #define PushFullListZero(arena, type, size) (type){ .data=pushSizeFill(arena, ListElementSize(type)*(size), 0), .length=(size), .capacity=(size) } #define EmptyList() { NULL, 0, 0 } #define __ArrayAsList(array) { .data=(array), .length=ArrayCount(array), .capacity=ArrayCount(array) } #define AsList(listtype, ...) (listtype)__ArrayAsList(((listtype##_underlying[])__VA_ARGS__)) // TODO(dledda): clone list // TODO(dledda): list back element accessor #define AppendList(list, element) \ if ((list)->length < (list)->capacity) { \ (list)->data[(list)->length++] = (element); \ } #define ZeroListFull(list) memset((list)->data, 0, (list)->length * sizeof((list)->data[0])) #define ZeroList(list) (list)->length = 0; \ memset((list)->data, 0, (list)->length * sizeof((list)->data[0])) // Following two macros do not use pointers due to copying #define ListSlice(list, start, stop) {\ .data= (stop > (list).length || start > stop) ? 0 : (list).data + start,\ .length=(stop > (list).length || start > stop) ? 0 : stop - start,\ .capacity=(stop > (list).length || start > stop) ? 0 : stop - start,\ } #define ListTail(list, start) ListSlice(list, start, (list).length) #define ListRemove(list, index)\ if ((index) >= 0 && (index) < (list)->length) {\ memcpy((list)->data + (index), (list)->data + (index) + 1, (parentNode->children.length - (i + 1))*sizeof(*((list)->data)));\ parentNode->children.length -= 1;\ } // ### Strings ### struct string { char *str; size_t length; }; #define STB_SPRINTF_DECORATE(name) stb_##name // define this before including if you want to change the names #include "vendor/stb_sprintf.h" #define s(lit) ((string){(char *)(lit), sizeof(lit) - 1}) #define PushString(arena, length) ((string){ (char *)pushSize(arena, length), (length) }) #define PushStringFill(arena, length, characterByte) ((string){ (char *)pushSizeFill(arena, length, characterByte), (length) }) // C Strings DefineList(char, Char); const char *cstringFromCharList(Arena *arena, CharList buf); const char *cstring(Arena *arena, string str); size_t calcStringLen(const char *str); string strFromCString(Arena *arena, const char *str); bool strEql(string s1, string s2); bool strStartsWith(string str, string testStr); bool stringContains(string str, char c); string strReverse(Arena *arena, string str); string strSlice(string str, size_t start, size_t stop); string strSliceCStr(char *data, size_t start, size_t stop); StringList strSplit(Arena *arena, string splitStr, string inputStr); string strPrintfv(Arena *arena, const char *fmt, va_list args); string strPrintf(Arena *arena, const char *fmt, ...); #define DefineResult(type, prefix) \ typedef struct prefix ## Result prefix ## Result;\ struct prefix ## Result {\ type result;\ bool valid;\ };\ typedef type prefix ## Result ## _underlying DefineResult(int32, Int32); Int32Result parsePositiveInt(string str); DefineResult(real32, Real32); Real32Result parsePositiveReal32(string str); inline function bool isNumeric(char c); // ### Cmdline ### StringList getArgs(Arena *arena, int argc, char **argv); // ### Time ### typedef uint64 UnixTimestamp; typedef struct tm Timestamp; UnixTimestamp getSystemUnixTime(); Timestamp timestampFromUnixTime(UnixTimestamp *unixTimestamp); string formatTimeHmsUnix(Arena *arena, UnixTimestamp time); string formatTimeHms(Arena *arena, Timestamp *time); string formatTimeYmdUnix(Arena *arena, UnixTimestamp time); string formatTimeYmd(Arena *arena, Timestamp *time); // ### Linked Lists ### // TODO(djledda): implement basic linked lists (based on arenas?) // ### Logging ### typedef enum { StdStream_stdout, StdStream_stdin, StdStream_stderr, } StdStream; #define ANSI_INSTRUCTION_FROM_ENUM(ansiCodeEnum) ANSI_INSTRUCTION(ansiCodeEnum) #define ANSI_INSTRUCTION(ansiCode) "\x1b[" #ansiCode "m" #define ANSI_INSTRUCTION_STR(ansiCodeStr) "\x1b[" ansiCodeStr "m" #define ANSI_RESET ANSI_INSTRUCTION(0) #define ANSI_fg_black 30 #define ANSI_fg_red 31 #define ANSI_fg_green 32 #define ANSI_fg_yellow 33 #define ANSI_fg_blue 34 #define ANSI_fg_magenta 35 #define ANSI_fg_cyan 36 #define ANSI_fg_white 37 #define ANSI_fg_bblack 90 #define ANSI_fg_bred 91 #define ANSI_fg_bgreen 92 #define ANSI_fg_byellow 93 #define ANSI_fg_bblue 94 #define ANSI_fg_bmagenta 95 #define ANSI_fg_bcyan 96 #define ANSI_fg_bwhite 97 #define ANSI_bg_black 40 #define ANSI_bg_red 41 #define ANSI_bg_green 42 #define ANSI_bg_yellow 43 #define ANSI_bg_blue 44 #define ANSI_bg_magenta 45 #define ANSI_bg_cyan 46 #define ANSI_bg_white 47 #define ANSI_bg_bblack 100 #define ANSI_bg_bred 101 #define ANSI_bg_bgreen 102 #define ANSI_bg_byellow 103 #define ANSI_bg_bblue 104 #define ANSI_bg_bmagenta 105 #define ANSI_bg_bcyan 106 #define ANSI_bg_bwhite 107 #define COLOR_TEXT(text, foregroundcolor) ANSI_INSTRUCTION_FROM_ENUM(foregroundcolor) text ANSI_RESET #define COLOR_TEXT_BG(text, backgroundcolor) ANSI_INSTRUCTION_FROM_ENUM(backgroundcolor) text ANSI_RESET #define COLOR_TEXT_FG_BG(text, foregroundcolor, backgroundcolor) ANSI_INSTRUCTION_FROM_ENUM(foregroundcolor) ANSI_INSTRUCTION_FROM_ENUM(backgroundcolor) text ANSI_RESET #define COLOR_TEXT_RGB(text, red, green, blue) ANSI_INSTRUCTION_STR("38;2;" #red ";" #green ";" #blue) text ANSI_RESET DefineList(int, Int); void printIntList(IntList l); void printStrList(StringList l); void setStdout(); void setStderr(); extern void (*print)(const char *fmt, ...); extern void (*println)(const char *fmt, ...); // ### Loops ### #define EachIn(list, it) size_t it = 0; it < (list).length; it++ #define EachEl(list, type, element) type *element = (list).data; element < (list).data + (list).length; element += 1 #define EachInReversed(list, it) size_t it = (list).length - 1; it >= 0 && it < (list).length; it-- #define EachInArray(arr, it) size_t it = 0; it < ArrayCount(arr); ++it // ### Misc ### int intCompare(const void *a, const void *b); #endif