File Cleanup, removed unused files, and pulled gs_libs into the codebase so that its a standalone codebase

This commit is contained in:
Peter Slattery 2020-01-20 22:56:36 -08:00
parent af11a85e94
commit d23a2a68d4
31 changed files with 5582 additions and 964 deletions

130
gs_libs/gs_bucket.h Normal file
View File

@ -0,0 +1,130 @@
//
// gs_bucket.h - cpp template implementation of a growable, freeable list
// Author: Peter Slattery
// Date: December 30, 2019
//
// The key difference between gs_list.h and gs_bucket.h is that gs_bucket.h keeps everything
// sequential (new elements are appended to the end, free elements are filled in from the end),
// whereas gs_list.h maintiains a free list and deals with holes in the list
template <typename T>
struct gs_bucket_bucket
{
T* Contents;
};
#define GS_LIST_DEFAULT_BUCKET_SIZE 256
template <typename T>
class gs_bucket {
public:
u32 BucketSize;
u32 BucketCount;
gs_bucket_bucket<T>* Buckets;
u32 Used;
gs_bucket();
gs_bucket(u32 BucketSize);
void GrowBucket();
T* GetElementAtIndex(u32 Index);
T* TakeElement();
u32 PushElementOnBucket(T Ele);
void FreeElementAtIndex(u32 Index);
};
template <typename T>
gs_bucket<T>::gs_bucket()
{
this->BucketSize = 0;
this->BucketCount = 0;
this->Buckets = 0;
this->Used = 0;
}
template <typename T>
gs_bucket<T>::gs_bucket(u32 BucketSize)
{
this->BucketSize = BucketSize;
this->BucketCount = 0;
this->Buckets = 0;
this->Used = 0;
}
template <typename T>
void gs_bucket<T>::GrowBucket()
{
if (this->BucketCount == 0)
{
// First Grow Attempt
this->Buckets = 0;
}
if (this->BucketSize == 0)
{
this->BucketSize = GS_LIST_DEFAULT_BUCKET_SIZE;
}
this->BucketCount += 1;
this->Buckets = (gs_bucket_bucket<T>*)realloc(this->Buckets, sizeof(gs_bucket_bucket<T>) * this->BucketCount);
gs_bucket_bucket<T>* NewBucket = this->Buckets + (this->BucketCount - 1);
NewBucket->Contents = (T*)malloc(sizeof(T) * this->BucketSize);
}
template <typename T>
T* gs_bucket<T>::GetElementAtIndex(u32 Index)
{
Assert(Index < this->BucketSize * this->BucketCount);
Assert(Index < this->Used);
u32 BucketIndex = Index / this->BucketSize;
u32 IndexInBucket = Index % this->BucketSize;
T* Result = this->Buckets[BucketIndex].Contents + IndexInBucket;
return Result;
}
template <typename T>
T* gs_bucket<T>::TakeElement()
{
if (this->Used >= this->BucketSize * this->BucketCount)
{
this->GrowBucket();
}
u32 Index = this->Used++;
T* Result = this->GetElementAtIndex(Index);
return Result;
}
template <typename T>
u32 gs_bucket<T>::PushElementOnBucket(T Ele)
{
u32 ResultIndex = 0;
if (this->Used >= this->BucketSize * this->BucketCount)
{
this->GrowBucket();
}
ResultIndex = this->Used++;
T* FreeElement = this->GetElementAtIndex(ResultIndex);
*FreeElement = Ele;
return ResultIndex;
}
template <typename T>
void gs_bucket<T>::FreeElementAtIndex(u32 Index)
{
Assert(Index < this->BucketSize * this->BucketCount);
T* ToFillIn = this->GetElementAtIndex(Index);
T* ToFree = this->GetElementAtIndex(--this->Used);
*ToFillIn = *ToFree;
}

468
gs_libs/gs_language.h Normal file
View File

@ -0,0 +1,468 @@
#ifndef GS_LANGUAGE_H
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__)
#include <intrin.h>
// TODO(Peter): Get rid of math.h
#include <math.h>
#elif defined(__APPLE__) && defined(__MAC__)
// TODO(Peter):
#else // Std lib
#include <stdlib.h>
#endif
#define internal static
#define local_persist static
#define global_variable static
#if !defined(GS_TYPES)
#define GSINT64(s) (s) ## L
#define GSUINT64(s) (s) ## UL
typedef signed char b8;
typedef short int b16;
typedef int b32;
typedef long long int b64;
typedef unsigned char u8;
typedef unsigned short int u16;
typedef unsigned int u32;
typedef unsigned long long int u64;
typedef signed char s8;
typedef short int s16;
typedef int s32;
typedef long long int s64;
typedef float r32;
typedef double r64;
#ifndef _STDINT
#define INT8_MIN (-128)
#define INT16_MIN (-32767-1)
#define INT32_MIN (-2147483647-1)
#define INT64_MIN (-GSINT64(9223372036854775807)-1)
#define INT8_MAX (127)
#define INT16_MAX (32767)
#define INT32_MAX (2147483647)
#define INT64_MAX (GSINT64(9223372036854775807))
#define UINT8_MAX (255)
#define UINT16_MAX (65535)
#define UINT32_MAX (4294967295U)
#define UINT64_MAX (GSUINT64(18446744073709551615))
#endif // _STDINT
#define FLOAT_MIN (1.175494351e-38F)
#define FLOAT_MAX (3.402823466e+38F)
#define DOUBLE_MIN (2.2250738585072014e-308)
#define DOUBLE_MAX (1.7976931348623158e+308)
#define Kilobytes(Value) ((Value) * 1024)
#define Megabytes(Value) (Kilobytes(Value) * 1024)
#define Gigabytes(Value) (Megabytes(Value) * 1024)
#define Terabytes(Value) (Gigabytes(Value) * 1024)
#ifndef PI
#define PI 3.14159265359
#endif
#define TAU 6.2831853071
#define PI_OVER_180 0.01745329251f
#define GS_TYPES
#endif
#ifdef DEBUG
static void DebugPrint(char* Format, ...);
#if !defined(Assert)
// NOTE(peter): this writes to address 0 which is always illegal and will cause a crash
#define Assert(expression) if(!(expression)){ *((int *)0) = 5; }
#endif
#define DEBUG_IF(condition) if (condition)
#define InvalidCodePath Assert(0)
#define InvalidDefaultCase default: { Assert(0); }
#define DebugBreak __debugbreak()
#define STBI_ASSERT(x) Assert(x)
#ifdef GS_TEST_SUTE
#define TestClean(v, c) SuccessCount += Test(v, c, &TestCount)
internal s32
Test(b32 Result, char* Description, s32* Count)
{
char* Passed = (Result ? "Success" : "Failed");
if (!Result)
DebugPrint("%s:\n................................................%s\n\n", Description, Passed);
*Count = *Count + 1;
return (Result ? 1 : 0);
}
#endif // GS_TEST_SUTE
#ifndef GS_LANGUAGE_NO_PROFILER_DEFINES
#ifndef DEBUG_TRACK_SCOPE
#define DEBUG_TRACK_SCOPE(a)
#endif // DEBUG_TRACK_SCOPE
#ifndef DEBUG_TRACK_FUNCTION
#define DEBUG_TRACK_FUNCTION
#endif // DEBUG_TRACK_FUNCTION
#endif // GS_LANGUAGE_NO_PROFILER_DEFINES
#else
#define Assert(expression)
#define InvalidCodePath
#define DEBUG_IF(condition)
#ifndef GS_LANGUAGE_NO_PROFILER_DEFINES
#ifndef DEBUG_TRACK_SCOPE
#define DEBUG_TRACK_SCOPE(a)
#endif // DEBUG_TRACK_SCOPE
#ifndef DEBUG_TRACK_FUNCTION
#define DEBUG_TRACK_FUNCTION
#endif // DEBUG_TRACK_FUNCTION
#endif // GS_LANGUAGE_NO_PROFILER_DEFINES
#endif // DEBUG
#ifndef GS_LANGUAGE_MATH
#define GSArrayLength(arr) (sizeof(arr) / sizeof(arr[0]))
#define GSZeroStruct(data) GSZeroMemory_((u8*)(&(data)), sizeof(data))
#define GSZeroMemory(mem, size) GSZeroMemory_((u8*)(mem), (size))
#define GSZeroArray(arr, type, count) GSZeroMemory_((u8*)(arr), (sizeof(type) * count))
static void
GSZeroMemory_ (u8* Memory, s32 Size)
{
for (int i = 0; i < Size; i++) { Memory[i] = 0; }
}
#define GSMemCopy(from, to, size) GSMemCopy_((u8*)from, (u8*)to, size)
static void
GSMemCopy_ (u8* From, u8* To, s32 Size)
{
for (int i = 0; i < Size; i++) { To[i] = From[i]; }
}
#define GSMemSet(buffer, value, size) GSMemSet_((u8*)buffer, value, size)
internal void
GSMemSet_ (u8* Buffer, u8 Value, s32 Length)
{
u8* Cursor = Buffer;
for (s32 i = 0; i < Length; i++)
{
*Cursor++ = Value;
}
}
#define GSMinDef(type) static type GSMin(type A, type B) { return (A < B ? A : B); }
GSMinDef(s8)
GSMinDef(s16)
GSMinDef(s32)
GSMinDef(s64)
GSMinDef(u8)
GSMinDef(u16)
GSMinDef(u32)
GSMinDef(u64)
GSMinDef(r32)
GSMinDef(r64)
#undef GSMinDef
#define GSMaxDef(type) static type GSMax(type A, type B) { return (A > B ? A : B); }
GSMaxDef(s8)
GSMaxDef(s16)
GSMaxDef(s32)
GSMaxDef(s64)
GSMaxDef(u8)
GSMaxDef(u16)
GSMaxDef(u32)
GSMaxDef(u64)
GSMaxDef(r32)
GSMaxDef(r64)
#undef GSMaxDef
inline b32 XOR(b32 A, b32 B)
{
b32 Result = (A == !B);
return Result;
}
#define GSClampDef(type) static type GSClamp(type Min, type V, type Max) { \
type Result = V; \
if (V < Min) { Result = Min; } \
if (V > Max) { Result = Max; } \
return Result; \
}
GSClampDef(s8)
GSClampDef(s16)
GSClampDef(s32)
GSClampDef(s64)
GSClampDef(u8)
GSClampDef(u16)
GSClampDef(u32)
GSClampDef(u64)
GSClampDef(r32)
GSClampDef(r64)
#undef GSClampDef
#define GSClamp01Def(type) static type GSClamp01(type V) { \
type Min = 0; type Max = 1; \
type Result = V; \
if (V < Min) { Result = Min; } \
if (V > Max) { Result = Max; } \
return Result; \
}
GSClamp01Def(r32)
GSClamp01Def(r64)
#undef GSClamp01Def
#define GSAbsDef(type) static type GSAbs(type A) { return (A < 0 ? -A : A); }
GSAbsDef(s8)
GSAbsDef(s16)
GSAbsDef(s32)
GSAbsDef(s64)
GSAbsDef(r32)
GSAbsDef(r64)
#undef GSAbsDef
#define GSPowDef(type) static type GSPow(type N, s32 Power) { \
type Result = N; \
for(s32 i = 1; i < Power; i++) { Result *= N; } \
return Result; \
}
GSPowDef(s8)
GSPowDef(s16)
GSPowDef(s32)
GSPowDef(s64)
GSPowDef(u8)
GSPowDef(u16)
GSPowDef(u32)
GSPowDef(u64)
GSPowDef(r32)
GSPowDef(r64)
#undef GSPowDef
#define GSLerpDef(type) type GSLerp(type A, type B, type Percent) { return (A * (1.0f - Percent))+(B * Percent);}
GSLerpDef(r32)
GSLerpDef(r64)
#undef GSLerpDef
static r32 GSSqrt(r32 V)
{
r32 Result = _mm_cvtss_f32(_mm_sqrt_ss(_mm_set_ss(V)));
return Result;
}
#if 0
// TODO(Peter): Need a way to split the input into two f32's to supply to _mm_sqrt_sd
static r64 GSSqrt(r64 V)
{
r64 Result = _mm_cvtsd_f64(_mm_sqrt_sd(_mm_set_sd(V)));
return Result;
}
#endif
static r32 DegreesToRadians (r32 Degrees) { return Degrees * PI_OVER_180; }
static r64 DegreesToRadians (r64 Degrees) { return Degrees * PI_OVER_180; }
#define GSIsPowerOfTwoDef(type) static type IsPowerOfTwo(type V) { return (V & (V - 1)) == 0; }
GSIsPowerOfTwoDef(u8);
GSIsPowerOfTwoDef(u16);
GSIsPowerOfTwoDef(u32);
GSIsPowerOfTwoDef(u64);
#undef GSIsPowerOfTwoDef
#define GSIsOddDef(type) inline type IsOdd(type V) { return (V & 1); }
GSIsOddDef(u8);
GSIsOddDef(u16);
GSIsOddDef(u32);
GSIsOddDef(u64);
GSIsOddDef(s8);
GSIsOddDef(s16);
GSIsOddDef(s32);
GSIsOddDef(s64);
#undef GSIsOddDef
#define GSIntDivideRoundUpDef(type) static type IntegerDivideRoundUp (type A, type B) { r32 Result = (r32)A / (r32)B; Result += .99999f; return (type)Result; }
GSIntDivideRoundUpDef(u8);
GSIntDivideRoundUpDef(u16);
GSIntDivideRoundUpDef(u32);
GSIntDivideRoundUpDef(u64);
GSIntDivideRoundUpDef(s8);
GSIntDivideRoundUpDef(s16);
GSIntDivideRoundUpDef(s32);
GSIntDivideRoundUpDef(s64);
#undef GSIntDivideRoundUpDef
#define GSRemapDef(type) \
static type GSRemap(type Value, type OldMin, type OldMax, type NewMin, type NewMax) { \
type Result = (Value - OldMin) / (OldMax - OldMin); \
Result = (Result * (NewMax - NewMin)) + NewMin; \
return Result; \
}
GSRemapDef(u8);
GSRemapDef(u16);
GSRemapDef(u32);
GSRemapDef(u64);
GSRemapDef(s8);
GSRemapDef(s16);
GSRemapDef(s32);
GSRemapDef(s64);
GSRemapDef(r32);
GSRemapDef(r64);
#undef GSRemapDef
static r32
GSFloor(r32 Value)
{
return floor(Value);
}
static r32
GSFract(r32 Value)
{
return Value - GSFloor(Value);
}
static r32
GSModF(r32 Value, r32 Int)
{
r32 Div = Value / Int;
r32 Fract = GSAbs(GSFract(Div));
return Int * Fract;
}
#define GSTrigFunctionDef(name, type, func) static type name(type V) { return func(V); }
GSTrigFunctionDef(GSSin, r32, sinf);
GSTrigFunctionDef(GSSin, r64, sin);
GSTrigFunctionDef(GSCos, r32, cosf);
GSTrigFunctionDef(GSCos, r64, cos);
GSTrigFunctionDef(GSTan, r32, tanf);
GSTrigFunctionDef(GSTan, r64, tan);
#undef GSTrigFunctionDef
static u8
RoundToNearestPowerOfTwo (u8 V)
{
u8 Result = 0;
if (IsPowerOfTwo(V))
{
Result = V;
}
else
{
Result = V - 1;
Result |= Result >> 1;
Result |= Result >> 2;
Result |= Result >> 4;
Result += 1;
}
return Result;
}
static u16
RoundToNearestPowerOfTwo (u16 V)
{
u16 Result = 0;
if (IsPowerOfTwo(V))
{
Result = V;
}
else
{
Result = V - 1;
Result |= Result >> 1;
Result |= Result >> 2;
Result |= Result >> 4;
Result |= Result >> 8;
Result += 1;
}
return Result;
}
static u32
RoundToNearestPowerOfTwo (u32 V)
{
u32 Result = 0;
if (IsPowerOfTwo(V))
{
Result = V;
}
else
{
Result = V - 1;
Result |= Result >> 1;
Result |= Result >> 2;
Result |= Result >> 4;
Result |= Result >> 8;
Result |= Result >> 16;
Result += 1;
}
return Result;
}
static u64
RoundToNearestPowerOfTwo (u64 V)
{
u64 Result = 0;
if (IsPowerOfTwo(V))
{
Result = V;
}
else
{
Result = V - 1;
Result |= Result >> 1;
Result |= Result >> 2;
Result |= Result >> 4;
Result |= Result >> 8;
Result |= Result >> 16;
Result |= Result >> 32;
Result += 1;
}
return Result;
}
#define GS_LANGUAGE_MATH
#endif // GS_LANGUAGE_MATH
static u32
HostToNetU32(u32 In)
{
unsigned char *s = (unsigned char *)&In;
u32 Result = (u32)(s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]);
return Result;
}
static u16
HostToNetU16(u16 In)
{
unsigned char *s = (unsigned char *)&In;
u16 Result = (u16)(s[0] << 8 | s[1]);
return Result;
}
#define GS_LANGUAGE_H
#endif

