Initial commit

This commit is contained in:
Doyle Thai 2017-04-09 15:08:31 +10:00
commit ab5fa39957
6 changed files with 1010 additions and 0 deletions

46
.clang-format Normal file
View File

@ -0,0 +1,46 @@
{
ColumnLimit: 80,
TabWidth: 4,
IndentWidth: 4, # 1 tab
UseTab: ForIndentation,
BreakBeforeBraces: Allman,
PointerBindsToType: false,
###
AlwaysBreakAfterDefinitionReturnType: false,
AlwaysBreakTemplateDeclarations: true,
AlwaysBreakBeforeMultilineStrings: true,
IndentFunctionDeclarationAfterType: false,
#
AccessModifierOffset: -4, # 1 tab
AlignAfterOpenBracket: true,
AlignConsecutiveAssignments: true,
AlignTrailingComments: true,
#
AllowAllParametersOfDeclarationOnNextLine: true,
AllowShortBlocksOnASingleLine: false,
AllowShortIfStatementsOnASingleLine: true,
AllowShortLoopsOnASingleLine: false,
#
BinPackArguments: true,
BinPackParameters: true,
#
BreakConstructorInitializersBeforeComma: true,
ConstructorInitializerIndentWidth: 0,
#
IndentCaseLabels: true,
#
MaxEmptyLinesToKeep: 1,
NamespaceIndentation: None,
#
SpaceBeforeAssignmentOperators: true,
SpaceInEmptyParentheses: false,
SpacesBeforeTrailingComments: 1,
SpacesInAngles: false,
SpacesInCStyleCastParentheses: false,
SpacesInParentheses: false,
SpacesInSquareBrackets: false,
#
Cpp11BracedListStyle: true,
Standard: Cpp11,
#
}

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
tags
*.swp
*.swo
bin/
.vs/
*.db

52
build.bat Normal file
View File

