memory arena, allocator struct, os alloc and abort, strings, broken build script
This commit is contained in:
parent
2c9ce97a0e
commit
cbb34b745c
9 changed files with 420 additions and 31 deletions
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
*.exe
|
||||
*.ilk
|
||||
*.obj
|
||||
*.pdb
|
175
bastd.c
175
bastd.c
|
@ -1,6 +1,160 @@
|
|||
#ifndef BASTD_C
|
||||
#define BASTD_C
|
||||
|
||||
////////////////////////////////
|
||||
// NOTE(allen): Context Cracking
|
||||
|
||||
// NOTE(allen): Untangle Compiler, OS & Architecture
|
||||
#if defined(__clang__)
|
||||
# define COMPILER_CLANG 1
|
||||
|
||||
# if defined(_WIN32)
|
||||
# define OS_WINDOWS 1
|
||||
# elif defined(__gnu_linux__)
|
||||
# define OS_LINUX 1
|
||||
# elif defined(__APPLE__) && defined(__MACH__)
|
||||
# define OS_MAC 1
|
||||
# else
|
||||
# error missing OS detection
|
||||
# endif
|
||||
|
||||
# if defined(__amd64__)
|
||||
# define ARCH_X64 1
|
||||
// TODO(allen): verify this works on clang
|
||||
# elif defined(__i386__)
|
||||
# define ARCH_X86 1
|
||||
// TODO(allen): verify this works on clang
|
||||
# elif defined(__arm__)
|
||||
# define ARCH_ARM 1
|
||||
// TODO(allen): verify this works on clang
|
||||
# elif defined(__aarch64__)
|
||||
# define ARCH_ARM64 1
|
||||
# else
|
||||
# error missing ARCH detection
|
||||
# endif
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
# define COMPILER_CL 1
|
||||
|
||||
# if defined(_WIN32)
|
||||
# define OS_WINDOWS 1
|
||||
# else
|
||||
# error missing OS detection
|
||||
# endif
|
||||
|
||||
# if defined(_M_AMD64)
|
||||
# define ARCH_X64 1
|
||||
# elif defined(_M_I86)
|
||||
# define ARCH_X86 1
|
||||
# elif defined(_M_ARM)
|
||||
# define ARCH_ARM 1
|
||||
// TODO(allen): ARM64?
|
||||
# else
|
||||
# error missing ARCH detection
|
||||
# endif
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
# define COMPILER_GCC 1
|
||||
|
||||
# if defined(_WIN32)
|
||||
# define OS_WINDOWS 1
|
||||
# elif defined(__gnu_linux__)
|
||||
# define OS_LINUX 1
|
||||
# elif defined(__APPLE__) && defined(__MACH__)
|
||||
# define OS_MAC 1
|
||||
# else
|
||||
# error missing OS detection
|
||||
# endif
|
||||
|
||||
# if defined(__amd64__)
|
||||
# define ARCH_X64 1
|
||||
# elif defined(__i386__)
|
||||
# define ARCH_X86 1
|
||||
# elif defined(__arm__)
|
||||
# define ARCH_ARM 1
|
||||
# elif defined(__aarch64__)
|
||||
# define ARCH_ARM64 1
|
||||
# else
|
||||
# error missing ARCH detection
|
||||
# endif
|
||||
|
||||
#else
|
||||
# error no context cracking for this compiler
|
||||
#endif
|
||||
|
||||
#if !defined(COMPILER_CL)
|
||||
# define COMPILER_CL 0
|
||||
#endif
|
||||
#if !defined(COMPILER_CLANG)
|
||||
# define COMPILER_CLANG 0
|
||||
#endif
|
||||
#if !defined(COMPILER_GCC)
|
||||
# define COMPILER_GCC 0
|
||||
#endif
|
||||
#if !defined(OS_WINDOWS)
|
||||
# define OS_WINDOWS 0
|
||||
#endif
|
||||
#if !defined(OS_LINUX)
|
||||
# define OS_LINUX 0
|
||||
#endif
|
||||
#if !defined(OS_MAC)
|
||||
# define OS_MAC 0
|
||||
#endif
|
||||
#if !defined(ARCH_X64)
|
||||
# define ARCH_X64 0
|
||||
#endif
|
||||
#if !defined(ARCH_X86)
|
||||
# define ARCH_X86 0
|
||||
#endif
|
||||
#if !defined(ARCH_ARM)
|
||||
# define ARCH_ARM 0
|
||||
#endif
|
||||
#if !defined(ARCH_ARM64)
|
||||
# define ARCH_ARM64 0
|
||||
#endif
|
||||
|
||||
|
||||
// NOTE(allen): Language
|
||||
#if defined(__cplusplus)
|
||||
# define LANG_CXX 1
|
||||
#else
|
||||
# define LANG_C 1
|
||||
#endif
|
||||
|
||||
#if !defined(LANG_CXX)
|
||||
# define LANG_CXX 0
|
||||
#endif
|
||||
#if !defined(LANG_C)
|
||||
# define LANG_C 0
|
||||
#endif
|
||||
|
||||
|
||||
// NOTE(allen): Profiler
|
||||
#if !defined(PROFILER_SPALL)
|
||||
# define PROFILER_SPALL 0
|
||||
#endif
|
||||
|
||||
|
||||
// NOTE(allen): Determine Intrinsics Mode
|
||||
#if OS_WINDOWS
|
||||
# if COMPILER_CL || COMPILER_CLANG
|
||||
# define INTRINSICS_MICROSOFT 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(INTRINSICS_MICROSOFT)
|
||||
# define INTRINSICS_MICROSOFT 0
|
||||
#endif
|
||||
|
||||
|
||||
// NOTE(allen): Setup Pointer Size Macro
|
||||
#if ARCH_X64 || ARCH_ARM64
|
||||
# define ARCH_ADDRSIZE 64
|
||||
#else
|
||||
# define ARCH_ADDRSIZE 32
|
||||
#endif
|
||||
|
||||
// Types
|
||||
#include <stdint.h>
|
||||
|
||||
typedef int8_t I8;
|
||||
|
@ -15,17 +169,34 @@ typedef uint64_t U64;
|
|||
typedef float F32;
|
||||
typedef double F64;
|
||||
|
||||
typedef uintptr_t UPtr;
|
||||
typedef ptrdiff_t ISize;
|
||||
typedef size_t USize;
|
||||
|
||||
typedef U32 B32;
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
// Macros
|
||||
#define FUNCTION static
|
||||
#define GLOBAL_VAR static
|
||||
#define LOCAL_PERSIST static
|
||||
|
||||
#define STMNT(s) do{ s }while(0)
|
||||
|
||||
// TODO: Add Linux Version
|
||||
#define ASSERT(x, msg) STMNT(if (!x) __debugbreak();)
|
||||
#define ASSERT(x, msg) STMNT(if (!x) OS_DEBUGBREAK();)
|
||||
|
||||
#define CONCAT_(a,b) a##b
|
||||
#define CONCAT(a,b) CONCAT_(a,b)
|
||||
|
||||
#define NIL 0
|
||||
|
||||
#define COUNT_OF(a) (ISize)(sizeof(a) / sizeof(*(a)))
|
||||
#define LENGTH_OF(s) (COUNT_OF(s) - 1)
|
||||
|
||||
// Includes
|
||||
#include "bastd/string.c"
|
||||
#include "bastd/os_windows.c"
|
||||
#include "bastd/mem.c"
|
||||
|
||||
#endif //BASTD_C
|
116
bastd/mem.c
Normal file
116
bastd/mem.c
Normal file
|
@ -0,0 +1,116 @@
|
|||
#ifndef BASTD_MEM_C
|
||||
#define BASTD_MEM_C
|
||||
|
||||
FUNCTION void *
|
||||
M_memorySet(void *buffer, U8 value, ISize length)
|
||||
{
|
||||
U8* p = buffer;
|
||||
while (length-- > 0) {
|
||||
*p++ = value;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
FUNCTION void *
|
||||
M_memoryCopy(void *dst, void *src, size_t n)
|
||||
{
|
||||
U8 *s = (U8 *)src;
|
||||
U8 *d = (U8 *)dst;
|
||||
|
||||
for (I32 i = 0; i < n; i++) {
|
||||
d[i] = s[i];
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
/* Alloc function taken from Lua.
|
||||
If ptr == NIL, old_size irrelevant
|
||||
If ptr != NIL, old_size = size of block of memory at ptr
|
||||
If new_size > 0, function like realloc and either resize or create
|
||||
If new_size <= 0, function like free and clear the memory
|
||||
*/
|
||||
typedef void *(*M_AllocFunc)(void *ctx, void *ptr, ISize old_size, ISize new_size);
|
||||
|
||||
typedef struct M_Allocator M_Allocator;
|
||||
struct M_Allocator {
|
||||
M_AllocFunc alloc;
|
||||
void* ctx;
|
||||
};
|
||||
|
||||
#define M_MAKE(T, n, a) ((T *)((a).alloc((a).ctx, NIL, 0, sizeof(T) * n)))
|
||||
#define M_RESIZE(p, o, n, a) ((a).alloc((a).ctx, p, sizeof(*(p)) * o, sizeof(*(p)) * n))
|
||||
#define M_RELEASE(p, s, a) ((a).alloc((a).ctx, p, sizeof(*(p)) * s, 0))
|
||||
|
||||
/* Linear Allocator (Arena)
|
||||
Allocates variably-sized regions from a fixed-size block of memory.
|
||||
A set of regions is freed by setting the allocator's offset to an earlier
|
||||
value.
|
||||
*/
|
||||
typedef struct M_Arena M_Arena;
|
||||
struct M_Arena {
|
||||
U8* beg;
|
||||
U8* end;
|
||||
};
|
||||
|
||||
#define DEFAULT_ALIGNMENT (2 * sizeof(void *))
|
||||
|
||||
FUNCTION void *
|
||||
M_Arena_alloc(void *ctx, void *ptr, ISize old_size, ISize new_size)
|
||||
{
|
||||
M_Arena *a = (M_Arena *)ctx;
|
||||
|
||||
if (new_size <= 0) {
|
||||
/* Arena can only free the most recent block. This allows to follow stack pattern.
|
||||
What we do is move the end pointer forward by the size of the block
|
||||
Then, because there is now more available space, the data will be
|
||||
ignored following the next allocation.
|
||||
*/
|
||||
ISize padding = -old_size & (DEFAULT_ALIGNMENT - 1);
|
||||
a->end += old_size + padding;
|
||||
return NIL;
|
||||
} else {
|
||||
// Allocate a block
|
||||
ASSERT(new_size > old_size, "Can't reallocate to a smaller block");
|
||||
|
||||
ISize padding = -(UPtr)a->beg & (DEFAULT_ALIGNMENT - 1);
|
||||
ISize available = a->end - a->beg - padding;
|
||||
|
||||
if (available < 0 || new_size > available) {
|
||||
OS_Abort(S8("Out of Memory!"));
|
||||
}
|
||||
|
||||
void *p = NIL;
|
||||
|
||||
if (a->beg == (U8 *)ptr + old_size) {
|
||||
// This was the last allocated block, can extend allocation for realloc
|
||||
p = ptr;
|
||||
a->beg += padding + new_size;
|
||||
} else {
|
||||
// New allocation;
|
||||
p = a->beg + padding;
|
||||
a->beg += padding + new_size;
|
||||
p = M_memorySet(p, 0, new_size);
|
||||
|
||||
if (ptr != NIL) {
|
||||
// Arbitrary block, copy data from old pointer
|
||||
p = M_memoryCopy(p, ptr, old_size);
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
FUNCTION M_Arena
|
||||
M_Arena_create(void* buffer, ISize capacity)
|
||||
{
|
||||
M_Arena arena = {0};
|
||||
arena.beg = (U8 *)buffer;
|
||||
arena.end = arena.beg ? arena.beg + capacity : 0;
|
||||
return arena;
|
||||
}
|
||||
|
||||
#define M_ARENA_ALLOCATOR(a) (M_Allocator){M_Arena_alloc, (void *)&(a)}
|
||||
|
||||
#endif//BASTD_MEM_C
|
17
bastd/os.c
Normal file
17
bastd/os.c
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef BASTD_OS_C
|
||||
#define BASTD_OS_C
|
||||
|
||||
FUNCTION void OS_Abort(S8 msg);
|
||||
FUNCTION void *OS_Alloc(ISize cap);
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
|
||||
#include "os_windows.c"
|
||||
|
||||
#elif defined(OS_LINUX)
|
||||
|
||||
#include "os_linux.c"
|
||||
|
||||
#endif//OS_WINDOWS
|
||||
|
||||
#endif//BASTD_OS_C
|
23
bastd/os_windows.c
Normal file
23
bastd/os_windows.c
Normal file
|
@ -0,0 +1,23 @@
|
|||
#ifndef BASTD_OS_WINDOWS_C
|
||||
#define BASTD_OS_WINDOWS_C
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#define OS_DEBUGBREAK() __debugbreak();
|
||||
|
||||
FUNCTION void
|
||||
OS_Abort(S8 msg)
|
||||
{
|
||||
HANDLE stderr = GetStdHandle(-12);
|
||||
U32 dummy;
|
||||
WriteFile(stderr, msg.raw, msg.length, &dummy, 0);
|
||||
ExitProcess(101);
|
||||
}
|
||||
|
||||
FUNCTION void *
|
||||
OS_Alloc(ISize cap)
|
||||
{
|
||||
return VirtualAlloc(NIL, cap, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
}
|
||||
|
||||
#endif//BASTD_OS_WINDOWS_C
|
12
bastd/string.c
Normal file
12
bastd/string.c
Normal file
|
@ -0,0 +1,12 @@
|
|||
#ifndef BASTD_STRING_C
|
||||
#define BASTD_STRING_C
|
||||
|
||||
typedef struct S8 S8;
|
||||
struct S8 {
|
||||
ISize length;
|
||||
U8 *raw;
|
||||
};
|
||||
|
||||
#define S8(s) (S8){(U8 *)s, LENGTH_OF(s)}
|
||||
|
||||
#endif//BASTD_STRING_C
|
8
build.bat
Normal file
8
build.bat
Normal file
|
@ -0,0 +1,8 @@
|
|||
@echo off
|
||||
|
||||
if not exist build\ mkdir build
|
||||
pushd build
|
||||
|
||||
cl /Zi ..\main.c
|
||||
|
||||
popd
|
38
examples/memory.c
Normal file
38
examples/memory.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
int
|
||||
main(void)
|
||||
{
|
||||
ISize buffer_size = 100 * sizeof(U8);
|
||||
M_Arena arena = M_Arena_create(OS_Alloc(buffer_size), buffer_size);
|
||||
M_Allocator permanent_allocator = M_ARENA_ALLOCATOR(arena);
|
||||
|
||||
{
|
||||
/* By cloning an arena at the start of the scope, all changes to the
|
||||
arena are now local to the scope, so all allocations with be freed
|
||||
at the end automatically.
|
||||
*/
|
||||
M_Arena scratch_arena = arena;
|
||||
M_Allocator scratch_allocator = M_ARENA_ALLOCATOR(scratch_arena);
|
||||
|
||||
U8* array = M_MAKE(U8, 20, scratch_allocator);
|
||||
for (int i = 0; i < 20; i++) {
|
||||
array[i] = i;
|
||||
}
|
||||
} // Auto clears here
|
||||
|
||||
OS_DEBUGBREAK();
|
||||
|
||||
U8* array = M_MAKE(U8, 10, permanent_allocator);
|
||||
for (int i = 10; i-- > 0;) {
|
||||
array[10 - i] = i;
|
||||
}
|
||||
OS_DEBUGBREAK();
|
||||
|
||||
array = M_RESIZE(array, 10, 20, permanent_allocator);
|
||||
for (int i = 20; i-- > 0;) {
|
||||
array[20 - i] = i;
|
||||
}
|
||||
OS_DEBUGBREAK();
|
||||
|
||||
M_RELEASE(array, 20, permanent_allocator);
|
||||
OS_DEBUGBREAK();
|
||||
}
|
58
main.c
58
main.c
|
@ -5,16 +5,16 @@
|
|||
Line */
|
||||
|
||||
// "GLOBAL_VAR" macro expands to "static"
|
||||
GLOBAL_VAR F32 evil_number = 666 // variables names use snake_case
|
||||
GLOBAL_VAR F32 evil_number = 666; // variables names use snake_case
|
||||
|
||||
typedef struct RenderVertex RenderVertex; // typedefs come before structs
|
||||
struct RenderVertex { // struct names use PascalCase
|
||||
F32 x, y, z
|
||||
}
|
||||
F32 x, y, z;
|
||||
};
|
||||
|
||||
// Generic pattern. the output type will be "Slice_RenderVertex"
|
||||
#define SLICE_TYPE RenderVertex
|
||||
#include "slice.h"
|
||||
// #define SLICE_TYPE RenderVertex
|
||||
// #include "slice.h"
|
||||
|
||||
// all functions prefixed with "FUNCTION" macro, which expands to "static"
|
||||
FUNCTION I8 // primitive types follow rust style
|
||||
|
@ -29,32 +29,32 @@ addTwo(I8 a, I8 b) // Function names use camelCase
|
|||
defined as "static" , incase you decide to move it to a different
|
||||
compilation unit
|
||||
*/
|
||||
CALLBACK Error
|
||||
start(Slice_S8 args, Buffer stdin, Buffer stdout)
|
||||
{
|
||||
/* all functions that belong to a type or a module are styled
|
||||
"m_TypeName_functionName". "m" is a lower-case shortened version of the
|
||||
module's name (usually 1-3 letters).
|
||||
*/
|
||||
Buffer_appendS8(&stdout, args[0]);
|
||||
Buffer_flush(&stdout);
|
||||
// CALLBACK Error
|
||||
// start(Slice_S8 args, Buffer stdin, Buffer stdout)
|
||||
// {
|
||||
// /* all functions that belong to a type or a module are styled
|
||||
// "m_TypeName_functionName". "m" is a lower-case shortened version of the
|
||||
// module's name (usually 1-3 letters).
|
||||
// */
|
||||
// Buffer_appendS8(&stdout, args[0]);
|
||||
// Buffer_flush(&stdout);
|
||||
|
||||
r_Window window = r_Window_create(1280, 720, "Bastd Example");
|
||||
I32 frame_number = 0;
|
||||
// r_Window window = r_Window_create(1280, 720, "Bastd Example");
|
||||
// I32 frame_number = 0;
|
||||
|
||||
for (!window.should_close) {
|
||||
frame_number += 1;
|
||||
// for (!window.should_close) {
|
||||
// frame_number += 1;
|
||||
|
||||
// if there is no module, function is styled "TypeName_functionName"
|
||||
Buffer_appendS8(&stdout, "Current frame: ");
|
||||
Buffer_appendI32(&stdout, frame_number);
|
||||
Buffer_appendChar(&stdout, '\n');
|
||||
Buffer_flush(&stdout);
|
||||
// // if there is no module, function is styled "TypeName_functionName"
|
||||
// Buffer_appendS8(&stdout, "Current frame: ");
|
||||
// Buffer_appendI32(&stdout, frame_number);
|
||||
// Buffer_appendChar(&stdout, '\n');
|
||||
// Buffer_flush(&stdout);
|
||||
|
||||
r_Window_tick(&window);
|
||||
}
|
||||
// r_Window_tick(&window);
|
||||
// }
|
||||
|
||||
/* Enum names are styled with PascalCase. Enum values are styled
|
||||
"TypeName_value_name"*/
|
||||
return Error_success;
|
||||
}
|
||||
// /* Enum names are styled with PascalCase. Enum values are styled
|
||||
// "TypeName_value_name"*/
|
||||
// return Error_success;
|
||||
// }
|
Loading…
Add table
Reference in a new issue