247
gs_libs/gs_list.h Normal file
View File

@ -0,0 +1,247 @@
//
// gs_list.h - cpp template implementation of a growable, freeable list
// Author: Peter Slattery
// Date: December 30, 2019
//
// The key difference between gs_list.h and gs_bucket.h is that gs_bucket.h keeps everything
// sequential (new elements are appended to the end, free elements are filled in from the end),
// whereas gs_list.h maintiains a free list and deals with holes in the list
struct gs_list_handle
{
// NOTE(Peter): A generation of 0 in a handle denotes an invalid handle
u32 Generation;
u32 Index;
};
#define ListHandleIsInvalid(handle) ((handle).Generation == 0)
#define ListHandleIsValid(handle) ((handle).Generation != 0)
internal b32
GSListHandlesAreEqual(gs_list_handle A, gs_list_handle B)
{
b32 Result = (A.Index == B.Index) && (A.Generation == B.Generation);
return Result;
}
struct gs_free_list
{
u8* NextFreeEntry;
};
template <typename T>
struct gs_list_entry
{
gs_list_handle Handle;
gs_free_list Free;
T Value;
};
#define EntryIsFree(entry) ((entry)->Free.NextFreeEntry != 0)
template <typename T>
struct gs_list_bucket
{
gs_list_entry<T>* Contents;
};
#define GS_LIST_DEFAULT_BUCKET_SIZE 256
template <typename T>
class gs_list {
public:
u32 BucketCapacity;
u32 BucketCount;
gs_list_bucket<T>* Buckets;
gs_list_entry<T> FreeList;
u32 Used;
// NOTE(Peter): this is just here so we can get the next entry which is
// not a part of the free list but is still unused.
// It shouldn't be used outside of the actual list implementation.
u32 OnePastLastUsed;
gs_list();
gs_list(u32 BucketSize);
void GrowList();
gs_list_entry<T>* GetEntryAtIndex(u32 Index);
T* GetElementAtIndex(u32 Index);
T* GetElementWithHandle(gs_list_handle Handle);
gs_list_entry<T>* TakeFreeEntry();
T* TakeElement();
gs_list_handle PushElementOnList(T Ele);
void FreeElementAtIndex(u32 Index);
void FreeElementWithHandle(gs_list_handle Handle);
};
template <typename T>
gs_list<T>::gs_list()
{
this->BucketCapacity = GS_LIST_DEFAULT_BUCKET_SIZE;
this->BucketCount = 0;
this->Buckets = 0;
this->FreeList.Free.NextFreeEntry = (u8*)&this->FreeList;
this->Used = 0;
this->OnePastLastUsed = 0;
}
template <typename T>
gs_list<T>::gs_list(u32 BucketCapacity)
{
this->BucketCapacity = BucketCapacity;
this->BucketCount = 0;
this->Buckets = 0;
this->FreeList.Free.NextFreeEntry = (u8*)&this->FreeList;
this->Used = 0;
this->OnePastLastUsed = 0;
}
template <typename T>
void gs_list<T>::GrowList()
{
if (this->BucketCapacity == 0)
{
this->BucketCapacity = GS_LIST_DEFAULT_BUCKET_SIZE;
}
this->BucketCount += 1;
this->Buckets = (gs_list_bucket<T>*)realloc(this->Buckets, sizeof(gs_list_bucket<T>) * this->BucketCount);
gs_list_bucket<T>* NewBucket = this->Buckets + (this->BucketCount - 1);
NewBucket->Contents = (gs_list_entry<T>*)malloc(sizeof(gs_list_entry<T>) * this->BucketCapacity);
u32 IndexOffset = (this->BucketCount - 1) * this->BucketCapacity;
for (u32 i = 0; i < this->BucketCapacity; i++)
{
NewBucket->Contents[i].Handle.Index = IndexOffset + i;
NewBucket->Contents[i].Handle.Generation = 0;
}
}
template <typename T>
gs_list_entry<T>* gs_list<T>::GetEntryAtIndex(u32 Index)
{
gs_list_entry<T>* Result = 0;
u32 BucketIndex = Index / this->BucketCapacity;
u32 IndexInBucket = Index % this->BucketCapacity;
Assert(BucketIndex < this->BucketCount);
Assert(IndexInBucket < this->BucketCapacity); // this should always be true no matter what
Result = this->Buckets[BucketIndex].Contents + IndexInBucket;
return Result;
}
template <typename T>
T* gs_list<T>::GetElementAtIndex(u32 Index)
{
T* Result = 0;
gs_list_entry<T>* Entry = this->GetEntryAtIndex(Index);
Result = &Entry->Value;
return Result;
}
template <typename T>
T* gs_list<T>::GetElementWithHandle(gs_list_handle Handle)
{
T* Result = 0;
gs_list_entry<T>* Entry = this->GetEntryAtIndex(Handle.Index);
if (Entry->Handle.Generation == Handle.Generation)
{
Result = &Entry->Value;
}
return Result;
}
template <typename T>
gs_list_entry<T>* gs_list<T>::TakeFreeEntry()
{
gs_list_entry<T>* FreeEntry = (gs_list_entry<T>*)this->FreeList.Free.NextFreeEntry;
if (FreeEntry == 0 || this->BucketCapacity == 0 || this->BucketCount == 0)
{
this->FreeList.Free.NextFreeEntry = (u8*)&this->FreeList;
FreeEntry = (gs_list_entry<T>*)this->FreeList.Free.NextFreeEntry;
}
this->FreeList.Free.NextFreeEntry = FreeEntry->Free.NextFreeEntry;
if (FreeEntry == &this->FreeList)
{
if (this->Used >= this->BucketCapacity * this->BucketCount)
{
this->GrowList();
}
FreeEntry = this->GetEntryAtIndex(this->OnePastLastUsed++);
}
Assert(FreeEntry != 0);
FreeEntry->Handle.Generation++;
FreeEntry->Free.NextFreeEntry = 0;
this->Used++;
return FreeEntry;
}
template <typename T>
T* gs_list<T>::TakeElement()
{
T* Result = 0;
gs_list_entry<T>* FreeEntry = this->TakeFreeEntry();
Result = &FreeEntry->Value;
return Result;
}
template <typename T>
gs_list_handle gs_list<T>::PushElementOnList(T Ele)
{
gs_list_handle Result = {0};
gs_list_entry<T>* FreeEntry = this->TakeFreeEntry();
FreeEntry->Value = Ele;
Result = FreeEntry->Handle;
return Result;
}
template <typename T>
void gs_list<T>::FreeElementAtIndex(u32 Index)
{
Assert(Index < this->BucketCapacity * this->BucketCount);
gs_list_entry<T>* EntryToFree = this->GetEntryAtIndex(Index);
// If the entry has a value in NextFreeEntry, then it is already free
Assert(EntryToFree->Free.NextFreeEntry == 0);
EntryToFree->Free.NextFreeEntry = this->FreeList.Free.NextFreeEntry;
this->FreeList.Free.NextFreeEntry = (u8*)EntryToFree;
this->Used--;
}
template <typename T>
void gs_list<T>::FreeElementWithHandle(gs_list_handle Handle)
{
Assert(Handle.Index < this->BucketCapacity * this->BucketCount);
gs_list_entry<T>* EntryToFree = this->GetEntryAtIndex(Handle.Index);
// If the entry has a value in NextFreeEntry, then it is already free
Assert(EntryToFree->Free.NextFreeEntry == 0);
if (EntryToFree->Handle.Generation == Handle.Generation)
{
EntryToFree->Free.NextFreeEntry = this->FreeList.Free.NextFreeEntry;
this->FreeList.Free.NextFreeEntry = (u8*)EntryToFree;
this->Used--;
}
}