@ -0,0 +1,52 @@
@REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or
@REM vcvarsall.bat to setup command-line compiler.
@echo OFF
set ProjectName=dqnt_unit_test
set CompileEntryPoint=..\dqnt_unit_test.cpp
REM Build tags file
ctags -R
REM Check if build tool is on path
REM >nul, 2>nul will remove the output text from the where command
where cl.exe >nul 2>nul
if %errorlevel%==1 call msvc86.bat
REM Drop compilation files into build folder
IF NOT EXIST bin mkdir bin
pushd bin
REM EHa- disable exception handling (we don't use)
REM GR- disable c runtime type information (we don't use)
REM MD use dynamic runtime library
REM MT use static runtime library, so build and link it into exe
REM Oi enable intrinsics optimisation, let us use CPU intrinsics if there is one
REM instead of generating a call to external library (i.e. CRT).
REM Zi enables debug data, Z7 combines the debug files into one.
REM W4 warning level 4
REM WX treat warnings as errors
REM wd4100 ignore: unused argument parameters
REM wd4201 ignore: nonstandard extension used: nameless struct/union
REM wd4189 ignore: local variable is initialised but not referenced
set CompileFlags=-EHa- -GR- -Oi -MT -Z7 -W4 -WX -wd4100 -wd4201 -wd4189 -FC
REM Include directories
set IncludeFlags=
REM Link libraries
set LinkLibraries=user32.lib gdi32.lib msimg32.lib
REM incrmenetal:no, turn incremental builds off
REM opt:ref, try to remove functions from libs that are referenced at all
set LinkFlags=-incremental:no -opt:ref
cl %CompileFlags% %CompileEntryPoint% %IncludeFlags% /link %LinkLibraries% %LinkFlags% /nologo /OUT:"%ProjectName%.exe"
popd

514
dqnt.h Normal file
View File

@ -0,0 +1,514 @@
#ifndef DQNT_H
#define DQNT_H
/*
#define DQNT_IMPLEMENTATION // Enable the implementation
#define DQNT_MAKE_STATIC // Make all functions be static
#include "dqnt.h"
*/
#ifdef DQNT_MAKE_STATIC
#define DQNT_FILE_SCOPE static
#else
#define DQNT_FILE_SCOPE
#endif
////////////////////////////////////////////////////////////////////////////////
//
// HEADER
//
////////////////////////////////////////////////////////////////////////////////
#include "stdint.h"
#define LOCAL_PERSIST static
#define FILE_SCOPE static
typedef uint64_t u64;
typedef uint32_t u32;
typedef uint16_t u16;
typedef uint8_t u8;
typedef int32_t i64;
typedef int32_t i32;
typedef int64_t i16;
typedef double f64;
typedef float f32;
#define DQNT_INVALID_CODE_PATH 0
#define DQNT_ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0]))
#define DQNT_ASSERT(expr) if (!(expr)) { (*((i32 *)0)) = 0; }
#define DQNT_MATH_PI 3.14159265359f
#define DQNT_MATH_ABS(x) (((x) < 0) ? (-(x)) : (x))
#define DQNT_MATH_DEGREES_TO_RADIANS(x) ((x * (MATH_PI / 180.0f)))
#define DQNT_MATH_RADIANS_TO_DEGREES(x) ((x * (180.0f / MATH_PI)))
#define DQNT_MATH_MAX(a, b) ((a) < (b) ? (b) : (a))
#define DQNT_MATH_MIN(a, b) ((a) < (b) ? (a) : (b))
#define DQNT_MATH_SQUARED(x) ((x) * (x))
#define DQNT_MATH_SQRT(x) (sqrtf(x))
////////////////////////////////////////////////////////////////////////////////
// Vec2
////////////////////////////////////////////////////////////////////////////////
typedef union dqnt_v2 {
struct { f32 x, y; };
struct { f32 w, h; };
struct { f32 min, max; };
f32 e[2];
} dqnt_v2;
DQNT_FILE_SCOPE dqnt_v2 V2(f32 x, f32 y);
// Create a 2d-vector using ints and typecast to floats
DQNT_FILE_SCOPE dqnt_v2 V2i(i32 x, i32 y);
////////////////////////////////////////////////////////////////////////////////
// Vec3
////////////////////////////////////////////////////////////////////////////////
typedef union dqnt_v3
{
struct { f32 x, y, z; };
struct { f32 r, g, b; };
f32 e[3];
} dqnt_v3;
DQNT_FILE_SCOPE dqnt_v3 V3i(i32 x, i32 y, i32 z);
DQNT_FILE_SCOPE dqnt_v3 V3(f32 x, f32 y, f32 z);
////////////////////////////////////////////////////////////////////////////////
// Vec3
////////////////////////////////////////////////////////////////////////////////
typedef union dqnt_v4
{
struct { f32 x, y, z, w; };
struct { f32 r, g, b, a; };
f32 e[4];
dqnt_v2 vec2[2];
} dqnt_v4;
DQNT_FILE_SCOPE dqnt_v3 V3i(i32 x, i32 y, i32 z);
DQNT_FILE_SCOPE dqnt_v4 V4(f32 x, f32 y, f32 z, f32 w);
////////////////////////////////////////////////////////////////////////////////
// Other Math
////////////////////////////////////////////////////////////////////////////////
typedef struct Rect
{
dqnt_v2 min;
dqnt_v2 max;
} dqnt_rect;
////////////////////////////////////////////////////////////////////////////////
// String Ops
////////////////////////////////////////////////////////////////////////////////
DQNT_FILE_SCOPE bool dqnt_char_is_digit (char c);
DQNT_FILE_SCOPE bool dqnt_char_is_alpha (char c);
DQNT_FILE_SCOPE bool dqnt_char_is_alphanum(char c);
DQNT_FILE_SCOPE i32 dqnt_strcmp (const char *a, const char *b);
// Returns the length without the null terminator
DQNT_FILE_SCOPE i32 dqnt_strlen (const char *a);
DQNT_FILE_SCOPE char *dqnt_strncpy(char *dest, const char *src, i32 numChars);
#define DQNT_I32_TO_STR_MAX_BUF_SIZE 11
DQNT_FILE_SCOPE bool dqnt_str_reverse(char *buf, const i32 bufSize);
DQNT_FILE_SCOPE i32 dqnt_str_to_i32 (char *const buf, const i32 bufSize);
DQNT_FILE_SCOPE void dqnt_i32_to_str (i32 value, char *buf, i32 bufSize);
DQNT_FILE_SCOPE i32 dqnt_wstrcmp(const wchar_t *a, const wchar_t *b);
DQNT_FILE_SCOPE void dqnt_wstrcat(const wchar_t *a, i32 lenA, const wchar_t *b, i32 lenB, wchar_t *out, i32 outLen);
DQNT_FILE_SCOPE i32 dqnt_wstrlen(const wchar_t *a);
////////////////////////////////////////////////////////////////////////////////
// Timer
////////////////////////////////////////////////////////////////////////////////
DQNT_FILE_SCOPE f64 dqnt_time_now_in_s();
DQNT_FILE_SCOPE f64 dqnt_time_now_in_ms();
////////////////////////////////////////////////////////////////////////////////
// PCG (Permuted Congruential Generator) Random Number Generator
////////////////////////////////////////////////////////////////////////////////
typedef struct DqntRandPCGState
{
u64 state[2];
} DqntRandPCGState;
// You can manually specify a seed by calling init_with_seed, otherwise it
// automatically creates a seed using rdtsc. The generator is not valid until
// it's been seeded.
DQNT_FILE_SCOPE void dqnt_rnd_pcg_init_with_seed(DqntRandPCGState *pcg, u32 seed);
DQNT_FILE_SCOPE void dqnt_rnd_pcg_init(DqntRandPCGState *pcg);
// Returns a random number N between [0, 0xFFFFFFFF]
DQNT_FILE_SCOPE u32 dqnt_rnd_pcg_next (DqntRandPCGState *pcg);
// Returns a random float N between [0.0, 1.0f]
DQNT_FILE_SCOPE f32 dqnt_rnd_pcg_nextf(DqntRandPCGState *pcg);
// Returns a random integer N between [min, max]
DQNT_FILE_SCOPE i32 dqnt_rnd_pcg_range(DqntRandPCGState *pcg, i32 min, i32 max);
#endif /* DQNT_H */
////////////////////////////////////////////////////////////////////////////////
//
// IMPLEMENTATION
//
////////////////////////////////////////////////////////////////////////////////
#ifdef DQNT_IMPLEMENTATION
#undef DQNT_IMPLEMENTATION
#ifdef _WIN32
#define DQNT_WIN32
#include "Windows.h"
#define WIN32_LEAN_AND_MEAN
#endif
////////////////////////////////////////////////////////////////////////////////
// Vec2
////////////////////////////////////////////////////////////////////////////////
DQNT_FILE_SCOPE inline dqnt_v2 dqnt_vec2(f32 x, f32 y)
{
dqnt_v2 result = {};
result.x = x;
result.y = y;
return result;
}
DQNT_FILE_SCOPE inline dqnt_v2 dqnt_vec2i(i32 x, i32 y)
{
dqnt_v2 result = dqnt_vec2((f32)x, (f32)y);
return result;
}
DQNT_FILE_SCOPE dqnt_v2 dqnt_vec2_constrain_to_ratio(dqnt_v2 dim,
dqnt_v2 ratio)
{
dqnt_v2 result = {};
f32 numRatioIncrementsToWidth = (f32)(dim.w / ratio.w);
f32 numRatioIncrementsToHeight = (f32)(dim.h / ratio.h);
f32 leastIncrementsToSide =
DQNT_MATH_MIN(numRatioIncrementsToHeight, numRatioIncrementsToWidth);
result.w = (f32)(ratio.w * leastIncrementsToSide);
result.h = (f32)(ratio.h * leastIncrementsToSide);
return result;
}
////////////////////////////////////////////////////////////////////////////////
// Vec3
////////////////////////////////////////////////////////////////////////////////
DQNT_FILE_SCOPE inline dqnt_v3 dqnt_vec3(f32 x, f32 y, f32 z)
{
dqnt_v3 result = {};
result.x = x;
result.y = y;
result.z = z;
return result;
}
DQNT_FILE_SCOPE inline dqnt_v3 dqnt_vec3i(i32 x, i32 y, i32 z)
{
dqnt_v3 result = dqnt_vec3((f32)x, (f32)y, (f32)z);
return result;
}
////////////////////////////////////////////////////////////////////////////////
// Vec4
////////////////////////////////////////////////////////////////////////////////
DQNT_FILE_SCOPE inline dqnt_v4 dqnt_vec4(f32 x, f32 y, f32 z, f32 w)
{
dqnt_v4 result = {x, y, z, w};
return result;
}
DQNT_FILE_SCOPE inline dqnt_v4 dqnt_vec4i(i32 x, i32 y, i32 z, i32 w) {
dqnt_v4 result = dqnt_vec4((f32)x, (f32)y, (f32)z, (f32)w);
return result;
}
////////////////////////////////////////////////////////////////////////////////
// String Ops
////////////////////////////////////////////////////////////////////////////////
DQNT_FILE_SCOPE bool dqnt_char_is_digit(char c)
{
if (c >= '0' && c <= '9') return true;
return false;
}
DQNT_FILE_SCOPE bool dqnt_char_is_alpha(char c)
{
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) return true;
return false;
}
DQNT_FILE_SCOPE bool dqnt_char_is_alphanum(char c)
{
if (dqnt_char_is_alpha(c) || dqnt_char_is_digit(c)) return true;
return false;
}
DQNT_FILE_SCOPE i32 dqnt_strcmp(const char *a, const char *b)
{
if (!a && !b) return -1;
if (!a) return -1;
if (!b) return -1;
while ((*a) == (*b))
{
if (!(*a)) return 0;
a++;
b++;
}
return (((*a) < (*b)) ? -1 : 1);
}
DQNT_FILE_SCOPE i32 dqnt_strlen(const char *a)
{
i32 result = 0;
while (a && a[result]) result++;
return result;
}
DQNT_FILE_SCOPE char *dqnt_strncpy(char *dest, const char *src, i32 numChars)
{
if (!dest) return NULL;
if (!src) return dest;
for (i32 i = 0; i < numChars; i++)
dest[i] = src[i];
return dest;
}
DQNT_FILE_SCOPE bool dqnt_str_reverse(char *buf, const i32 bufSize)
{
if (!buf) return false;
i32 mid = bufSize / 2;
for (i32 i = 0; i < mid; i++)
{
char tmp = buf[i];
buf[i] = buf[(bufSize - 1) - i];
buf[(bufSize - 1) - i] = tmp;
}
return true;
}
DQNT_FILE_SCOPE i32 dqnt_str_to_i32(char *const buf, const i32 bufSize)
{
if (!buf || bufSize == 0) return 0;
i32 index = 0;
bool isNegative = false;
if (buf[index] == '-' || buf[index] == '+')
{
if (buf[index] == '-') isNegative = true;
index++;
}
else if (!dqnt_char_is_digit(buf[index]))
{
return 0;
}
i32 result = 0;
for (i32 i = index; i < bufSize; i++)
{
if (dqnt_char_is_digit(buf[i]))
{
result *= 10;
result += (buf[i] - '0');
}
else
{
break;
}
}
if (isNegative) result *= -1;
return result;
}
DQNT_FILE_SCOPE void dqnt_i32_to_str(i32 value, char *buf, i32 bufSize)
{
if (!buf || bufSize == 0) return;
if (value == 0)
{
buf[0] = '0';
return;
}
// NOTE(doyle): Max 32bit integer (+-)2147483647
i32 charIndex = 0;
bool negative = false;
if (value < 0) negative = true;
if (negative) buf[charIndex++] = '-';
i32 val = DQNT_MATH_ABS(value);
while (val != 0 && charIndex < bufSize)
{
i32 rem = val % 10;
buf[charIndex++] = (u8)rem + '0';
val /= 10;
}
// NOTE(doyle): If string is negative, we only want to reverse starting
// from the second character, so we don't put the negative sign at the end
if (negative)
{
dqnt_str_reverse(buf + 1, charIndex - 1);
}
else
{
dqnt_str_reverse(buf, charIndex);
}
}
DQNT_FILE_SCOPE i32 dqnt_wstrcmp(const wchar_t *a, const wchar_t *b)
{
if (!a && !b) return -1;
if (!a) return -1;
if (!b) return -1;
while ((*a) == (*b))
{
if (!(*a)) return 0;
a++;
b++;
}
return (((*a) < (*b)) ? -1 : 1);
}
DQNT_FILE_SCOPE i32 dqnt_wstrlen(const wchar_t *a)
{
i32 result = 0;
while (a && a[result]) result++;
return result;
}
////////////////////////////////////////////////////////////////////////////////
// Timer
////////////////////////////////////////////////////////////////////////////////
#ifdef DQNT_WIN32
inline FILE_SCOPE f64 dqnt_win32_query_perf_counter_time_in_s_internal()
{
LOCAL_PERSIST LARGE_INTEGER queryPerformanceFrequency = {};
if (queryPerformanceFrequency.QuadPart == 0)
{
QueryPerformanceFrequency(&queryPerformanceFrequency);
DQNT_ASSERT(queryPerformanceFrequency.QuadPart != 0);
}
LARGE_INTEGER qpcResult;
QueryPerformanceCounter(&qpcResult);
// Convert to seconds
f64 timestamp =
(f64)(qpcResult.QuadPart / queryPerformanceFrequency.QuadPart);
return timestamp;
}
#endif
f64 dqnt_time_now_in_s()
{
#ifdef _WIN32
return dqnt_win32_query_perf_counter_time_in_s_internal();
#else
DQNT_ASSERT(DQNT_INVALID_CODE_PATH);
return 0;
#endif
};
f64 dqnt_time_now_in_ms()
{
return dqnt_time_now_in_s() * 1000.0f;
}
////////////////////////////////////////////////////////////////////////////////
// PCG (Permuted Congruential Generator) Random Number Generator
////////////////////////////////////////////////////////////////////////////////
// Public Domain library with thanks to Mattias Gustavsson
// https://github.com/mattiasgustavsson/libs/blob/master/docs/rnd.md
// Convert a randomized u32 value to a float value x in the range 0.0f <= x
// < 1.0f. Contributed by Jonatan Hedborg
FILE_SCOPE f32 dqnt_rnd_f32_normalized_from_u32_internal(u32 value)
{
u32 exponent = 127;
u32 mantissa = value >> 9;
u32 result = (exponent << 23) | mantissa;
f32 fresult = *(f32 *)(&result);
return fresult - 1.0f;
}
FILE_SCOPE u64 dqnt_rnd_murmur3_avalanche64_internal(u64 h)
{
h ^= h >> 33;
h *= 0xff51afd7ed558ccd;
h ^= h >> 33;
h *= 0xc4ceb9fe1a85ec53;
h ^= h >> 33;
return h;
}
FILE_SCOPE u32 dqnt_rnd_make_seed_internal()
{
#ifdef _WIN32
__int64 numClockCycles = __rdtsc();
return (u32)numClockCycles;
#else
unsigned long long numClockCycles = rdtsc();
return (u32)numClockCycles;
#endif
}
DQNT_FILE_SCOPE void dqnt_rnd_pcg_init_with_seed(DqntRandPCGState *pcg, u32 seed)
{
u64 value = (((u64)seed) << 1ULL) | 1ULL;
value = dqnt_rnd_murmur3_avalanche64_internal(value);
pcg->state[0] = 0U;
pcg->state[1] = (value << 1ULL) | 1ULL;
dqnt_rnd_pcg_next(pcg);
pcg->state[0] += dqnt_rnd_murmur3_avalanche64_internal(value);
dqnt_rnd_pcg_next(pcg);
}
DQNT_FILE_SCOPE void dqnt_rnd_pcg_init(DqntRandPCGState *pcg)
{
u32 seed = dqnt_rnd_make_seed_internal();
dqnt_rnd_pcg_init_with_seed(pcg, seed);
}
DQNT_FILE_SCOPE u32 dqnt_rnd_pcg_next(DqntRandPCGState *pcg)
{
u64 oldstate = pcg->state[0];
pcg->state[0] = oldstate * 0x5851f42d4c957f2dULL + pcg->state[1];
u32 xorshifted = (u32)(((oldstate >> 18ULL) ^ oldstate) >> 27ULL);
u32 rot = (u32)(oldstate >> 59ULL);
return (xorshifted >> rot) | (xorshifted << ((-(i32)rot) & 31));
}
DQNT_FILE_SCOPE f32 dqnt_rnd_pcg_nextf(DqntRandPCGState *pcg)
{
return dqnt_rnd_f32_normalized_from_u32_internal(dqnt_rnd_pcg_next(pcg));
}
DQNT_FILE_SCOPE i32 dqnt_rnd_pcg_range(DqntRandPCGState *pcg, i32 min, i32 max)
{
i32 const range = (max - min) + 1;
if (range <= 0) return min;
i32 const value = (i32)(dqnt_rnd_pcg_nextf(pcg) * range);
return min + value;
}
#endif /* DQNT_IMPLEMENTATION */

363
dqnt_unit_test.cpp Normal file
View File

@ -0,0 +1,363 @@
#define DQNT_IMPLEMENTATION
#define DQNT_MAKE_STATIC
#include "dqnt.h"
#include "stdio.h"
void dqnt_strings_test()
{
{ // Char Checks
DQNT_ASSERT(dqnt_char_is_alpha('a') == true);
DQNT_ASSERT(dqnt_char_is_alpha('A') == true);
DQNT_ASSERT(dqnt_char_is_alpha('0') == false);
DQNT_ASSERT(dqnt_char_is_alpha('@') == false);
DQNT_ASSERT(dqnt_char_is_alpha(' ') == false);
DQNT_ASSERT(dqnt_char_is_alpha('\n') == false);
DQNT_ASSERT(dqnt_char_is_digit('1') == true);
DQNT_ASSERT(dqnt_char_is_digit('n') == false);
DQNT_ASSERT(dqnt_char_is_digit('N') == false);
DQNT_ASSERT(dqnt_char_is_digit('*') == false);
DQNT_ASSERT(dqnt_char_is_digit(' ') == false);
DQNT_ASSERT(dqnt_char_is_digit('\n') == false);
DQNT_ASSERT(dqnt_char_is_alphanum('1') == true);
DQNT_ASSERT(dqnt_char_is_alphanum('a') == true);
DQNT_ASSERT(dqnt_char_is_alphanum('A') == true);
DQNT_ASSERT(dqnt_char_is_alphanum('*') == false);
DQNT_ASSERT(dqnt_char_is_alphanum(' ') == false);
DQNT_ASSERT(dqnt_char_is_alphanum('\n') == false);
printf("dqnt_strings_test(): char_checks: Completed successfully\n");
}
// String Checks
{
// strcmp
{
char *a = "str_a";
// Check simple compares
{
DQNT_ASSERT(dqnt_strcmp(a, "str_a") == +0);
DQNT_ASSERT(dqnt_strcmp(a, "str_b") == -1);
DQNT_ASSERT(dqnt_strcmp("str_b", a) == +1);
DQNT_ASSERT(dqnt_strcmp(a, "") == +1);
DQNT_ASSERT(dqnt_strcmp("", "") == 0);
// NOTE: Check that the string has not been trashed.
DQNT_ASSERT(dqnt_strcmp(a, "str_a") == +0);
}
// Check ops against null
{
DQNT_ASSERT(dqnt_strcmp(NULL, NULL) != +0);
DQNT_ASSERT(dqnt_strcmp(a, NULL) != +0);
DQNT_ASSERT(dqnt_strcmp(NULL, a) != +0);
}
printf("dqnt_strings_test(): strcmp: Completed successfully\n");
}
// strlen
{
char *a = "str_a";
DQNT_ASSERT(dqnt_strlen(a) == 5);
DQNT_ASSERT(dqnt_strlen("") == 0);
DQNT_ASSERT(dqnt_strlen(" a ") == 6);
DQNT_ASSERT(dqnt_strlen("a\n") == 2);
// NOTE: Check that the string has not been trashed.
DQNT_ASSERT(dqnt_strcmp(a, "str_a") == 0);
DQNT_ASSERT(dqnt_strlen(NULL) == 0);
printf("dqnt_strings_test(): strlen: Completed successfully\n");
}
// strncpy
{
{
char *a = "str_a";
char b[10] = {};
// Check copy into empty array
{
char *result = dqnt_strncpy(b, a, dqnt_strlen(a));
DQNT_ASSERT(dqnt_strcmp(b, "str_a") == 0);
DQNT_ASSERT(dqnt_strcmp(a, "str_a") == 0);
DQNT_ASSERT(dqnt_strcmp(result, "str_a") == 0);
DQNT_ASSERT(dqnt_strlen(result) == 5);
}
// Check copy into array offset, overlap with old results
{
char *newResult = dqnt_strncpy(&b[1], a, dqnt_strlen(a));
DQNT_ASSERT(dqnt_strcmp(newResult, "str_a") == 0);
DQNT_ASSERT(dqnt_strlen(newResult) == 5);
DQNT_ASSERT(dqnt_strcmp(a, "str_a") == 0);
DQNT_ASSERT(dqnt_strlen(a) == 5);
DQNT_ASSERT(dqnt_strcmp(b, "sstr_a") == 0);
DQNT_ASSERT(dqnt_strlen(b) == 6);
}
}
// Check strncpy with NULL pointers
{
DQNT_ASSERT(dqnt_strncpy(NULL, NULL, 5) == NULL);
char *a = "str";
char *result = dqnt_strncpy(a, NULL, 5);
DQNT_ASSERT(dqnt_strcmp(a, "str") == 0);
DQNT_ASSERT(dqnt_strcmp(result, "str") == 0);
DQNT_ASSERT(dqnt_strcmp(result, a) == 0);
}
// Check strncpy with 0 chars to copy
{
char *a = "str";
char *b = "ing";
char *result = dqnt_strncpy(a, b, 0);
DQNT_ASSERT(dqnt_strcmp(a, "str") == 0);
DQNT_ASSERT(dqnt_strcmp(b, "ing") == 0);
DQNT_ASSERT(dqnt_strcmp(result, "str") == 0);
}
printf("dqnt_strings_test(): strncpy: Completed successfully\n");
}
// str_reverse
{
// Basic reverse operations
{
char a[] = "aba";
DQNT_ASSERT(dqnt_str_reverse(a, dqnt_strlen(a)) == true);
DQNT_ASSERT(dqnt_strcmp(a, "aba") == 0);
DQNT_ASSERT(dqnt_str_reverse(a, 2) == true);
DQNT_ASSERT(dqnt_strcmp(a, "baa") == 0);
DQNT_ASSERT(dqnt_str_reverse(a, dqnt_strlen(a)) == true);
DQNT_ASSERT(dqnt_strcmp(a, "aab") == 0);
DQNT_ASSERT(dqnt_str_reverse(&a[1], 2) == true);
DQNT_ASSERT(dqnt_strcmp(a, "aba") == 0);
DQNT_ASSERT(dqnt_str_reverse(a, 0) == true);
DQNT_ASSERT(dqnt_strcmp(a, "aba") == 0);
}
// Try reverse empty string
{
char a[] = "";
DQNT_ASSERT(dqnt_str_reverse(a, dqnt_strlen(a)) == true);
DQNT_ASSERT(dqnt_strcmp(a, "") == 0);
}
// Try reverse single char string
{
char a[] = "a";
DQNT_ASSERT(dqnt_str_reverse(a, dqnt_strlen(a)) == true);
DQNT_ASSERT(dqnt_strcmp(a, "a") == 0);
DQNT_ASSERT(dqnt_str_reverse(a, 0) == true);
DQNT_ASSERT(dqnt_strcmp(a, "a") == 0);
}
printf(
"dqnt_strings_test(): str_reverse: Completed successfully\n");
}
// str_to_i32
{
char *a = "123";
DQNT_ASSERT(dqnt_str_to_i32(a, dqnt_strlen(a)) == 123);
char *b = "-123";
DQNT_ASSERT(dqnt_str_to_i32(b, dqnt_strlen(b)) == -123);
DQNT_ASSERT(dqnt_str_to_i32(b, 1) == 0);
DQNT_ASSERT(dqnt_str_to_i32(&b[1], dqnt_strlen(&b[1])) == 123);
char *c = "-0";
DQNT_ASSERT(dqnt_str_to_i32(c, dqnt_strlen(c)) == 0);
char *d = "+123";
DQNT_ASSERT(dqnt_str_to_i32(d, dqnt_strlen(d)) == 123);
DQNT_ASSERT(dqnt_str_to_i32(&d[1], dqnt_strlen(&d[1])) == 123);
printf("dqnt_strings_test(): str_to_i32: Completed successfully\n");
}
// i32_to_str
{
char a[DQNT_I32_TO_STR_MAX_BUF_SIZE] = {};
dqnt_i32_to_str(+100, a, DQNT_ARRAY_COUNT(a));
DQNT_ASSERT(dqnt_strcmp(a, "100") == 0);
char b[DQNT_I32_TO_STR_MAX_BUF_SIZE] = {};
dqnt_i32_to_str(-100, b, DQNT_ARRAY_COUNT(b));
DQNT_ASSERT(dqnt_strcmp(b, "-100") == 0);
char c[DQNT_I32_TO_STR_MAX_BUF_SIZE] = {};
dqnt_i32_to_str(0, c, DQNT_ARRAY_COUNT(c));
DQNT_ASSERT(dqnt_strcmp(c, "0") == 0);
printf("dqnt_strings_test(): str_to_i32: Completed successfully\n");
}
}
// Wide String Checks
{
// wstrcmp
{
wchar_t *a = L"str_a";
// Check simple compares
{
DQNT_ASSERT(dqnt_wstrcmp(a, L"str_a") == +0);
DQNT_ASSERT(dqnt_wstrcmp(a, L"str_b") == -1);
DQNT_ASSERT(dqnt_wstrcmp(L"str_b", a) == +1);
DQNT_ASSERT(dqnt_wstrcmp(a, L"") == +1);
DQNT_ASSERT(dqnt_wstrcmp(L"", L"") == 0);
// NOTE: Check that the string has not been trashed.
DQNT_ASSERT(dqnt_wstrcmp(a, L"str_a") == +0);
}
// Check ops against null
{
DQNT_ASSERT(dqnt_wstrcmp(NULL, NULL) != +0);
DQNT_ASSERT(dqnt_wstrcmp(a, NULL) != +0);
DQNT_ASSERT(dqnt_wstrcmp(NULL, a) != +0);
}
printf("dqnt_strings_test(): wstrcmp: Completed successfully\n");
}
// wstrlen
{
wchar_t *a = L"str_a";
DQNT_ASSERT(dqnt_wstrlen(a) == 5);
DQNT_ASSERT(dqnt_wstrlen(L"") == 0);
DQNT_ASSERT(dqnt_wstrlen(L" a ") == 6);
DQNT_ASSERT(dqnt_wstrlen(L"a\n") == 2);
// NOTE: Check that the string has not been trashed.
DQNT_ASSERT(dqnt_wstrcmp(a, L"str_a") == 0);
DQNT_ASSERT(dqnt_wstrlen(NULL) == 0);
printf("dqnt_strings_test(): wstrlen: Completed successfully\n");
}
}
printf("dqnt_strings_test(): Completed successfully\n");
}
#include "Windows.h"
#define WIN32_LEAN_AND_MEAN
void dqnt_other_test()
{
{ // Test Win32 Sleep
// NOTE: Win32 Sleep is not granular to a certain point so sleep excessively to meet
u32 sleepInMs = 100;
f64 startInMs = dqnt_time_now_in_ms();
Sleep(sleepInMs);
f64 endInMs = dqnt_time_now_in_ms();
DQNT_ASSERT(startInMs < endInMs);
printf("dqnt_other_test(): time_now: Completed successfully\n");
}
printf("dqnt_other_test(): Completed successfully\n");
}
void dqnt_random_test() {
DqntRandPCGState pcg;
dqnt_rnd_pcg_init(&pcg);
for (i32 i = 0; i < 10; i++)
{
i32 min = -100;
i32 max = 100000;
i32 result = dqnt_rnd_pcg_range(&pcg, min, max);
DQNT_ASSERT(result >= min && result <= max)
f32 randF32 = dqnt_rnd_pcg_nextf(&pcg);
DQNT_ASSERT(randF32 >= 0.0f && randF32 <= 1.0f);
printf("dqnt_random_test(): rnd_pcg: Completed successfully\n");
}
printf("dqnt_random_test(): Completed successfully\n");
}
void dqnt_vec_test()
{
{ // V2
{
dqnt_v2 vec = dqnt_vec2(5.5f, 5.0f);
DQNT_ASSERT(vec.x == 5.5f && vec.y == 5.0f);
DQNT_ASSERT(vec.w == 5.5f && vec.h == 5.0f);
}
{
dqnt_v2 vec = dqnt_vec2i(3, 5);
DQNT_ASSERT(vec.x == 3 && vec.y == 5.0f);
DQNT_ASSERT(vec.w == 3 && vec.h == 5.0f);
}
{ // constrain_to_ratio
dqnt_v2 ratio = dqnt_vec2(16, 9);
dqnt_v2 dim = dqnt_vec2(2000, 1080);
dqnt_v2 result = dqnt_vec2_constrain_to_ratio(dim, ratio);
DQNT_ASSERT(result.w == 1920 && result.h == 1080);
}
printf("dqnt_vec_test(): vec2: Completed successfully\n");
}
{ // V3
{
dqnt_v3 vec = dqnt_vec3(5.5f, 5.0f, 5.875f);
DQNT_ASSERT(vec.x == 5.5f && vec.y == 5.0f && vec.z == 5.875f);
DQNT_ASSERT(vec.r == 5.5f && vec.g == 5.0f && vec.b == 5.875f);
}
{
dqnt_v3 vec = dqnt_vec3(3, 4, 5);
DQNT_ASSERT(vec.x == 3 && vec.y == 4 && vec.z == 5);
DQNT_ASSERT(vec.r == 3 && vec.g == 4 && vec.b == 5);
}
printf("dqnt_vec_test(): vec3: Completed successfully\n");
}
{ // V4
{
dqnt_v4 vec = dqnt_vec4(5.5f, 5.0f, 5.875f, 5.928f);
DQNT_ASSERT(vec.x == 5.5f && vec.y == 5.0f && vec.z == 5.875f && vec.w == 5.928f);
DQNT_ASSERT(vec.r == 5.5f && vec.g == 5.0f && vec.b == 5.875f && vec.a == 5.928f);
}
{
dqnt_v4 vec = dqnt_vec4i(3, 4, 5, 6);
DQNT_ASSERT(vec.x == 3 && vec.y == 4 && vec.z == 5 && vec.w == 6);
DQNT_ASSERT(vec.r == 3 && vec.g == 4 && vec.b == 5 && vec.a == 6);
}
printf("dqnt_vec_test(): vec4: Completed successfully\n");
}
printf("dqnt_vec_test(): Completed successfully\n");
}
int main(void)
{
dqnt_strings_test();
dqnt_random_test();
dqnt_vec_test();
dqnt_other_test();
return 0;
}

29
misc/dqnt_unit_test.sln Normal file
View File

@ -0,0 +1,29 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{911E67C6-3D85-4FCE-B560-20A9C3E3FF48}") = "dqnt_unit_test", "..\bin\dqnt_unit_test.exe", "{87785192-6F49-4F85-AA0D-F0AFA5CCCDDA}"
ProjectSection(DebuggerProjectSystem) = preProject
PortSupplier = 00000000-0000-0000-0000-000000000000
Executable = C:\git\dqnt\bin\dqnt_unit_test.exe
RemoteMachine = THAI-PC
StartingDirectory = C:\git\dqnt
Environment = Default
LaunchingEngine = 00000000-0000-0000-0000-000000000000
UseLegacyDebugEngines = No
LaunchSQLEngine = No
AttachLaunchAction = No
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{87785192-6F49-4F85-AA0D-F0AFA5CCCDDA}.Release|x86.ActiveCfg = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal