#ifndef BASE_TYPES_H #define BASE_TYPES_H #include #include #include ///////////////////////// //~ Macros ///////////////////////// //- Linking keywords // TODO(anton): Understand this, yoinked from rjf's layer. #if LANG_CPP # define no_name_mangle extern "C" #else # define no_name_mangle #endif // TODO(anton): OS_WINDOWS dll import/export macros ///////////////////////// //- Keywords // Static is stupid and means different things depending on context in C and C++. // These defines increases readability. #define function static // Function internal to compilation unit. #define local_persist static #define global static #define fallthrough // for use in switch statements, for clarity.. // TODO(anton): Understand and add good comment on this. #if LANG_CPP # define root_global no_name_mangle # define root_function function #else # define root_global extern # define root_function function #endif #define inline_function inline static #if OS_WINDOWS # pragma section(".roglob", read) # define read_only __declspec(allocate(".roglob")) #else # define read_only #endif #if COMPILER_MSVC # define per_thread __declspec(thread) #else # error Thread keyword not abstracted on compiler. #endif ///////////////////////// //- Memory operations // It's nice to put these in macros, so we can swap out the functionality from standard library, eventually. #define MemoryCopy memcpy #define MemoryMove memmove #define MemorySet memset // NOTE(anton): This gives a 4127 compiler warning for the sizeof conditional. This should be ignored #define MemoryCopyStruct(dst, src) do { Assert(sizeof(*(dst)) == sizeof(*(src))); MemoryCopy((dst), (src), sizeof(*(dst))); } while(0) #define MemoryZero(ptr, size) MemorySet((ptr), 0, (size)) #define MemoryZeroStruct(ptr) MemoryZero((ptr), sizeof(*(ptr))) #define MemoryZeroArray(arr) MemoryZero((arr), sizeof(arr)) ///////////////////////// //- Integer/pointer/array/type manipulations #define ArrayCount(a) (sizeof(a) / sizeof((a)[0])) #define IntFromPtr(p) (U64)(((U8*)p) - 0) #define PtrFromInt(i) (void*)(((U8*)0) + i) #define Member(type, member_name) ((type *)0)->member_name // TODO(anton): Understand why this becomes offset actually #define OffsetOf(type, member_name) IntFromPtr(&Member(type, member_name)) // TODO(anton): Understand this #define BaseFromMember(type, member_name, ptr) (type *)((U8 *)(ptr) - OffsetOf(type, member_name)) #define Bytes(n) (n) #define Kilobytes(n) (n << 10) // 2^10 == 1024 etc #define Megabytes(n) (n << 20) #define Gigabytes(n) (((U64)n) << 30) #define Terabytes(n) (((U64)n) << 40) #define Thousand(n) ((n)*1000) #define Million(n) ((n)*1000000) #define Billion(n) ((n)*1000000000LL) #define AbsoluteValueU64(x) (U64)llabs((U64)(x)) ///////////////////////// //- Linked list helpers #define CheckNull(p) ((p)==0) #define SetNull(p) ((p)=0) // Link list helper macros that are a bit involved // Suffixes N,P,Z means that we have (N)ext, (P)rev arguments and/or a (Z)ero check and/or set argument // f, l, n are "first", "last", "node" I think? // DLL // Doubly Linked List: Each node has a prev and next pointer. Operations: Push back, Push front, remove #define DLLInsert_NPZ(f,l,p,n,next,prev,zchk,SetNull) \ (zchk(f) ? (((f) = (l) = (n)), SetNull((n)->next), SetNull((n)->prev)) :\ zchk(p) ? (SetNull((n)->prev), (n)->next = (f), (zchk(f) ? (0) : ((f)->prev = (n))), (f) = (n)) :\ ((zchk((p)->next) ? (0) : (((p)->next->prev) = (n))), (n)->next = (p)->next, (n)->prev = (p), (p)->next = (n),\ ((p) == (l) ? (l) = (n) : (0)))) #define DLLPushBack_NPZ(f,l,n,next,prev,zchk,SetNull) DLLInsert_NPZ(f,l,l,n,next,prev,zchk,SetNull) #define DLLPushBack_NP(f, l, n, next, prev, zchk) \ (zchk(f) ? ((f)=(l)=(n),(n)->next=(n)->prev=0) : ((n)->prev=(l),(l)->next=(n),(l)=(n),(n)->next=0)) // If f == n we put f to f->next, and f->prev = 0. // Else if l == n, we put l=l->prev, l->next = 0. // If l != n and f != n we set n->next->prev to n->prev, and n->prev->next to n->next #define DLLRemove_NP(f, l, n, next, prev) (((f) == (n) ? \ ((f)=(f)->next, (f)->prev=0) : \ (l) == (n) ? \ ((l)=(l)->prev, (l)->next=0) : \ ((n)->next->prev=(n)->prev, \ (n)->prev->next=(n)->next) )) #define DLLRemove_NPZ(f,l,n,next,prev,zchk,SetNull) (((f)==(n))?\ ((f)=(f)->next, (zchk(f) ? (SetNull(l)) : SetNull((f)->prev))):\ ((l)==(n))?\ ((l)=(l)->prev, (zchk(l) ? (SetNull(f)) : SetNull((l)->next))):\ ((zchk((n)->next) ? (0) : ((n)->next->prev=(n)->prev)),\ (zchk((n)->prev) ? (0) : ((n)->prev->next=(n)->next)))) #define DLLPushBack(f, l, n) DLLPushBack_NPZ(f, l, n, next, prev, CheckNull, SetNull) // For front push I can just switch prev/next! #define DLLPushFront(f, l, n) DLLPushBack_NPZ(l, f, n, prev, next, CheckNull, SetNull) #define DLLRemove(f, l, n) DLLRemove_NPZ(f, l, n, next, prev, CheckNull, SetNull) // SLL, queue or stack. // These are from rjf's layer. //////////////// // Queue // Queue has only a next pointer. But we can push from front also. // zchk = zero check, SetNull = zero set #define QueuePush_NZ(f, l, n, next, zchk, SetNull) (zchk(f)?\ (((f)=(l)=(n)), SetNull((n)->next)):\ ((l)->next=(n),(l)=(n),SetNull((n)->next))) #define QueuePushFront_NZ(f, l, n, next, zchk, SetNull) ( zchk(f) ? \ ((f)=(l)=(n)), SetNull((n)->next) : \ ((n)->next = (f)), ((f) = (n)) ) #define QueuePop_NZ(f, l, next, zchk, SetNull) ( (f)==(l) ? \ (SetNull(f), SetNull(l)) : ((f)=(f)->next)) #define QueuePush(f, l, n) QueuePush_NZ(f, l, n, next, CheckNull, SetNull) #define QueuePushFront(f, l, n) QueuePushFront_NZ(f, l, n, next, CheckNull, SetNull) #define QueuePop(f, l) QueuePop_NZ(f, l, next, CheckNull, SetNull) //////////////// // Stack #define StackPush_N(f, n, next) ((n)->next=(f), (f)=(n)) // Take the first element and set it to n->next, and set the first element to the node n. #define StackPop_NZ(f, next, zchk) (zchk(f) ? 0 : ((f)=(f)->next)) // If first element is not zero we say that the first element is f->next, ie we pop f and put f->next on top. #define StackPush(f, n) StackPush_N(f, n, next) #define StackPop(f) StackPop_NZ(f, next, CheckNull) ///////////////////////// //- Clamp/min/max #define Min(a, b) (((a)<(b)) ? (a) : (b)) #define Max(a, b) (((a)>(b)) ? (a) : (b)) #define ClampTop(x, a) Min(x,a) // "Top" since we are cutting off anything above Min(x,a) #define ClampBot(a, x) Max(a,x) // "Bot" since we're cutting off anything below Max(a,x) // If a > x we get a, else we see if b < x and then get b if true, else x. // TODO(anton): Is this actually what we want from a Clamp? #define Clamp(a, x, b) (((a)>(x))?(a):((b)<(x))?(b):(x)) //- loop #define DeferLoop(start, end) for(int _i_ = ((start), 0); _i_ == 0; _i_ += 1, (end)) #define DeferLoopChecked(begin, end) for(int _i_ = 2 * !(begin); (_i_ == 2 ? ((end), 0) : !_i_); _i_ += 1, (end)) #define EachEnumVal(type, it) type it = (type)0; it < type##_COUNT; it = (type)(it+1) #define EachNonZeroEnumVal(type, it) type it = (type)1; it < type##_COUNT; it = (type)(it+1) ///////////////////////// //~ Base types typedef int8_t S8; typedef int16_t S16; typedef int32_t S32; typedef int64_t S64; typedef uint8_t U8; typedef uint16_t U16; typedef uint32_t U32; typedef uint64_t U64; typedef S8 B8; typedef S16 B16; typedef S32 B32; typedef S64 B64; typedef float F32; typedef double F64; typedef void VoidFunction(void); ///////////////////////// //~ Numerical limits read_only global U8 U8Max = 0xFF; read_only global U8 U8Min = 0; read_only global U32 U32Max = 0xFFFFFFFF; read_only global U32 U32Min = 0; read_only global U64 U64Max = 0xFFFFFFFFFFFFFFFF; // TODO(anton): Rest of the limits, unsigned and signed integer values read_only global U32 SignF32 = 0x80000000; //- compiler, shut up! helpers #define unused_variable(name) (void)name ///////////////////////// //~ Base enums // Describing a 2-coordinate system typedef enum Axis2 { Axis2_Invalid = -1, Axis2_X, Axis2_Y, Axis2_COUNT } Axis2; #define Axis2_flip(a) ((Axis2)(!(a))) // Corners of a rectangle. // 00 ----- 10 // | | // 01 ----- 11 typedef enum Corner { Corner_Invalid = -1, Corner_00, Corner_01, Corner_10, Corner_11, Corner_COUNT } Corner; //////////////////////////////// //~ Member Offset Helper typedef struct MemberOffset MemberOffset; struct MemberOffset { U64 v; }; #define MemberOff(S, member) (MemberOffset){OffsetOf(S, member)} #define MemberOffLit(S, member) {OffsetOf(S, member)} #define MemberFromOff(ptr, type, memoff) (*(type *)((U8 *)ptr + memoff.v)) ///////////////////////// //~ Assertions #if OS_WINDOWS # define break_debugger() __debugbreak() #else # error not implemented #endif #undef Assert #define Assert(b) do { if(!(b)) { break_debugger(); } } while(0) #if !defined(LOG_NOT_IMPLEMENTED) # define LOG_NOT_IMPLEMENTED printf("\nFATAL ERROR: Not implemented yet.\n"); Assert(false); exit(1); #endif ///////////////////////// //~ Bit patterns #define AlignUpToPow2(bytes_to_align, alignment_bytes) (((bytes_to_align) + (alignment_bytes - 1)) & ~(alignment_bytes - 1)) inline_function F32 absolute_value_F32(F32 f) { union { U32 u; F32 f; } x; x.f = f; x.u = x.u & ~SignF32; return x.f; } // TODO(anton): Understand rjf's bit patterns #endif //BASE_TYPES_H