614
gs_libs/gs_memory_arena.h Normal file
View File

@ -0,0 +1,614 @@
// File: gs_memory_arena.h
// Description: Single header file library that defines a push-only memory arena
// Author: Peter Slattery
// Date Created: 2019-12-22
//
//
// -----------------
// Set Up
// -----------------
//
// Include 'gs_memory_arena.h' in a file and start using it! (Simple! Nice!)
//
// -----------------
// Usage
// -----------------
// Simply create a memory_arena and use PushSize, PushStruct, or PushArray
// to allocate out of it.
// See Example Program below.
//
// While there are options you can set (see Options below), the library adheres
// to a 'zero-is-initialization' policy, that is, a memory_arena initialized to
// zero, under all default options, will 'just work'.
//
// Alignment:
// By default, the Push functions use 4 byte alignment
// If you need to control the alignment of an allocation, there are variants of the
// Push functions that allow for this: PushSizeAligned, PushStructAligned, and PushArrayAligned
// These functions simply take a final parameter which specifies the alignment.
// Note: Alignment must be a power of two
//
// -----------------
// Options
// -----------------
//
// DEBUG:
// Define DEBUG for debug functionality.
//
// To override the default assert function define GSMem_Assert(expression)
// before inluding this file.
//
// GS_MEMORY_NO_STD_LIBS:
// if you don't want stdlib.h to be included, define GS_MEMORY_NO_STD_LIBS
// before including this file.
// Note that if you do this, zero-is-initialization will no longer work for
// memory_arenas. You must either:
// 1. Set each memory_arena's Alloc and Realloc so they can grow fields
// 2. Set each memory_arena's ExpansionRule to ExpansionRule_Disallowed
// If DEBUG is defined, the program will assert if one of the 2 rules above
// aren't followed.
//
// memory_arena.Alloc and memory_arena.Realloc
// By default, memory_arena's will use malloc and realloc to grow.
// You can override this by setting the Alloc and Realloc function pointers
// of a memory_arena. See the example program below for an implementation of this.
//
// GS_MEMORY_BUFFER_SIZE:
// This defines the minimum buffer size for memory_arena's. If an arena doesn't have
// room to fit an allocation, it will allocate a new buffer no smaller than GS_MEMORY_BUFFER_SIZE
// and place the allocation in the new buffer.
// By default this is 4096 bytes. To override, define GS_MEMORY_BUFFER_SIZE before including
// this file
//
// GS_MEMORY_TRACK_ALLOCATIONS:
// If you want to keep records of each allocation performed in every arena, define
// GS_MEMORY_TRACK_ALLOCATIONS before including this file.
// When defined, memory arenas gain fields that allow them to keep a list of every
// allocation they contain. It also adds a footer on the end of each allocation that
// can be checked to ensure there are no writes to allocations that overflow their bounds
// Note that calling ClearArena also clears this list
// You can then call AssertAllocationsNoOverflow occasionally throughout your program
// to check that no allocations have been written beyond their boundaries
//
//
// Example Program
// (this compiles - copy it into its own file though)
#if 0
// #include "gs_memory_arena.h"
// Places the characters 'gs' at the end of each allocation. This would allow for an external
// function to check that we haven't written past the end of an allocation
void* MallocWrapper(gs_mem_u32 Size)
{
int SizeWithFooter = Size + (sizeof(char) * 2);
void* Result = malloc(SizeWithFooter);
char* Footer = (char*)(Result + Size);
Footer[0] = 'g';
Footer[1] = 's';
return Result;
}
void* ReallocWrapper(void* Address, gs_mem_u32 Size)
{
return realloc(Address, Size);
}
int
main(int ArgCount, char** Args)
{
memory_arena Arena = {};
// Uncomment these lines for an example of how you can implement custom allocation functions
// Arena.Alloc = MallocWrapper;
// Arena.Realloc = ReallocWrapper;
int ArrayLength = 10;
int* A = PushArray(&Arena, int, ArrayLength);
int* B = PushArray(&Arena, int, ArrayLength);
int* C = PushArray(&Arena, int, ArrayLength);
int* D = PushArrayAligned(&Arena, int, ArrayLength, 8);
int* E = PushArrayAligned(&Arena, int, ArrayLength, 16);
// Just ensure that we can actually write to each address of each array
for (s32 i = 0; i < ArrayLength; i++)
{
A[i] = i;
B[i] = i;
C[i] = i;
D[i] = i;
E[i] = i;
}
ClearArena(&Arena);
A = PushArray(&Arena, int, ArrayLength);
for (s32 i = 0; i < ArrayLength; i++)
{
A[i] = i;
}
return 0;
}
#endif
// -------------------
// Begin Library
// -------------------
#ifndef GS_MEMORY_ARENA_H
#ifndef GS_MEMORY_NO_STD_LIBS
// NOTE(Peter): We use this so that we can fall back on malloc and realloc
// in the event that a memory_arena needs to grow but doesn't have a
// alloc or realloc function pointer assigned to it.
//
// See GrowArena to see where this is used
//
#include <stdlib.h>
#endif
typedef unsigned char gs_mem_u8;
typedef unsigned int gs_mem_u32;
typedef unsigned long long int gs_mem_u64;
#ifdef DEBUG
#if !defined(GSMem_Assert)
#define GSMem_Assert(expression) \
if(!(expression)) { \
*((int *)0) = 5; \
}
#endif
#else
#define GSMem_Assert(expression)
#endif
enum gs_memory_expansion_rule
{
MemoryExpansion_Allowed, // Zero is initialization lets the memory grow on its own
MemoryExpansion_OnlyIfFunctionsProvided,
MemoryExpansion_Disallowed,
MemoryExpansion_Count,
};
// NOTE(Peter):
// This rule is only here to allow for taking arena snapshots. The problem this solves
// is if you take a snapshot while there are 'holes' in memory_buffers behind the
// most recently added memory_buffer, take a snapshot of that arena, then push something
// on that fits in one of those holes, we will fill the hole and be unable to track/free
// that addition via the snapshot construct.
//
// By requiring that allocations in a buffer only come from the most recent memory_buffer
// we can very easily rewind the buffer to the correct location.
// Hence FindAddress_InLastBufferOnly
enum gs_memory_find_address_rule
{
FindAddress_InAnyBuffer,
FindAddress_InLastBufferOnly,
FindAddress_Count,
};
typedef void* gs_memory_alloc(gs_mem_u32 Size);
typedef void* gs_memory_realloc(void* Address, gs_mem_u32 OldSize, gs_mem_u32 NewSize);
typedef void gs_memory_free(void* Address, gs_mem_u32 Size);
#ifndef GS_MEMORY_BUFFER_SIZE
#define GS_MEMORY_BUFFER_SIZE 1024
#endif
#define GS_MEMORY_FOOTER_SIZE 4
#define GS_MEMORY_FOOTER_0 'g'
#define GS_MEMORY_FOOTER_1 's'
#define GS_MEMORY_FOOTER_2 'p'
#define GS_MEMORY_FOOTER_3 's'
struct tracked_allocation
{
gs_mem_u8* Head;
gs_mem_u8* Footer;
char* File;
gs_mem_u32 LineNumber;
};
#define GS_MEM_TRACKED_ALLOCATION_BUFFER_SIZE 512
struct tracked_allocation_buffer
{
tracked_allocation Buffer[GS_MEM_TRACKED_ALLOCATION_BUFFER_SIZE];
};
struct memory_buffer
{
gs_mem_u8* Buffer;
gs_mem_u32 Size;
gs_mem_u32 Used;
};
struct memory_arena
{
memory_buffer* Buffers;
gs_mem_u32 BuffersCount;
gs_mem_u32 TotalUsed;
gs_mem_u32 TotalSize;
gs_memory_find_address_rule FindAddressRule;
gs_memory_expansion_rule ExpansionRule;
gs_memory_alloc* Alloc;
gs_memory_realloc* Realloc;
#ifdef GS_MEMORY_TRACK_ALLOCATIONS
tracked_allocation_buffer** AllocationBuffers;
gs_mem_u32 AllocationBuffersCount;
gs_mem_u32 AllocationsUsed;
#endif
};
struct address_and_buffer
{
memory_buffer* Buffer;
gs_mem_u64 Address;
gs_mem_u32 SizeWithAlignment;
};
struct arena_snapshot
{
gs_mem_u32 ArenaUsedAtSnapshot;
gs_mem_u32 HeadBufferUsedAtSnapshot;
gs_mem_u32 HeadBufferAtSnapshot;
memory_arena* Arena;
#ifdef GS_MEMORY_TRACK_ALLOCATIONS
gs_mem_u32 AllocationsUsedAtSnapshot;
#endif
};
static void
FreeMemoryArena(memory_arena* Arena, gs_memory_free* Free = 0)
{
if (Free)
{
for (gs_mem_u32 i = 0; i < Arena->BuffersCount; i++)
{
memory_buffer* Buffer = Arena->Buffers + i;
Free(Buffer->Buffer, Buffer->Size);
}
Free(Arena->Buffers, sizeof(memory_buffer) * Arena->BuffersCount);
}
else
{
#ifdef GS_MEMORY_NO_STD_LIBS
GSMem_Assert(0);
#else
for (gs_mem_u32 i = 0; i < Arena->BuffersCount; i++)
{
memory_buffer* Buffer = Arena->Buffers + i;
free(Buffer->Buffer);
}
free(Arena->Buffers);
#endif
}
}
#define IsPowerOfTwo(v) ((v != 0) && ((v & (v - 1)) == 0))
inline gs_mem_u32
GetAlignmentOffset (gs_mem_u64 Address, gs_mem_u32 Alignment, gs_mem_u32 AlignmentMask)
{
gs_mem_u32 AlignmentOffset = 0;
if (Address & AlignmentMask)
{
AlignmentOffset = Alignment - (Address & AlignmentMask);
}
return AlignmentOffset;
}
static address_and_buffer
GetAlignedAddressInBuffer(memory_buffer* Buffer, gs_mem_u32 Size, gs_mem_u32 Alignment, gs_mem_u32 AlignmentMask)
{
address_and_buffer Result = {};
gs_mem_u64 HeadAddress = (gs_mem_u64)Buffer->Buffer + Buffer->Used;
gs_mem_u32 AlignmentOffset = GetAlignmentOffset(HeadAddress, Alignment, AlignmentMask);
gs_mem_u64 AlignedAddress = HeadAddress + AlignmentOffset;
if (Buffer->Used + AlignmentOffset + Size <= Buffer->Size)
{
Result.Buffer = Buffer;
Result.Address = AlignedAddress;
Result.SizeWithAlignment = Size + AlignmentOffset;
}
return Result;
}
static address_and_buffer
FindAlignedAddressInBufferWithRoom(memory_arena* Arena, gs_mem_u32 Size, gs_mem_u32 Alignment, gs_mem_u32 AlignmentMask)
{
address_and_buffer Result = {};
for (gs_mem_u32 i = 0; i < Arena->BuffersCount; i++)
{
memory_buffer* At = Arena->Buffers + i;
GSMem_Assert(At);
address_and_buffer AddressInCurrentBuffer = GetAlignedAddressInBuffer(At, Size, Alignment, AlignmentMask);
if (AddressInCurrentBuffer.Address != 0)
{
Result = AddressInCurrentBuffer;
break;
}
}
return Result;
}
static gs_mem_u8*
ArenaAlloc(memory_arena* Arena, gs_mem_u32 Size)
{
gs_mem_u8* Result = 0;
if (Arena->Alloc)
{
Result = (gs_mem_u8*)Arena->Alloc(sizeof(gs_mem_u8) * Size);
}
else
{
#ifdef GS_MEMORY_NO_STD_LIBS
// NOTE(Peter): If you specify no std libs AND don't supply a allocation function
// we should assert as this is an invalid codepath
GSMem_Assert(0);
#else
Result = (gs_mem_u8*)malloc(sizeof(gs_mem_u8) * Size);
#endif
}
return Result;
}
static gs_mem_u8*
ArenaRealloc(memory_arena* Arena, gs_mem_u8* Head, gs_mem_u32 OldSize, gs_mem_u32 NewSize)
{
gs_mem_u8* Result = 0;
if (Arena->Realloc != 0)
{
Result = (gs_mem_u8*)Arena->Realloc(Head, OldSize, NewSize);
}
else
{
#ifdef GS_MEMORY_NO_STD_LIBS
// NOTE(Peter): If you specify no std libs AND don't supply a reallocation function
// we should assert as this is an invalid codepath
GSMem_Assert(0);
#else
Result = (gs_mem_u8*)realloc(Head, NewSize);
#endif
}
return Result;
}
static memory_buffer*
GrowArena(memory_arena* Arena, gs_mem_u32 SizeNeeded)
{
GSMem_Assert(Arena->ExpansionRule != MemoryExpansion_Disallowed);
if (Arena->ExpansionRule == MemoryExpansion_OnlyIfFunctionsProvided)
{
GSMem_Assert((Arena->Alloc != 0) && (Arena->Realloc != 0));
}
gs_mem_u32 NewBuffersCount = (Arena->BuffersCount + 1);
gs_mem_u32 OldBuffersSize = sizeof(memory_buffer) * Arena->BuffersCount;
gs_mem_u32 NewBuffersSize = sizeof(memory_buffer) * NewBuffersCount;
Arena->Buffers = (memory_buffer*)ArenaRealloc(Arena, (gs_mem_u8*)Arena->Buffers, OldBuffersSize, NewBuffersSize);
Arena->BuffersCount = NewBuffersCount;
memory_buffer* NewBuffer = Arena->Buffers + (Arena->BuffersCount - 1);
NewBuffer->Size = GS_MEMORY_BUFFER_SIZE;
if (SizeNeeded > NewBuffer->Size)
{
NewBuffer->Size = SizeNeeded;
}
NewBuffer->Buffer = ArenaAlloc(Arena, sizeof(gs_mem_u8) * NewBuffer->Size);
NewBuffer->Used = 0;
Arena->TotalSize += NewBuffer->Size;
return NewBuffer;
}
#ifdef GS_MEMORY_TRACK_ALLOCATIONS
#define DetermineAllocationSize(size) (size) + GS_MEMORY_FOOTER_SIZE
#define ClearAllocationsUsed(arena) (arena)->AllocationsUsed = 0
#define ClearAllocationsUsedToSnapshot(arena, snapshot) \
(arena)->AllocationsUsed = (snapshot).AllocationsUsedAtSnapshot;
static void
TrackAllocation(memory_arena* Arena, gs_mem_u8* Head, gs_mem_u32 Size, char* Filename, gs_mem_u32 LineNumber)
{
gs_mem_u32 AllocationsMax = Arena->AllocationBuffersCount * GS_MEM_TRACKED_ALLOCATION_BUFFER_SIZE;
if (Arena->AllocationsUsed >= AllocationsMax)
{
gs_mem_u32 NewAllocationBuffersCount = Arena->AllocationBuffersCount + 1;
Arena->AllocationBuffers = (tracked_allocation_buffer**)ArenaRealloc(Arena,
(gs_mem_u8*)Arena->AllocationBuffers,
Arena->AllocationBuffersCount * sizeof(void*),
NewAllocationBuffersCount * sizeof(void*));
Arena->AllocationBuffersCount = NewAllocationBuffersCount;
gs_mem_u32 NewBufferIndex = Arena->AllocationBuffersCount - 1;
Arena->AllocationBuffers[NewBufferIndex] = (tracked_allocation_buffer*)ArenaAlloc(Arena, sizeof(tracked_allocation_buffer));
}
gs_mem_u32 AllocationIndex = Arena->AllocationsUsed++;
gs_mem_u32 BufferIndex = AllocationIndex / GS_MEM_TRACKED_ALLOCATION_BUFFER_SIZE;
gs_mem_u32 IndexInBuffer = AllocationIndex % GS_MEM_TRACKED_ALLOCATION_BUFFER_SIZE;
tracked_allocation_buffer* Buffer = Arena->AllocationBuffers[BufferIndex];
tracked_allocation* NewAllocationTracker = Buffer->Buffer + IndexInBuffer;
NewAllocationTracker->Head = Head;
NewAllocationTracker->Footer = Head + Size - GS_MEMORY_FOOTER_SIZE;
NewAllocationTracker->Footer[0] = GS_MEMORY_FOOTER_0;
NewAllocationTracker->Footer[1] = GS_MEMORY_FOOTER_1;
NewAllocationTracker->Footer[2] = GS_MEMORY_FOOTER_2;
NewAllocationTracker->Footer[3] = GS_MEMORY_FOOTER_3;
NewAllocationTracker->File = Filename;
NewAllocationTracker->LineNumber = LineNumber;
}
inline bool
VerifyAllocationNoOverflow (tracked_allocation Allocation)
{
bool Result = ((Allocation.Footer[0] == GS_MEMORY_FOOTER_0) &&
(Allocation.Footer[1] == GS_MEMORY_FOOTER_1) &&
(Allocation.Footer[2] == GS_MEMORY_FOOTER_2) &&
(Allocation.Footer[3] == GS_MEMORY_FOOTER_3));
return Result;
}
static void
AssertAllocationsNoOverflow (memory_arena Arena)
{
for (gs_mem_u32 AllocationIndex = 0;
AllocationIndex< Arena.AllocationsUsed;
AllocationIndex++)
{
gs_mem_u32 BufferIndex = AllocationIndex / GS_MEM_TRACKED_ALLOCATION_BUFFER_SIZE;
gs_mem_u32 IndexInBuffer = AllocationIndex % GS_MEM_TRACKED_ALLOCATION_BUFFER_SIZE;
tracked_allocation_buffer* Buffer = Arena.AllocationBuffers[BufferIndex];
tracked_allocation Allocation = Buffer->Buffer[IndexInBuffer];
GSMem_Assert(VerifyAllocationNoOverflow(Allocation));
}
}
#define PushSize(arena, size) PushSize_((arena), (size), 4, __FILE__, __LINE__)
#define PushArray(arena, type, length) (type*)PushSize_((arena), sizeof(type) * length, 4, __FILE__, __LINE__)
#define PushStruct(arena, type) (type*)PushSize_((arena), sizeof(type), 4, __FILE__, __LINE__)
#define PushSizeAligned(arena, size, alignment) PushSize_((arena), (size), (alignment), __FILE__, __LINE__)
#define PushArrayAligned(arena, type, length, alignment) (type*)PushSize_((arena), sizeof(type) * length, (alignment), __FILE__, __LINE__)
#define PushStructAligned(arena, type, alignment) (type*)PushSize_((arena), sizeof(type), (alignment), __FILE__, __LINE__)
#else // GS_MEMORY_TRACK_ALLOCATIONS
#define AssertAllocationsNoOverflow(arena)
#define DetermineAllocationSize(size) size
#define ClearAllocationsUsed(arena)
#define ClearAllocationsUsedToSnapshot(arena, snapshot)
#define TrackAllocation(arena, head, size, filename, linenumber)
#define PushSize(arena, size) PushSize_((arena), (size))
#define PushArray(arena, type, length) (type*)PushSize_((arena), sizeof(type) * length)
#define PushStruct(arena, type) (type*)PushSize_((arena), sizeof(type))
#define PushSizeAligned(arena, size, alignment) PushSize_((arena), (size), (alignment))
#define PushArrayAligned(arena, type, length, alignment) (type*)PushSize_((arena), sizeof(type) * length, (alignment))
#define PushStructAligned(arena, type, alignment) (type*)PushSize_((arena), sizeof(type), (alignment))
#endif // GS_MEMORY_TRACK_ALLOCATIONS
static gs_mem_u8*
PushSize_(memory_arena* Arena, gs_mem_u32 Size, gs_mem_u32 Alignment = 4, char* Filename = 0, gs_mem_u32 LineNumber = 0)
{
// ie. Alignment = 4 = 100 (binary)
// 4 - 1 = 3
// 100 - 1 = 011 which is a mask of the bits we don't want set in the start address
GSMem_Assert(IsPowerOfTwo(Alignment));
gs_mem_u32 AlignmentMask = Alignment - 1;
gs_mem_u32 AllocationSize = DetermineAllocationSize(Size);
address_and_buffer ResultAddress = {};
if (Arena->FindAddressRule == FindAddress_InAnyBuffer)
{
ResultAddress = FindAlignedAddressInBufferWithRoom(Arena, AllocationSize, Alignment, AlignmentMask);
}
else if (Arena->FindAddressRule == FindAddress_InLastBufferOnly
&& Arena->BuffersCount > 0)
{
memory_buffer* LastBuffer = Arena->Buffers + Arena->BuffersCount - 1;
ResultAddress = GetAlignedAddressInBuffer(LastBuffer, Size, Alignment, AlignmentMask);
}
if (ResultAddress.Address == 0)
{
memory_buffer* Buffer = GrowArena(Arena, AllocationSize);
ResultAddress = GetAlignedAddressInBuffer(Buffer, AllocationSize, Alignment, AlignmentMask);
}
GSMem_Assert(ResultAddress.Address != 0);
GSMem_Assert((ResultAddress.Address & AlignmentMask) == 0);
gs_mem_u8* Result = (gs_mem_u8*)ResultAddress.Address;
ResultAddress.Buffer->Used += ResultAddress.SizeWithAlignment;
Arena->TotalUsed += ResultAddress.SizeWithAlignment;
TrackAllocation(Arena, Result, AllocationSize, Filename, LineNumber);
return Result;
}
static void
ClearArena(memory_arena* Arena)
{
for (gs_mem_u32 i = 0; i < Arena->BuffersCount; i++)
{
memory_buffer* At = Arena->Buffers + i;
At->Used = 0;
}
Arena->TotalUsed = 0;
ClearAllocationsUsed(Arena);
}
static arena_snapshot
TakeSnapshotOfArena(memory_arena* Arena)
{
Assert(Arena->FindAddressRule == FindAddress_InLastBufferOnly);
arena_snapshot Result = {};
Result.Arena = Arena;
Result.ArenaUsedAtSnapshot = Arena->TotalUsed;
if (Arena->BuffersCount > 0)
{
Result.HeadBufferAtSnapshot = Arena->BuffersCount - 1;
}
else
{
Result.HeadBufferAtSnapshot = 0;
}
memory_buffer* HeadBuffer = Arena->Buffers + Result.HeadBufferAtSnapshot;
if (HeadBuffer)
{
Result.HeadBufferUsedAtSnapshot = HeadBuffer->Used;
}
return Result;
}
static void
ClearArenaToSnapshot(memory_arena* Arena, arena_snapshot Snapshot)
{
Assert(Arena == Snapshot.Arena);
memory_buffer* HeadBufferAtSnapshot = Arena->Buffers + Snapshot.HeadBufferAtSnapshot;
if (HeadBufferAtSnapshot)
{
HeadBufferAtSnapshot->Used = Snapshot.HeadBufferUsedAtSnapshot;
for (gs_mem_u32 i = Snapshot.HeadBufferAtSnapshot + 1; i < Arena->BuffersCount; i++)
{
memory_buffer* Buffer = Arena->Buffers + i;
Buffer->Used = 0;
}
}
Arena->TotalUsed = Snapshot.ArenaUsedAtSnapshot;
ClearAllocationsUsedToSnapshot(Arena, Snapshot);
}
#define GS_MEMORY_ARENA_H
#endif // GS_MEMORY_ARENA_H

