libcommon: Backport code for the common lib

stable
jaxne 4 years ago
parent 719f4efcf1
commit aaf9ed39f7

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -0,0 +1,4 @@
#include "types.h"
#include "shared.h"
#include "tokenizer.h"
#include "tokenizer.cpp"

@ -0,0 +1,288 @@
#ifndef SHARED_H
#define SHARED_H
#define ZeroStruct(Struct) ZeroSize(&Struct, sizeof(Struct))
inline void ZeroSize(void* Ptr, size_t Size) {
u8* Byte = (u8*)Ptr;
// todo(jax): @Speed: Check performance of the two code blocks
#if 0
for (size_t i = 0; i < Size; ++i) {
*Byte++ = 0;
}
#else
while (Size--) {
*Byte++ = 0;
}
#endif
}
#define CopyArray(Dest, Source, Count) MemoryCopy((Dest), (Source), (Count)*sizeof(*(Source)))
inline void* MemoryCopy(void* _Dest, void* _Source, size_t Size) {
#if 0
return memcpy(_Dest, _Source, Size);
#else //NO CRT VERSION HERE!
if (_Source == 0) {
ZeroSize(_Dest, Size);
return _Dest;
}
u8* Source = (u8*)_Source;
u8* Dest = (u8*)_Dest;
while (Size--) {
*Dest++ = *Source++;
}
return _Dest;
#endif
}
inline u8* Advance(string* String, umm Count) {
u8 *Result = 0;
if(String->Count >= Count) {
Result = String->Data;
String->Data += Count;
String->Count -= Count;
} else {
String->Data += String->Count;
String->Count = 0;
}
return(Result);
}
inline b32 IsSpacing(char C) {
b32 Result = ((C == ' ') || (C == '\t') || (C == '\v') ||(C == '\f'));
return(Result);
}
inline b32 IsEndOfLine(char Value) {
b32 Result = ((Value == '\n') || (Value == '\r'));
return Result;
}
inline b32 IsWhitespace(char Value, bool IncludeEOL = false) {
b32 Result = ((Value == ' ') || (Value == '\t') || (Value == '\v') || (Value == '\f') || ( IncludeEOL ? IsEndOfLine(Value) : 1));
return Result;
}
inline b32 IsAlphabetical(char Value) {
b32 Result = (((Value >= 'a') && (Value <= 'z')) || ((Value >= 'A') && (Value <= 'Z')));
return Result;
}
inline b32 IsNumeric(char Value) {
b32 Result = ((Value >= '0') && (Value <= '9'));
return Result;
}
inline char* GetNextLine(char** Contents) {
char* Text = *Contents;
if (!*Text) {
return nullptr;
}
char* Line = Text;
while (*Text && (*Text != '\n') && (*Text != '\r')) {
++Text;
}
char* End = Text;
++End;
if (*Text == '\r') {
if (*End == '\n') {
++End;
}
*Text = '\0';
}
*Contents = End;
return Line;
}
inline int StringLength(char* String) {
int Count = 0;
while (*String++) {
++Count;
}
return Count;
}
inline char* Substring(char* Source, char* String) {
while (*Source) {
char *Begin = Source;
char *Pattern = String;
// If first character of sub string match, check for whole string
while (*Source && *Pattern && *Source == *Pattern) {
Source++;
Pattern++;
}
// If complete sub string match, return starting address
if (!*Pattern)
return Begin;
Source = Begin + 1;
}
return NULL;
}
// note: _Char is expected to be an ASCII character
inline char* FindFirstChar(char* String, int _Char) {
char Char = (char)_Char;
while (*String != Char) {
if (!*String++) {
return NULL;
}
}
return (char*)String;
}
// todo(jax): Consider using while loops for Append and StringCopy?? Query performance benefit.
inline char* Append(char* Dest, size_t DestSize, char* Source) {
// todo(jax): Do we need to terminate annd or allocate needed memory?
Dest = (char*)malloc(DestSize + (1 + StringLength(Source) * sizeof(char)));
MemoryCopy(Dest + StringLength(Dest), Source, DestSize + 1);
return Dest;
}
inline char* StringCopy(char* String) {
char* Result = (char*)malloc(sizeof(char) * (StringLength(String) + 1));
MemoryCopy(Result, String, sizeof(char) * (StringLength(String) + 1));
return Result;
}
inline bool StringsMatch(char* A, char* B) {
while (*A && *B) {
if (*A != *B){
return false;
}
++A;
++B;
}
if (*A != *B){
return false;
} else {
return true;
}
}
inline void CatStrings(size_t SourceACount, char* SourceA, size_t SourceBCount, char* SourceB, size_t DestCount, char* Dest) {
// todo(jax): Bounds check the Destination. This code is risky!
for (int Index = 0; Index < SourceACount; ++Index) {
*Dest++ = *SourceA++;
}
for (int Index = 0; Index < SourceBCount; ++Index) {
*Dest++ = *SourceB++;
}
*Dest++ = 0;
}
//
// NOT REALLY SURE IF WE WANT TO USE THE FOLLOWING CODE!
//
#if 1
void __cdecl __va_start(va_list*, ...);
#define _crt_va_start(ap, x) ((void)(__va_start(&ap, x)))
#define _crt_va_arg(ap, t) \
((sizeof(t) > sizeof(__int64) || (sizeof(t) & (sizeof(t) - 1)) != 0) \
? **(t**)((ap += sizeof(__int64)) - sizeof(__int64)) \
: *(t* )((ap += sizeof(__int64)) - sizeof(__int64)))
#define _crt_va_end(ap) ((void)(ap = (va_list)0))
#else
#define _crt_va_start(ap, v) va_start(ap, v)
#define _crt_va_arg(ap, t) va_arg(ap, t)
#define _crt_va_end(ap) va_end(ap)
#endif
inline int32 StringToI32_(char** AtInit) {
int32 Result = {};
char* At = *AtInit;
while ((*At >= '0') && (*At <= '9')) {
Result *= 10;
Result += (*At - '0');
++At;
}
*AtInit = At;
return Result;
}
inline int32 StringToI32(char* At) {
char* Ignored = At;
int32 Result = StringToI32_(&Ignored);
return Result;
}
struct format_dest;
void OutChar(format_dest* Dest, char Value);
void OutChars(format_dest* Dest, char* Value);
void U64ToASCII(format_dest* Dest, u64 Value, u32 Base, char* Digits);
void F64ToASCII(format_dest* Dest, f64 Value, u32 Precision);
// note(jax): This function serves as a replacement to `stdio.h` sprintf()
umm FormatArgList(umm DestSize, char* DestInit, char* Format, va_list ArgList);
inline umm Format(umm DestSize, char* Dest, char* Format, ...) {
va_list ArgList;
_crt_va_start(ArgList, Format);
umm Result = FormatArgList(DestSize, Dest, Format, ArgList);
_crt_va_end(ArgList);
return Result;
}
inline int _crt_sprintf(char* Buffer, size_t Count, char* Format, ...) {
int Result;
va_list ArgList;
__crt_va_start(ArgList, Format);
Result = _vsprintf_s_l(Buffer, Count, Format, NULL, ArgList);
__crt_va_end(ArgList);
return Result;
}
inline umm ae_sprintf(char* Dest, char* Format, ...) {
va_list ArgList;
_crt_va_start(ArgList, Format);
umm Result = FormatArgList(sizeof(Dest), Dest, Format, ArgList);
_crt_va_end(ArgList);
return Result;
}
inline umm ae_sprintf(char* Dest, char* Format, va_list ArgList) {
umm Result = FormatArgList(sizeof(Dest), Dest, Format, ArgList);
return Result;
}
inline umm ae_printf(char* Format, ...) {
char Buffer[1024];
va_list ArgList;
_crt_va_start(ArgList, Format);
umm Result = FormatArgList(1024, Buffer, Format, ArgList);
_crt_va_end(ArgList);
fwrite(Buffer, sizeof(char), StringLength(Buffer), stdout);
fflush(stdout);
return Result;
}
#endif

@ -0,0 +1,187 @@
#include <math.h>
b32 IsTokenValid(token Token) {
b32 Result = (Token.Type != Token_Unknown);
return Result;
}
b32 TokenEquals(token Token, char* Match) {
b32 Result = StringsMatch(Token.String, Match);
return Result;
}
void Refill(tokenizer *Tokenizer){
if(Tokenizer->Input.Count == 0) {
Tokenizer->At[0] = 0;
Tokenizer->At[1] = 0;
} else if(Tokenizer->Input.Count == 1) {
Tokenizer->At[0] = Tokenizer->Input.Data[0];
Tokenizer->At[1] = 0;
} else {
char C0 = Tokenizer->Input.Data[0];
char C1 = Tokenizer->Input.Data[1];
Tokenizer->At[0] = C0;
Tokenizer->At[1] = C1;
}
}
void AdvanceInput(tokenizer* Tokenizer, u32 Count) {
Tokenizer->TotalCount += Count;
Advance(&Tokenizer->Input, Count);
Refill(Tokenizer);
}
tokenizer Tokenize(string Data, char* Filename) {
tokenizer Result = {};
Result.Filename = Filename;
Result.LinesCount = 1;
Result.TokensCount = 1;
Result.TotalCount = 1;
Result.Input = Data;
Result.At = (char*)malloc(2);
Refill(&Result);
return(Result);
}
tokenizer Tokenize(char* Data);
tokenizer Tokenize(char* Filename);
token GetToken(tokenizer* Tokenizer) {
token Token = {};
Token.Filename = Tokenizer->Filename;
Token.TextLength = 1;
Token.Text = Tokenizer->Input;
char C = Tokenizer->At[0];
AdvanceInput(Tokenizer, 1);
switch (C) {
case '\0': { Token.Type = Token_EndOfStream; } break;
case '(': { Token.Type = Token_OpenParen; } break;
case ')': { Token.Type = Token_CloseParen; } break;
case ':': { Token.Type = Token_Colon; } break;
case ';': { Token.Type = Token_Semicolen; } break;
case '*': { Token.Type = Token_Asterik; } break;
case '[': { Token.Type = Token_OpenBracket; } break;
case ']': { Token.Type = Token_CloseBracket; } break;
case '{': { Token.Type = Token_OpenBrace; } break;
case '}': { Token.Type = Token_CloseBrace; } break;
case '=': { Token.Type = Token_Equals; } break;
case ',': { Token.Type = Token_Comma; } break;
case '|': { Token.Type = Token_Or; } break;
case '#': { Token.Type = Token_Pound; } break;
case '"': { // note(jax): We've got a string
Token.Type = Token_String;
while(Tokenizer->At[0] && Tokenizer->At[0] != '"') {
if ((Tokenizer->At[0] == '\\') && (Tokenizer->At[1])) {
AdvanceInput(Tokenizer, 1);
}
AdvanceInput(Tokenizer, 1);;
}
if (Tokenizer->At[0] == '"') {
AdvanceInput(Tokenizer, 1);
}
if (Token.Text.Count &&
(Token.Text.Data[0] == '"')) {
++Token.Text.Data;
--Token.Text.Count;
}
if (Token.Text.Count &&
(Token.Text.Data[Token.Text.Count - 1] == '"')) {
--Token.Text.Count;
}
} break;
default: {
if (IsSpacing(C)) {
Token.Type = Token_Space;
while (IsSpacing(Tokenizer->At[0])) {
AdvanceInput(Tokenizer, 1);
}
} else if (IsEndOfLine(C)) {
Token.Type = Token_EndOfLine;
if(((C == '\r') &&
(Tokenizer->At[0] == '\n')) ||
((C == '\n') &&
(Tokenizer->At[0] == '\r'))) {
AdvanceInput(Tokenizer, 1);
}
++Tokenizer->LinesCount;
} else if((C == '/') && (Tokenizer->At[0] == '/')) {
Token.Type = Token_Comment;
AdvanceInput(Tokenizer, 2);
while(Tokenizer->At[0] && !IsEndOfLine(Tokenizer->At[0])) {
AdvanceInput(Tokenizer, 1);
}
} else if((C == '/') &&
(Tokenizer->At[0] == '*')) {
Token.Type = Token_Comment;
AdvanceInput(Tokenizer, 2);
while(Tokenizer->At[0] && !((Tokenizer->At[0] == '*')
&& (Tokenizer->At[1] == '/'))) {
if(((Tokenizer->At[0] == '\r') && (Tokenizer->At[1] == '\n'))
|| ((Tokenizer->At[0] == '\n') && (Tokenizer->At[1] == '\r'))) {
AdvanceInput(Tokenizer, 1);
}
if (IsEndOfLine(Tokenizer->At[0])) {
++Tokenizer->LinesCount;
}
AdvanceInput(Tokenizer, 1);
}
if(Tokenizer->At[0] == '*') {
AdvanceInput(Tokenizer, 2);
}
} else if (IsAlphabetical(C)) {
Token.Type = Token_Identifier;
while (IsAlphabetical(Tokenizer->At[0]) || IsNumeric(Tokenizer->At[0]) || (Tokenizer->At[0] == '_')) {
AdvanceInput(Tokenizer, 1);
}
} else if (IsNumeric(C)) {
f32 Number = (f32)(C - '0');
while (IsNumeric(Tokenizer->At[0])) {
f32 Digit = (f32)(Tokenizer->At[0] - '0');
Number = 10.0f*Number + Digit;
AdvanceInput(Tokenizer, 1);
}
// This float detection code is copy pasted, I have no idea how it works!
if (Tokenizer->At[0] == '.') {
AdvanceInput(Tokenizer, 1);
f32 Coefficient = 0.1f;
while (IsNumeric(Tokenizer->At[0])) {
f32 Digit = (f32)(Tokenizer->At[0] - '0');
Number += Coefficient * Digit;
Coefficient *= 0.1f;
AdvanceInput(Tokenizer, 1);
}
}
Token.Type = Token_Literal;
Token.Float = Number;
Token.Integer = (s32)Number;
} else {
Token.Type = Token_Unknown;
}
} break;
}
++Tokenizer->TokensCount;
Token.Text.Count = (Tokenizer->Input.Data - Token.Text.Data);
return Token;
}
token PeekToken(tokenizer* Tokenizer);

@ -0,0 +1,63 @@
#ifndef TOKENIZER_H
#define TOKENIZER_H
enum token_type {
Token_Unknown,
Token_OpenParen, // (
Token_CloseParen, // )
Token_Colon, // :
Token_Semicolen, // ;
Token_Asterik, // *
Token_OpenBracket, // [
Token_CloseBracket, // ]
Token_OpenBrace, // {
Token_CloseBrace, // }
Token_Equals,
Token_Comma,
Token_Or,
Token_Pound,
Token_String,
Token_Identifier,
Token_Literal, // Number
Token_Space,
Token_EndOfLine,
Token_Comment,
Token_EndOfStream,
};
struct token {
char* Filename;
token_type Type;
size_t TextLength;
string Text;
union {
char* String;
f32 Float;
s32 Integer;
};
};
struct tokenizer {
char* Filename;
u32 LinesCount;
u32 TokensCount;
u32 TotalCount;
string Input;
char* At;
};
b32 IsTokenValid(token Token);
b32 TokenEquals(token Token, char* Match);
API_EXPORT token GetToken(tokenizer* Tokenizer);
API_EXPORT token PeekToken(tokenizer* Tokenizer, int Lookahead);
API_EXPORT tokenizer Tokenize(char* Data);
API_EXPORT tokenizer Tokenize(char* Filename);
API_EXPORT tokenizer Tokenize(string Data, char* Filename);
#endif

@ -0,0 +1,193 @@
#ifndef TYPES_H
#define TYPES_H
#include <direct.h>
#include <float.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef BUILD_WIN32
#define API_EXPORT __declspec(dllexport)
#else
#define API_EXPORT
#endif
typedef unsigned int uint;
typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef int64_t int64;
typedef int32 bool32;
typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
typedef float real32;
typedef double real64;
typedef int8 s8;
typedef int16 s16;
typedef int32 s32;
typedef int64 s64;
typedef bool32 b32;
typedef uint8 u8;
typedef uint16 u16;
typedef uint32 u32;
typedef uint64 u64;
typedef real32 f32;
typedef real64 f64;
typedef uintptr_t umm;
typedef intptr_t smm;
#define S32Min ((s32)0x80000000)
#define S32Max ((s32)0x7fffffff)
#define U16Max 65535
#define U32Max ((u32)-1)
#define U64Max ((u64)-1)
#define F32Max FLT_MAX
#define F32Min -FLT_MAX
#define Minimum(A, B) ((A < B) ? (A) : (B))
#define Maximum(A, B) ((A > B) ? (A) : (B))
#define For(Value) For_e((Value), ArrayCount(Value))
#define For_e(Value, End) For_se((Value), 0, (End))
#define For_se(Value, Start, End) for (int (Value) = (Start); (Value) < (End); ++(Value))
// todo(jax): Should these always be 64-bit?
#define Kilobytes(Value) (((uint64)Value) * 1024LL)
#define Megabytes(Value) (Kilobytes((uint64)Value) * 1024LL)
#define Gigabytes(Value) (Megabytes((uint64)Value) * 1024LL)
#define Terabytes(Value) (Gigabytes((uint64)Value) * 1024LL)
#define ArrayCount(Array) (sizeof(Array) / sizeof((Array)[0]))
// todo(jax): swap, min, max ... macros???
#define AlignPow2(Value, Alignment) ((Value + ((Alignment) - 1)) & ~((Alignment) - 1))
#define Align4(Value) ((Value + 3) & ~3)
#define Align8(Value) ((Value + 7) & ~7)
#define Align16(Value) ((Value + 15) & ~15)
#define Stringize(x) PrimitiveStringize(x)
#define PrimitiveStringize(x) #x
inline b32 IsPow2(u32 Value) {
return ((Value & ~(Value - 1)) == Value);
}
// note(jax): Platform-independent way to perform an assertion.
// Flat out writes to zero memory to crash the program.
// todo(jax): Create some sort of assert function that creates a message box
// like in previous engines I've worked on!
#if ENGINE_SLOW
#define Assert(Expression) if (!(Expression)) { *(int*)0=0; }
#else
#define Assert(Expression)
#endif
// A structure that encapsulates a non-terminated buffer
struct string {
u8* Data;
umm Count;
};
#include "shared.h"
//#define printf ae_printf
//#define sprintf ae_sprintf
inline u32 SafeTruncateU32(u64 Value) {
// todo(jax): Defines for min/max values
Assert(Value <= 0xFFFFFFFF);
u32 Result = (u32)Value;
return Result;
}
inline u16 SafeTruncateU16(u32 Value) {
// todo(jax): Defines for min/max values
Assert(Value <= 0xFFFF);
u16 Result = (u16)Value;
return Result;
}
inline u8 SafeTruncateU8(u64 Value) {
Assert(Value <= 0xFF);
u8 Result = (u8)Value;
return Result;
}
inline s32 SafeTruncateS32(s64 Value) {
if (Value >> 63) {
b32 IsSafeOperation = !(!(Value >> 32) && 0xffffffff);
if (!IsSafeOperation) {
printf("SafeTruncateS32: Performing unsafe truncation on '%lld'\n", Value);
}
return (s32)Value;
} else {
b32 IsSafeOperation = !((Value >> 32) && 0xffffffff);
if (!IsSafeOperation) {
printf("SafeTruncateS32: Performing unsafe truncation on '%lld'\n", Value);
}
return (s32)Value;
}
}
inline s16 SafeTruncateS16(s32 Value) {
if (Value >> 31) {
b32 IsSafeOperation = !(!(Value >> 16) && 0xffff);
if (!IsSafeOperation) {
printf("SafeTruncateS16: Performing unsafe truncation on '%d'\n", Value);
}
return (s16)Value;
} else {
b32 IsSafeOperation = !((Value >> 16) && 0xffff);
if (!IsSafeOperation) {
printf("SafeTruncateS16: Performing unsafe truncation on '%d'\n", Value);
}
return (s16)Value;
}
}
inline s8 SafeTruncateS8(s16 Value) {
if (Value >> 15) {
b32 IsSafeOperation = !(!(Value >> 8) && 0xff);
if (!IsSafeOperation) {
printf("SafeTruncateS8: Performing unsafe truncation on '%d'\n", Value);
}
return (s8)Value;
} else {
b32 IsSafeOperation = !((Value >> 8) && 0xff);
if (!IsSafeOperation) {
printf("SafeTruncateS8: Performing unsafe truncation on '%d'\n", Value);
}
return (s8)Value;
}
}
//
// note: Scalar operations
//
// todo(jax): These will eventually go into mathlib
inline real32 Square(real32 A) {
real32 Result = A*A;
return Result;
}
inline real32 Lerp(real32 A, real32 t, real32 B){
real32 Result = (1.0f - t)*A + t*B;
return Result;
}
#endif
Loading…
Cancel
Save