81
gs_libs/gs_radix_sort.h Normal file
View File

@ -0,0 +1,81 @@
/*
gs_radix_sort.h - An implementation of radix sort for fixed size unsigned 32bit integer buffers
TODO
*/
#ifndef GS_RADIX_SORT_H
#ifdef DEBUG
#if !defined(GSRad_Assert)
#define GSRad_Assert(expression) \
if(!(expression)) { \
*((int *)0) = 5; \
}
#endif // !defined(GSRad_Assert)
#endif // DEBUG
typedef unsigned int gs_rad_u32;
typedef unsigned int gs_rad_b32;
struct gs_radix_entry
{
gs_rad_u32 Radix;
gs_rad_u32 ID;
};
static void
RadixSortInPlace_ (gs_radix_entry* Data, gs_rad_u32 Start, gs_rad_u32 End, gs_rad_u32 Iteration)
{
gs_rad_u32 Shift = Iteration;
gs_rad_u32 ZerosBoundary = Start;
gs_rad_u32 OnesBoundary = End - 1;
for (gs_rad_u32 d = Start; d < End; d++)
{
gs_radix_entry Entry = Data[ZerosBoundary];
gs_rad_u32 Place = (Entry.Radix >> Shift) & 0x1;
if (Place)
{
gs_radix_entry Evicted = Data[OnesBoundary];
Data[OnesBoundary] = Entry;
Data[ZerosBoundary] = Evicted;
OnesBoundary -= 1;
}
else
{
ZerosBoundary += 1;
}
}
if (Iteration > 0)
{
RadixSortInPlace_(Data, Start, ZerosBoundary, Iteration - 1);
RadixSortInPlace_(Data, ZerosBoundary, End, Iteration - 1);
}
}
static void
RadixSortInPlace (gs_radix_entry* Data, gs_rad_u32 Count)
{
gs_rad_u32 Highest = 0;
for (gs_rad_u32 i = 0; i < Count; i++)
{
if (Data[i].Radix > Highest)
{
Highest = Data[i].Radix;
}
}
gs_rad_u32 Iterations = 0;
while (Highest > 1)
{
++Iterations;
Highest = Highest >> 1;
}
RadixSortInPlace_(Data, 0, Count, Iterations);
}
#define GS_RADIX_SORT_H
#endif // GS_RADIX_SORT_H

2390
gs_libs/gs_string.h Normal file

File diff suppressed because it is too large Load Diff

104
gs_libs/gs_string_builder.h Normal file
View File

@ -0,0 +1,104 @@
//
// File: gs_string_builder.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef GS_STRING_BUILDER_H
#ifndef GS_STRING_BUILDER_NO_STDIO
#include <stdio.h>
#endif
#define STRING_BUILDER_BUFFER_CAPACITY 4096
struct string_builder_buffer
{
u8* BufferMemory;
string String;
string_builder_buffer* Next;
};
struct string_builder
{
string_builder_buffer* Buffers;
string_builder_buffer* Head;
};
internal void
GrowStringBuilder(string_builder* StringBuilder)
{
u8* BufferAndHeader = (u8*)malloc(sizeof(string_builder_buffer) + STRING_BUILDER_BUFFER_CAPACITY);
string_builder_buffer* NewBuffer = (string_builder_buffer*)BufferAndHeader;
*NewBuffer = {0};
NewBuffer->BufferMemory = (u8*)(NewBuffer + 1);
NewBuffer->String = MakeString((char*)NewBuffer->BufferMemory, 0, STRING_BUILDER_BUFFER_CAPACITY);
if (!StringBuilder->Buffers)
{
StringBuilder->Buffers = NewBuffer;
StringBuilder->Head = NewBuffer;
}
else
{
StringBuilder->Head->Next = NewBuffer;
StringBuilder->Head = NewBuffer;
}
}
internal void
Write(string Text, string_builder* StringBuilder)
{
string TextLeft = Text;
if (StringBuilder->Buffers == 0)
{
GrowStringBuilder(StringBuilder);
}
while (TextLeft.Length > 0)
{
// Copy what there is room for
s32 SpaceAvailable = StringBuilder->Head->String.Max - StringBuilder->Head->String.Length;
ConcatString(TextLeft, GSMin(SpaceAvailable, TextLeft.Length), &StringBuilder->Head->String);
TextLeft.Memory += SpaceAvailable;
TextLeft.Length -= SpaceAvailable;
if (TextLeft.Length > 0)
{
GrowStringBuilder(StringBuilder);
}
}
}
internal void
WriteF(string_builder* StringBuilder, char* Format, ...)
{
MakeStringBuffer(Buffer, 256);
va_list Args;
va_start(Args, Format);
Buffer.Length = PrintFArgsList(Buffer.Memory, Buffer.Max, Format, Args);
va_end(Args);
Write(Buffer, StringBuilder);
}
#ifndef GS_STRING_BUILDER_NO_STDIO
internal void
WriteStringBuilderToFile(string_builder StringBuilder, FILE* WriteFile)
{
string_builder_buffer* BufferAt = StringBuilder.Buffers;
while (BufferAt)
{
string String = BufferAt->String;
fwrite(String.Memory, 1, String.Length, WriteFile);
BufferAt = BufferAt->Next;
}
}
#endif // GS_STRING_BUILDER_NO_STDIO
#define GS_STRING_BUILDER_H
#endif // GS_STRING_BUILDER_H

1493
gs_libs/gs_vector_matrix.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -16,7 +16,7 @@ set CommonLinkerFlags= -opt:ref
pushd build pushd build
cl %CommonCompilerFlags% -IC:\programs-dev\gs_libs\src ..\meta\foldhaus_meta.cpp /link %CommonLinkerFlags% cl %CommonCompilerFlags% ..\meta\foldhaus_meta.cpp /link %CommonLinkerFlags%
C:\programs\ctime\ctime.exe -end C:\projects\foldhaus\build\win32_gs_meta_build_time.ctm %LastError% C:\programs\ctime\ctime.exe -end C:\projects\foldhaus\build\win32_gs_meta_build_time.ctm %LastError%
C:\programs\ctime\ctime.exe -stats C:\projects\foldhaus\build\win32_gs_meta_build_time.ctm C:\programs\ctime\ctime.exe -stats C:\projects\foldhaus\build\win32_gs_meta_build_time.ctm

View File

@ -24,14 +24,17 @@ int main(int ArgCount, char* Args[])
FinishGeneratingTypes(&TypeGenerator); FinishGeneratingTypes(&TypeGenerator);
gsm_code_generator NodeTypeGen = BeginEnumGeneration("node_type", "NodeType", false, true); gsm_code_generator NodeTypeGen = BeginEnumGeneration("node_type", "NodeType", false, true);
#if 0
// TODO(Peter): Create a FilterTypesByTag function to create a contiguous array // TODO(Peter): Create a FilterTypesByTag function to create a contiguous array
// of type_definition** // of type_definition**
printf("\n\n"); printf("\n\n");
for (u32 i = 0; i < Meta.TypeTable.Types.Used; i++) for (u32 b = 0; b < Meta.TypeTable.TypeBucketsCount; b++)
{ {
type_definition* Decl = Meta.TypeTable.Types.GetElementAtIndex(i); type_table_hash_bucket Bucket = Meta.TypeTable.Types[b];
for (u32 i = 0; i < TYPE_TABLE_BUCKET_MAX; i++)
{
if (!Bucket.Keys[i] == 0) { continue; }
type_definition* Decl = Bucket.Values + i;
if (HasTag(MakeStringLiteral("node_proc"), Decl->MetaTags) && if (HasTag(MakeStringLiteral("node_proc"), Decl->MetaTags) &&
Decl->Type == TypeDef_Function) Decl->Type == TypeDef_Function)
{ {
@ -50,8 +53,8 @@ int main(int ArgCount, char* Args[])
printf(");\n\n"); printf(");\n\n");
} }
} }
}
printf("\n\n"); printf("\n\n");
#endif
FinishEnumGeneration(&NodeTypeGen); FinishEnumGeneration(&NodeTypeGen);

View File

@ -20,16 +20,16 @@
#include <windows.h> #include <windows.h>
#include <stdio.h> #include <stdio.h>
#include <gs_language.h> #include "..\gs_libs\gs_language.h"
#include <gs_bucket.h> #include "..\gs_libs\gs_bucket.h"
#include "..\src\gs_platform.h" #include "..\gs_libs\gs_platform.h"
#include <gs_memory_arena.h> #include "..\gs_libs\gs_memory_arena.h"
#include <gs_string.h> #include "..\gs_libs\gs_string.h"
#include "gs_meta_lexer.h" #include "gs_meta_lexer.h"
#include "gs_meta_error.h" #include "gs_meta_error.h"
#include "foldhaus_meta_type_table.h" #include "gs_meta_type_table.h"
struct source_code_file struct source_code_file
{ {
@ -404,10 +404,6 @@ ReadEntireFileAndNullTerminate (source_code_file* File, errors* Errors)
LengthRead = (s32)ReadSize + 1; LengthRead = (s32)ReadSize + 1;
fclose(ReadFile); fclose(ReadFile);
} }
else
{
PushFError(Errors, "Could Not Read File: %S", File->Path);
}
return LengthRead; return LengthRead;
} }
@ -431,7 +427,7 @@ FileAlreadyInSource(string Path, gs_bucket<source_code_file> SourceFiles)
} }
internal void internal void
AddFileToSource(string RelativePath, gs_bucket<source_code_file>* SourceFiles, errors* Errors) AddFileToSource(string RelativePath, source_code_file CurrentFile, gs_bucket<source_code_file>* SourceFiles, errors* Errors)
{ {
source_code_file File = {0}; source_code_file File = {0};
@ -451,7 +447,11 @@ AddFileToSource(string RelativePath, gs_bucket<source_code_file>* SourceFiles, e
} }
else else
{ {
PushFError(Errors, "Error: Could not load file %S\n", RelativePath); PushFError(Errors, "Error: Could not load file %S.\n", RelativePath);
if (CurrentFile.Path.Length > 0)
{
PushFError(Errors, " Loaded In: %S\n", CurrentFile.Path);
}
} }
} }
@ -1442,7 +1442,7 @@ PreprocessProgram (char* SourceFile)
string CurrentWorkingDirectory = MakeString((char*)malloc(1024), 0, 1024); string CurrentWorkingDirectory = MakeString((char*)malloc(1024), 0, 1024);
string RootFile = MakeString(SourceFile); string RootFile = MakeString(SourceFile);
AddFileToSource(RootFile, &Meta.SourceFiles, &Meta.Errors); AddFileToSource(RootFile, {}, &Meta.SourceFiles, &Meta.Errors);
s32 LastSlash = ReverseSearchForCharInSet(RootFile, "\\/"); s32 LastSlash = ReverseSearchForCharInSet(RootFile, "\\/");
if (LastSlash <= 0) if (LastSlash <= 0)
@ -1514,7 +1514,7 @@ PreprocessProgram (char* SourceFile)
ParseSuccess = true; ParseSuccess = true;
if (!FileAlreadyInSource(TempFilePath, Meta.SourceFiles)) if (!FileAlreadyInSource(TempFilePath, Meta.SourceFiles))
{ {
AddFileToSource(TempFilePath, &Meta.SourceFiles, &Meta.Errors); AddFileToSource(TempFilePath, *File, &Meta.SourceFiles, &Meta.Errors);
} }
EndScope(IncludeScope); EndScope(IncludeScope);
} }
@ -1590,9 +1590,10 @@ FinishMetaprogram(gs_meta_preprocessor* Meta)
FinishProfiler(&Meta->Profiler); FinishProfiler(&Meta->Profiler);
PrintAllErrors(Meta->Errors); PrintAllErrors(Meta->Errors);
printf("\nMetaprogram Performance:\n"); printf("\nMetaprogram Performance:\n");
PrintAllCategories(&Meta->Profiler); PrintAllCategories(&Meta->Profiler);
printf("\n");
} }
#define GS_META_CPP #define GS_META_CPP

View File

@ -5,8 +5,8 @@
// //
#ifndef GS_META_CODE_GENERATOR_H #ifndef GS_META_CODE_GENERATOR_H
#include <gs_string.h> #include "../gs_libs/gs_string.h"
#include <gs_string_builder.h> #include "../gs_libs/gs_string_builder.h"
enum gsm_code_gen_type enum gsm_code_gen_type
{ {

View File

@ -1,164 +0,0 @@
#define CODE_SIZE 256
struct generated_code
{
s32 Used;
char* Code;
generated_code* Next;
};
internal void
InitGeneratedCode (generated_code* Code)
{
Code->Used = 0;
Code->Code = (char*)malloc(sizeof(char) * CODE_SIZE);
*(Code->Code + CODE_SIZE - 1) = 0;
Code->Next = 0;
}
// NOTE(Peter): This ONLY supports printing strings into the buffer at the moment
static void
PrintF_ (
generated_code* Dest,
char* Format,
va_list Args
)
{
if (!Dest->Code) {
InitGeneratedCode(Dest);
}
char* Src = Format;
char* Dst = Dest->Code + Dest->Used;
while (*Src && (Dst - Dest->Code) < CODE_SIZE)
{
if (*Src == '\\' && *(Src + 1) && *(Src + 1) == '%')
{
*Src++;
*Dst++ = *Src++;
}
else if (*Src == '%')
{
Src++;
if (*Src == 's')
{
Src++;
s32 StringLength = va_arg(Args, s32);
char* String = va_arg(Args, char*);
char* C = String;
while(*C && StringLength > 0 && (Dst - Dest->Code) < CODE_SIZE)
{
StringLength--;
*Dst++ = *C++;
}
}
else
{
InvalidCodePath;
}
}
else
{
*Dst++ = *Src++;
}
}
if (!*Dst && *Src)
{
Dest->Next = (generated_code*)malloc(sizeof(generated_code));
InitGeneratedCode(Dest->Next);
PrintF_(Dest->Next, Src, Args);
}
if (*Dst && !*Src) { *Dst = 0; }
Dest->Used = (s32)(Dst - Dest->Code);
}
static void
PrintF (
generated_code* Dest,
char* Format,
...)
{
va_list Args;
va_start(Args, Format);
PrintF_(Dest, Format, Args);
va_end(Args);
}
static void
PrintCode (generated_code* Code)
{
GS_PRINTF(Code->Code);
if (Code->Next) { PrintCode(Code->Next); }
}
static void
GenerateFieldCode (ast_field_declaration* Field, string_buffer* CodeBuffer, string_partition* Partition,
s32 IndentLevel, char* Terminator)
{
for (s32 i = 0; i < IndentLevel; i++)
{
PrintStringBufferFormat(CodeBuffer, Partition, " ");
}
PrintStringBufferFormat(CodeBuffer, Partition, "%s%s %s%s",
Field->TypeLength, Field->Type,
(Field->TypePointer ? 1 : 0), (Field->TypePointer ? "*" : ""),
Field->NameLength, Field->Name,
(Field->TypeArray ? 2 : 0), (Field->TypeArray ? "[]" : ""));
PrintStringBufferFormat(CodeBuffer, Partition, Terminator);
}
static string_buffer*
GenerateStructCode (ast_node* Struct, string_partition* StringPartition)
{
Assert(Struct->Type == ASTNode_StructDeclaration);
string_buffer* StructCodeBuffer = GetStringBuffer(StringPartition);
PrintStringBufferFormat(StructCodeBuffer, StringPartition, "struct %s\n{\n",
Struct->StructDeclaration.NameLength, Struct->StructDeclaration.Name);
ast_field_declaration* Member = Struct->StructDeclaration.Members;
while (Member)
{
GenerateFieldCode(Member, StructCodeBuffer, StringPartition, 1, ";\n");
Member = Member->Next;
}
PrintStringBufferFormat(StructCodeBuffer, StringPartition, "}\n\n");
return StructCodeBuffer;
}
static string_buffer*
GenerateFunctionDeclaration (ast_node* Function, string_partition* Partition)
{
Assert(Function->Type == ASTNode_FunctionDeclaration);
ast_function_declaration* FuncDecl = &Function->FunctionDeclaration;
string_buffer* FunctionDeclBuffer = GetStringBuffer(Partition);
PrintStringBufferFormat(FunctionDeclBuffer, Partition, "%s %s (",
FuncDecl->ReturnTypeLength, FuncDecl->ReturnType,
FuncDecl->NameLength, FuncDecl->Name);
ast_field_declaration* Param = FuncDecl->Arguments;
while (Param)
{
GenerateFieldCode(Param, FunctionDeclBuffer, Partition, 0, "");
if (Param->Next)
{
PrintStringBufferFormat(FunctionDeclBuffer, Partition, ", ");
}
Param = Param->Next;
}
PrintStringBufferFormat(FunctionDeclBuffer, Partition, ")\n");
return FunctionDeclBuffer;
}

View File

@ -1,337 +0,0 @@
enum ast_node_type
{
ASTNode_Invalid,
ASTNode_Program,
ASTNode_StructDeclaration,
ASTNode_FunctionDeclaration,
ASTNode_Count
};
struct ast_field_declaration
{
s32 NameLength;
char* Name;
s32 TypeLength;
char* Type;
b32 TypePointer;
b32 TypeArray;
ast_field_declaration* Next;
};
struct ast_struct_declaration
{
s32 NameLength;
char* Name;
s32 MembersCount;
ast_field_declaration* Members;
};
struct ast_function_declaration
{
s32 ReturnTypeLength;
char* ReturnType;
s32 NameLength;
char* Name;
ast_field_declaration* Arguments;
};
struct ast_node
{
ast_node_type Type;
ast_node* Children;
union
{
ast_struct_declaration StructDeclaration;
ast_function_declaration FunctionDeclaration;
};
ast_node* Next;
};
struct parse_field_decl_result
{
ast_field_declaration* Member;
token* NextToken;
};
internal parse_field_decl_result
ParseFieldDeclaration (//ast_field_declaration** Container, ast_field_declaration* PreviousMember,
token* StartToken, token_type TerminatorToken, token_type EnclosingToken)
{
parse_field_decl_result Result = {};
ast_field_declaration* Member = 0;
token* CurrentToken = StartToken;
if (StartToken->Type == Token_Identifier)
{
Member = (ast_field_declaration*)malloc(sizeof(ast_field_declaration));
Member->Next = 0;
Member->Type = CurrentToken->Text;
Member->TypeLength = CurrentToken->TextLength;
Member->TypePointer = false;
Member->TypeArray = false;
CurrentToken = CurrentToken->Next;
if (*CurrentToken->Text == '*')
{
Member->TypePointer = true;
CurrentToken = CurrentToken->Next;
}
Member->Name = CurrentToken->Text;
Member->NameLength = CurrentToken->TextLength;
CurrentToken = CurrentToken->Next;
if (CurrentToken->Type == Token_LeftSquareBracket)
{
CurrentToken = CurrentToken->Next;
if (CurrentToken->Type != Token_RightSquareBracket)
{
GS_DEBUG_PRINTF("ALERT: Skipping Array parameter that has a size");
while (CurrentToken->Type != Token_RightSquareBracket)
{
CurrentToken = CurrentToken->Next;
}
}
CurrentToken = CurrentToken->Next;
Member->TypeArray = true;
}
else if (CurrentToken->Type != TerminatorToken &&
CurrentToken->Type != EnclosingToken)
{
GS_DEBUG_PRINTF("Error: struct member %s %.*s not followed by its terminator type: %s or %s\n",
TokenNames[CurrentToken->Type], CurrentToken->TextLength, CurrentToken->Text,
TokenNames[(int)TerminatorToken], TokenNames[(int)EnclosingToken]);
}
}
else if (StartToken->Type == Token_Comment)
{
CurrentToken = StartToken->Next;
}
// NOTE(Peter): this is here because if the current token is the enclosing type,
// ie. the ')' in a parameter list, it isn't the responsibility of this function
// to deal with that.
if (CurrentToken->Type == TerminatorToken)
{
CurrentToken = CurrentToken->Next;
}
Result.Member = Member;
Result.NextToken = CurrentToken;
return Result;
}
struct parse_result
{
b32 Parsed;
ast_node* Node;
token* NextToken;
};
internal parse_result
ParseStructDeclaration (ast_node* PreviousNode, token* StartToken)
{
parse_result Result = {};
ast_node* Struct = 0;
token* CurrentToken = StartToken;
if (PreviousNode == 0)
{
Struct = (ast_node*)malloc(sizeof(ast_node));;
}
else
{
PreviousNode->Next = (ast_node*)malloc(sizeof(ast_node));
Struct = PreviousNode->Next;
}
Struct->Next = 0;
Struct->StructDeclaration.Members = 0;
Struct->Type = ASTNode_StructDeclaration;
CurrentToken = CurrentToken->Next;
// Name Before Declaration
if (CurrentToken->Type == Token_Identifier)
{
Struct->StructDeclaration.NameLength = CurrentToken->TextLength;
Struct->StructDeclaration.Name = CurrentToken->Text;
CurrentToken = CurrentToken->Next;
}
if (CurrentToken->Type == Token_LeftCurlyBracket)
{
CurrentToken = CurrentToken->Next;
ast_field_declaration* Member = 0;
while (CurrentToken->Type != Token_RightCurlyBracket)
{
parse_field_decl_result MemberResult = ParseFieldDeclaration(CurrentToken, Token_Semicolon, Token_RightCurlyBracket);
if (!Member)
{
Member = MemberResult.Member;
Member->Next = 0;
Struct->StructDeclaration.Members = Member;
}
else if (MemberResult.Member)
{
Member->Next = MemberResult.Member;
Member = Member->Next;
}
CurrentToken = MemberResult.NextToken;
}
// Advance Past the Right Bracket
CurrentToken = CurrentToken->Next;
}
else
{
GS_DEBUG_PRINTF("Error: struct <name> not followed by {");
}
// Name After Declaration
if (CurrentToken->Type == Token_Identifier)
{
Struct->StructDeclaration.NameLength = CurrentToken->TextLength;
Struct->StructDeclaration.Name = CurrentToken->Text;
CurrentToken = CurrentToken->Next;
}
if (CurrentToken->Type == Token_Semicolon)
{
CurrentToken = CurrentToken->Next;
}
else
{
GS_DEBUG_PRINTF("Error: struct declaration did not finish with a semicolon");
}
Result.Node = Struct;
Result.NextToken = CurrentToken;
Result.Parsed = true;
return Result;
}
internal b32
IsFunction (token* StartToken)
{
b32 Result = true;
token* Current = StartToken;
// TODO(Peter): check a type table to see if we can do this now.
// TODO(Peter): is there a way to defer this to later?
if (Current->Type != Token_Identifier) // Return Type
{
Result = false;
return Result;
}
Current = Current->Next;
if (Current->Type != Token_Identifier) // Function Name
{
Result = false;
return Result;
}
Current = Current->Next;
if (Current->Type != Token_LeftParen)
{
Result = false;
return Result;
}
Current = Current->Next;
while (Current && Current->Type != Token_RightParen)
{
Current = Current->Next;
}
if (Current->Type != Token_RightParen)
{
Result = false;
return Result;
}
return Result;
}
internal parse_result
ParseFunctionDeclaration (ast_node* PreviousNode, token* StartToken)
{
parse_result Result;
ast_node* Function = 0;
token* CurrentToken = StartToken;
if (PreviousNode == 0)
{
Function = (ast_node*)malloc(sizeof(ast_node));
}
else
{
PreviousNode->Next = (ast_node*)malloc(sizeof(ast_node));
Function = PreviousNode->Next;
}
Function->Next = 0;
Function->Type = ASTNode_FunctionDeclaration;
Function->FunctionDeclaration.Arguments = 0;
Function->FunctionDeclaration.ReturnTypeLength = CurrentToken->TextLength;
Function->FunctionDeclaration.ReturnType = CurrentToken->Text;
CurrentToken = CurrentToken->Next;
Function->FunctionDeclaration.NameLength = CurrentToken->TextLength;
Function->FunctionDeclaration.Name = CurrentToken->Text;
CurrentToken = CurrentToken->Next;
if (CurrentToken->Type == Token_LeftParen)
{
CurrentToken = CurrentToken->Next;
ast_field_declaration* Param = 0;
while (CurrentToken->Type != Token_RightParen)
{
parse_field_decl_result ParamResult = ParseFieldDeclaration(CurrentToken, Token_Comma, Token_RightParen);
if (!Param)
{
Param = ParamResult.Member;
Param->Next = 0;
}
else if (ParamResult.Member)
{
Param->Next = ParamResult.Member;
Param = Param->Next;
}
CurrentToken = ParamResult.NextToken;
}
CurrentToken = CurrentToken->Next;
}
else
{
GS_DEBUG_PRINTF("Error: Function declaration is not followed by left parenthesis");
InvalidCodePath;
}
Result.Node = Function;
Result.NextToken = CurrentToken;
Result.Parsed = true;
return Result;
}

View File

@ -9,9 +9,9 @@
// //
#ifndef GS_META_TYPEINFO_GENERATOR_H #ifndef GS_META_TYPEINFO_GENERATOR_H
#include <gs_language.h> #include "..\gs_libs\gs_language.h"
#include <gs_string.h> #include "..\gs_libs\gs_string.h"
#include <gs_string_builder.h> #include "..\gs_libs\gs_string_builder.h"
#include "gs_meta_code_generator.h" #include "gs_meta_code_generator.h"
struct typeinfo_generator struct typeinfo_generator

View File

@ -1,99 +0,0 @@
#define STRING_BUILDER_ARRAY_BUFFER_SIZE 32
struct string_array
{
string** Buckets;
s32 BucketSize;
s32 BucketCount;
s32 Used;
free_list FreeList;
};
internal string*
GetEntryAtIndex (s32 Index, string_array Buffer)
{
string* Result = 0;
if (Buffer.Buckets)
{
bucket_index BucketIndex = GetBucketIndexForIndex(Index, Buffer.BucketSize);
Result = Buffer.Buckets[BucketIndex.Bucket] + BucketIndex.IndexInBucket;
}
return Result;
}
internal s32
PushElement (string Data, string_array* Buffer)
{
s32 Result = -1;
if (Buffer->Used >= Buffer->BucketSize * Buffer->BucketCount)
{
Buffer->Buckets = (string**)GrowBuffer(Buffer->BucketSize, sizeof(string), &Buffer->BucketCount, (void**)Buffer->Buckets);
}
s32 Index = Buffer->Used++;
s32 BucketIndex = Index / Buffer->BucketSize;
s32 IndexInBucket = Index % Buffer->BucketSize;
Buffer->Buckets[BucketIndex][IndexInBucket] = Data;
Result = Index;
return Result;
}
struct string_builder
{
string_array Buffer;
s32 BufferElementSize;
};
internal string_builder
InitStringBuilder(s32 BufferSize)
{
string_builder Result = {};
Result.BufferElementSize = BufferSize;
Result.Buffer.BucketSize = STRING_BUILDER_ARRAY_BUFFER_SIZE;
Result.Buffer.FreeList.Next = &Result.Buffer.FreeList;
return Result;
}
internal void
GrowStringBuilder (string_builder* StringBuilder)
{
string NewSegment = {};
NewSegment.Memory = (char*)malloc(StringBuilder->BufferElementSize * sizeof(char));
NewSegment.Max = StringBuilder->BufferElementSize;
PushElement(NewSegment, &StringBuilder->Buffer);
}
internal void
StringBuilderPrintF (string_builder* StringBuilder, char* Format, ...)
{
string Addition = {};
Addition.Max = 2048;
Addition.Memory = (char*)malloc(Addition.Max * sizeof(char));
va_list Args;
va_start(Args, Format);
Addition.Length = PrintFArgsList(Addition.Memory, Addition.Max, Format, Args);
s32 CharsCopied = 0;
while (CharsCopied < Addition.Length)
{
s32 StringBuilderTailIndex = StringBuilder->Buffer.Used - 1;
string* LastString = GetEntryAtIndex(StringBuilderTailIndex, StringBuilder->Buffer);
if (!LastString || LastString->Length >= LastString->Max)
{
GrowStringBuilder(StringBuilder);
StringBuilderTailIndex = StringBuilder->Buffer.Used - 1;
LastString = GetEntryAtIndex(StringBuilderTailIndex, StringBuilder->Buffer);
}
while (CharsCopied < Addition.Length && LastString->Length < LastString->Max)
{
LastString->Memory[LastString->Length++] = Addition.Memory[CharsCopied++];
}
}
free(Addition.Memory);
}

View File

@ -1,42 +0,0 @@
#include "..\src\gs_language.h"
#include "..\src\foldhaus_memory.h"
#include "..\src\gs_string.h"
#include "gs_meta.cpp"
#include <windows.h>
#include <stdio.h>
int main (int ArgCount, char* Arg[])
{
gs_meta_processor Meta = CreateMetaProcessor();
AddFile(&Meta, "C:/projects/foldhaus/meta/meta_test.cpp");
LexAllFiles(&Meta);
ParseAllFiles(&Meta);
#if 0
identifier_table_entry* NodeStructEntry = AddDefineToIdentifierTable(&Meta, "NODE_STRUCT", "NODE_STRUCT(%name)", StructDefinition);
identifier_table_entr* NodeProcEntry = AddDefineToIdentifierTable(&Meta, "NODE_PROC", "NODE_PROC(%name, %data)", FunctionDefinition);
symbol_list NodeStructs = FindAllMatchingSymbols(Meta, NodeStructEntry);
for (s32 i = 0; i < NodeStructs.Length; i++)
{
struct_definition_symbol Struct = NodeStructs.List[i];
Struct.Size;
for (s32 m = 0; m < Struct.MembersCount; m++)
{
Struct.Members[m];
}
}
#endif
if (Meta.ErrorList.TotalUsed > 0)
{
PrintErrorList(Meta.ErrorList);
}
return 0;
}

View File

@ -1,21 +0,0 @@
typedef float r32;
struct test_struct
{
float Float;
int Int;
char* CharPointer;
};
struct nested_struct
{
float Hello;
test_struct NestedValue;
r32 TypedefedValue;
};
int main(char* Args, int ArgCount)
{
return 0;
}

View File

@ -5,7 +5,7 @@
// //
#ifndef FOLDHAUS_APP_CPP #ifndef FOLDHAUS_APP_CPP
#include "../meta/foldhaus_meta_include.h" #include "../meta/gs_meta_include.h"
#include "foldhaus_platform.h" #include "foldhaus_platform.h"
#include "foldhaus_app.h" #include "foldhaus_app.h"

View File

@ -7,7 +7,7 @@
#include "../meta/gs_meta_lexer.h" #include "../meta/gs_meta_lexer.h"
#include "gs_font.h" #include "../gs_libs/gs_font.h"
#include "interface.h" #include "interface.h"
#include "foldhaus_network_ordering.h" #include "foldhaus_network_ordering.h"

View File

@ -9,17 +9,17 @@
#include <stdio.h> #include <stdio.h>
#define GS_LANGUAGE_NO_PROFILER_DEFINES #define GS_LANGUAGE_NO_PROFILER_DEFINES
#include "C:\programs-dev\gs_libs\src\gs_language.h" #include "..\gs_libs\gs_language.h"
#include "gs_platform.h" #include "..\gs_libs\gs_platform.h"
#include "C:\programs-dev\gs_libs\src\gs_radix_sort.h" #include "..\gs_libs\gs_radix_sort.h"
#include "C:\programs-dev\gs_libs\src\gs_list.h" #include "..\gs_libs\gs_list.h"
#include "C:\programs-dev\gs_libs\src\gs_bucket.h" #include "..\gs_libs\gs_bucket.h"
#define GS_MEMORY_TRACK_ALLOCATIONS #define GS_MEMORY_TRACK_ALLOCATIONS
#include "C:\programs-dev\gs_libs\src\gs_memory_arena.h" #include "..\gs_libs\gs_memory_arena.h"
#include "C:\programs-dev\gs_libs\src\gs_string.h" #include "..\gs_libs\gs_string.h"
#include "foldhaus_debug.h" #include "foldhaus_debug.h"
global_variable debug_services* GlobalDebugServices; global_variable debug_services* GlobalDebugServices;
@ -27,9 +27,9 @@ global_variable debug_services* GlobalDebugServices;
global_variable platform_alloc* GSAlloc; global_variable platform_alloc* GSAlloc;
global_variable platform_free* GSFree; global_variable platform_free* GSFree;
#include "C:\programs-dev\gs_libs\src\gs_vector_matrix.h" #include "..\gs_libs\gs_vector_matrix.h"
#include "gs_input.h" #include "..\gs_libs\gs_input.h"
#include "foldhaus_renderer.h" #include "foldhaus_renderer.h"

View File

@ -1,239 +0,0 @@
//
// File: gs_array.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef GS_ARRAY_H
struct free_list
{
free_list* Next;
s32 Index;
};
struct bucket_index
{
s32 Bucket;
s32 IndexInBucket;
};
inline bucket_index
GetBucketIndexForIndex (s32 Index, s32 BucketSize)
{
bucket_index Result = {};
Result.Bucket = Index / BucketSize;
Result.IndexInBucket = Index % BucketSize;
return Result;
};
struct array_entry_handle
{
s32 Generation;
s32 Index;
};
// NOTE(Peter): This is a total bastardization of the preprocessor but it works and is
// easier than writing a metaprogramming system at the moment.
// TODO(Peter): Write a metaprogramming version of this that is actually easy to debug
#define TYPEDEF_ARRAY(element_type) \
struct element_type##_array_entry { \
s32 Generation; \
union \
{ \
element_type Entry; \
free_list Free; \
}; \
}; \
\
struct element_type##_array \
{ \
element_type##_array_entry** Buckets; \
s32 BucketSize; \
s32 BucketCount; \
s32 Used; \
free_list FreeList; \
}; \
\
internal void \
GrowBuffer(element_type##_array* Buffer) \
{ \
s32 NewBucketSize = sizeof(element_type##_array_entry) * Buffer->BucketSize; \
element_type##_array_entry* NewBucket = (element_type##_array_entry*)malloc(NewBucketSize); \
GSZeroMemory((u8*)NewBucket, NewBucketSize); \
\
s32 NewBucketIndex = Buffer->BucketCount++; \
if (!Buffer->Buckets) \
{ \
Buffer->Buckets = (element_type##_array_entry**)malloc(sizeof(element_type##_array_entry*)); \
} \
else \
{ \
Buffer->Buckets = (element_type##_array_entry**)realloc(Buffer->Buckets, sizeof(element_type##_array_entry*) * Buffer->BucketCount); \
} \
Buffer->Buckets[NewBucketIndex] = NewBucket; \
} \
\
internal element_type##_array_entry* \
GetEntryAtIndex (s32 Index, element_type##_array Buffer) \
{ \
bucket_index BucketIndex = GetBucketIndexForIndex(Index, Buffer.BucketSize); \
element_type##_array_entry* Entry = Buffer.Buckets[BucketIndex.Bucket] + BucketIndex.IndexInBucket; \
return Entry; \
} \
\
internal array_entry_handle \
PushElement (element_type Data, element_type##_array* Buffer) \
{ \
array_entry_handle Result = {}; \
\
if (Buffer->FreeList.Next != &Buffer->FreeList) \
{ \
free_list* FreeList = Buffer->FreeList.Next; \
element_type##_array_entry* Entry = GetEntryAtIndex(FreeList->Index, *Buffer); \
Buffer->FreeList.Next = Entry->Free.Next; \
\
Result.Index = Entry->Free.Index; \
Result.Generation = Entry->Generation; \
Entry->Entry = Data; \
\
++Buffer->Used; \
} \
else \
{ \
if (Buffer->Used >= Buffer->BucketSize * Buffer->BucketCount) \
{ \
GrowBuffer(Buffer); \
} \
\
s32 Index = Buffer->Used++; \
s32 BucketIndex = Index / Buffer->BucketSize; \
s32 IndexInBucket = Index % Buffer->BucketSize; \
\
Buffer->Buckets[BucketIndex][IndexInBucket].Entry = Data; \
Result.Index = Index; \
Result.Generation = Buffer->Buckets[BucketIndex][IndexInBucket].Generation; \
} \
\
return Result; \
} \
\
internal element_type* \
GetElementAtIndex (s32 Index, element_type##_array Buffer) \
{ \
Assert(Index < Buffer.Used); \
element_type##_array_entry* Entry = GetEntryAtIndex(Index, Buffer); \
element_type* Result = &Entry->Entry; \
return Result; \
} \
\
internal element_type* \
GetElementWithHandle (array_entry_handle Handle, element_type##_array Buffer) \
{ \
element_type* Result = 0; \
\
element_type##_array_entry* Entry = GetEntryAtIndex(Handle.Index, Buffer); \
\
if (Entry->Generation == Handle.Generation) \
{ \
Result = &Entry->Entry; \
} \
\
return Result; \
} \
\
internal void \
RemoveElementAtIndex (s32 Index, element_type##_array* Buffer) \
{ \
Assert(Index < Buffer->Used); \
\
element_type##_array_entry* Entry = GetEntryAtIndex(Index, *Buffer); \
++Entry->Generation; \
Entry->Free.Index = Index; \
\
Entry->Free.Next = Buffer->FreeList.Next; \
Buffer->FreeList.Next = &Entry->Free; \
\
} \
// END OF CRAZY MACRO
#define TYPEDEF_CONTIGUOUS_ARRAY(element_type) \
struct element_type##_contiguous_array \
{ \
element_type** Buckets; \
s32 BucketSize; \
s32 BucketCount; \
s32 Used; \
}; \
\
internal void \
GrowBuffer(element_type##_contiguous_array* Buffer) \
{ \
s32 NewBucketSize = sizeof(element_type) * Buffer->BucketSize; \
element_type* NewBucket = (element_type*)malloc(NewBucketSize); \
GSZeroMemory((u8*)NewBucket, NewBucketSize); \
\
s32 NewBucketIndex = Buffer->BucketCount++; \
if (!Buffer->Buckets) \
{ \
Buffer->Buckets = (element_type**)malloc(sizeof(element_type*)); \
} \
else \
{ \
Buffer->Buckets = (element_type**)realloc(Buffer->Buckets, sizeof(element_type*) * Buffer->BucketCount); \
} \
Buffer->Buckets[NewBucketIndex] = NewBucket; \
} \
\
internal element_type* \
GetElementAtIndex (s32 Index, element_type##_contiguous_array Buffer) \
{ \
element_type* Entry = 0; \
if (Index <= Buffer.Used) \
{ \
bucket_index BucketIndex = GetBucketIndexForIndex(Index, Buffer.BucketSize); \
Entry = Buffer.Buckets[BucketIndex.Bucket] + BucketIndex.IndexInBucket; \
} \
return Entry; \
} \
\
internal s32 \
PushElement (element_type Data, element_type##_contiguous_array* Buffer) \
{ \
s32 Result = -1; \
\
if (Buffer->Used >= Buffer->BucketSize * Buffer->BucketCount) \
{ \
GrowBuffer(Buffer); \
} \
\
s32 Index = Buffer->Used++; \
s32 BucketIndex = Index / Buffer->BucketSize; \
s32 IndexInBucket = Index % Buffer->BucketSize; \
\
Buffer->Buckets[BucketIndex][IndexInBucket] = Data; \
Result = Index; \
return Result; \
} \
\
internal void \
RemoveElementAtIndex (s32 Index, element_type##_contiguous_array* Buffer) \
{ \
Assert(Index < Buffer->Used); \
\
bucket_index IndexToRemove = GetBucketIndexForIndex(Index, Buffer->BucketSize); \
bucket_index LastIndex = GetBucketIndexForIndex(Buffer->Used - 1, Buffer->BucketSize); \
element_type ValueAtLastIndex = Buffer->Buckets[LastIndex.Bucket][LastIndex.IndexInBucket]; \
Buffer->Buckets[IndexToRemove.Bucket][IndexToRemove.IndexInBucket] = ValueAtLastIndex; \
--Buffer->Used; \
} \
// END OF CRAZY MACRO
TYPEDEF_ARRAY(array_entry_handle);
TYPEDEF_CONTIGUOUS_ARRAY(array_entry_handle);
#define GS_ARRAY_H
#endif // GS_ARRAY_H

View File

@ -1,11 +0,0 @@
//
// File: gs_hashtable.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef GS_HASHTABLE_H
//
#define GS_HASHTABLE_H
#endif // GS_HASHTABLE_H

View File

@ -11,10 +11,10 @@
#include <windowsx.h> #include <windowsx.h>
#include <gl/gl.h> #include <gl/gl.h>
#include "../meta/foldhaus_meta_include.h" #include "../meta/gs_meta_include.h"
#include "foldhaus_platform.h" #include "foldhaus_platform.h"
#include "gs_win32.cpp" #include "../gs_libs/gs_win32.cpp"
#include "foldhaus_renderer.cpp" #include "foldhaus_renderer.cpp"
global_variable b32 Running = false; global_variable b32 Running = false;