Add soft asserts, fixed string test, conditional asserts

This commit is contained in:
doyle 2019-09-23 23:21:14 +10:00
parent 4150864d59
commit 9dd058a5f0
2 changed files with 104 additions and 30 deletions

View File

@ -1,3 +1,4 @@
// #define DQN_ENABLE_ASSERTS to enable DQN_ASSERT, otherwise compile out and use non aborting asserts where appropriate
// #define DQN_USE_PRIMITIVE_TYPEDEFS to enable typical typedefs such as i32 = int32_t .. etc // #define DQN_USE_PRIMITIVE_TYPEDEFS to enable typical typedefs such as i32 = int32_t .. etc
// #define DQN_IMPLEMENTATION in one and only one C++ file to enable the header file // #define DQN_IMPLEMENTATION in one and only one C++ file to enable the header file
@ -234,14 +235,27 @@ STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char comma, char peri
#endif #endif
#define DQN_INVALID_CODE_PATH 0 #define DQN_INVALID_CODE_PATH 0
#define DQN_ASSERT(expr) DQN_ASSERT_MSG(expr, "") #if defined(DQN_ENABLE_ASSERTS)
#define DQN_ASSERT_MSG(expr, fmt, ...) \ #define DQN_ASSERT(expr) DQN_ASSERT_MSG(expr, "")
#define DQN_ASSERT_MSG(expr, fmt, ...) \
if (!(expr)) \ if (!(expr)) \
{ \ { \
DQN_LOG_E("Assert: [" #expr "] " fmt, ##__VA_ARGS__); \ DQN_LOG_E("Assert: [" #expr "] " fmt, ##__VA_ARGS__); \
DEBUG_BREAK; \ DEBUG_BREAK; \
} }
#define DQN_IF_ASSERT(expr) DQN_IF_ASSERT_MSG(expr, "")
#define DQN_IF_ASSERT_MSG(expr, fmt, ...) \
DQN_ASSERT_MSG(expr, fmt, ## __VA_ARGS__); \
if (0)
#else
#define DQN_ASSERT(expr)
#define DQN_ASSERT_MSG(expr, fmt, ...)
#define DQN_IF_ASSERT(expr) DQN_IF_ASSERT_MSG(expr, "")
#define DQN_IF_ASSERT_MSG(expr, fmt, ...) \
if (!(expr) && DQN_LOG_E("Soft assert: [" #expr "] " fmt, ## __VA_ARGS__))
#endif
#define DQN_SECONDS_TO_MS(val) ((val) * 1000.0f) #define DQN_SECONDS_TO_MS(val) ((val) * 1000.0f)
#define DQN_MATH_PI 3.14159265359f #define DQN_MATH_PI 3.14159265359f
@ -339,9 +353,9 @@ struct DqnDeferHelper
DqnDefer<Lambda> operator+(Lambda lambda) { return DqnDefer<Lambda>(lambda); }; DqnDefer<Lambda> operator+(Lambda lambda) { return DqnDefer<Lambda>(lambda); };
}; };
#define DQN_TOKEN_COMBINE(x, y) x ## y #define DQN_TOKEN_COMBINE2(x, y) x ## y
#define DQN_TOKEN_COMBINE2(x, y) DQN_TOKEN_COMBINE(x, y) #define DQN_TOKEN_COMBINE(x, y) DQN_TOKEN_COMBINE2(x, y)
#define DQN_UNIQUE_NAME(prefix) DQN_TOKEN_COMBINE2(prefix, __COUNTER__) #define DQN_UNIQUE_NAME(prefix) DQN_TOKEN_COMBINE(prefix, __COUNTER__)
#define DQN_DEFER const auto DQN_UNIQUE_NAME(defer_lambda_) = DqnDeferHelper() + [&]() #define DQN_DEFER const auto DQN_UNIQUE_NAME(defer_lambda_) = DqnDeferHelper() + [&]()
enum struct Dqn_LogType enum struct Dqn_LogType
@ -637,7 +651,7 @@ struct Dqn_MemArenaScopedRegion
#define DQN_MEM_ARENA_ALLOC_ARRAY(arena, T, num) (T *)Dqn_MemArena_Alloc(arena, sizeof(T) * num DQN_DEBUG_PARAMS) #define DQN_MEM_ARENA_ALLOC_ARRAY(arena, T, num) (T *)Dqn_MemArena_Alloc(arena, sizeof(T) * num DQN_DEBUG_PARAMS)
#define DQN_MEM_ARENA_ALLOC_STRUCT(arena, T) (T *)Dqn_MemArena_Alloc(arena, sizeof(T) DQN_DEBUG_PARAMS) #define DQN_MEM_ARENA_ALLOC_STRUCT(arena, T) (T *)Dqn_MemArena_Alloc(arena, sizeof(T) DQN_DEBUG_PARAMS)
#define DQN_MEM_ARENA_RESERVE(arena, size) Dqn_MemArena_Reserve(arena, size DQN_DEBUG_PARAMS) #define DQN_MEM_ARENA_RESERVE(arena, size) Dqn_MemArena_Reserve(arena, size DQN_DEBUG_PARAMS)
#define DQN_MEM_ARENA_FREE(arena) Dqn_MemArena_Free #define DQN_MEM_ARENA_FREE(arena) Dqn_MemArena_Free(arena)
DQN_HEADER_COPY_END DQN_HEADER_COPY_END
// @ ------------------------------------------------------------------------------------------------- // @ -------------------------------------------------------------------------------------------------
@ -879,7 +893,7 @@ DQN_HEADER_COPY_PROTOTYPE(template <typename T> inline Dqn_Slice<T>, Dqn_Slice_C
Dqn_Slice<T> result = {}; Dqn_Slice<T> result = {};
result.len = len; result.len = len;
result.buf = DQN_MEM_ARENA_ALLOC_ARRAY(arena, T, len); result.buf = DQN_MEM_ARENA_ALLOC_ARRAY(arena, T, len);
MemCopy(result.buf, src, len * sizeof(T)); memcpy(result.buf, src, len * sizeof(T));
return result; return result;
} }
@ -950,7 +964,7 @@ DQN_HEADER_COPY_PROTOTYPE(template <typename T> char *, Dqn_Asprintf(T *arena, c
template <typename T> void Dqn__EraseStableFromCArray(T *array, Dqn_isize len, Dqn_isize max, Dqn_isize index) template <typename T> void Dqn__EraseStableFromCArray(T *array, Dqn_isize len, Dqn_isize max, Dqn_isize index)
{ {
DQN_ASSERT(index >= 0 && index < len); DQN_ASSERT(index >= 0 && index < len);
DQN_ASSERT(len <= max); DQN_ASSERT(len <= max); (void)max;
Dqn_isize next_index = DQN_MIN(index + 1, len); Dqn_isize next_index = DQN_MIN(index + 1, len);
Dqn_usize bytes_to_copy = (len - next_index) * sizeof(T); Dqn_usize bytes_to_copy = (len - next_index) * sizeof(T);
memmove(array + index, array + next_index, bytes_to_copy); memmove(array + index, array + next_index, bytes_to_copy);
@ -963,20 +977,26 @@ DQN_FIXED_ARRAY_TEMPLATE struct Dqn_FixedArray
{ {
T data[MAX_]; T data[MAX_];
Dqn_isize len; Dqn_isize len;
Dqn_isize Max() const { return MAX_; }
T &operator[] (Dqn_isize i) { DQN_ASSERT_MSG(i >= 0 && i < len, "%d >= 0 && %d < %d", i, len); return data[i]; } T &operator[] (Dqn_isize i) { DQN_ASSERT_MSG(i >= 0 && i <= len, "%jd >= 0 && %jd < %jd", i, len); return data[i]; }
T *begin () { return data; } T *begin () { return data; }
T *end () { return data + len; } T *end () { return data + len; }
T *operator+ (Dqn_isize i) { DQN_ASSERT_MSG(i >= 0 && i < len, "%d >= 0 && %d < %d", i, len); return data + i; } T *operator+ (Dqn_isize i) { DQN_ASSERT_MSG(i >= 0 && i <= len, "%jd >= 0 && %jd < %jd", i, len); return data + i; }
T const &operator[] (Dqn_isize i) const { DQN_ASSERT_MSG(i >= 0 && i < len, "%d >= 0 && %d < %d", i, len); return data[i]; } T const &operator[] (Dqn_isize i) const { DQN_ASSERT_MSG(i >= 0 && i <= len, "%jd >= 0 && %jd < %jd", i, i, len); return data[i]; }
T const *begin () const { return data; } T const *begin () const { return data; }
T const *end () const { return data + len; } T const *end () const { return data + len; }
T const *operator+ (Dqn_isize i) const { DQN_ASSERT_MSG(i >= 0 && i < len, "%d >= 0 && %d < %d", i, len); return data + i; } T const *operator+ (Dqn_isize i) const { DQN_ASSERT_MSG(i >= 0 && i <= len, "%jd >= 0 && %jd < %jd", i, len); return data + i; }
}; };
DQN_HEADER_COPY_END DQN_HEADER_COPY_END
DQN_FIXED_ARRAY_TEMPLATE
DQN_HEADER_COPY_PROTOTYPE(int, Dqn_FixedArray_Capacity(DQN_FIXED_ARRAY_TEMPLATE_DECL *))
{
int result = MAX_;
return result;
}
DQN_FIXED_ARRAY_TEMPLATE DQN_FIXED_ARRAY_TEMPLATE
DQN_HEADER_COPY_PROTOTYPE(DQN_FIXED_ARRAY_TEMPLATE_DECL, Dqn_FixedArray_Init(T const *item, int num)) DQN_HEADER_COPY_PROTOTYPE(DQN_FIXED_ARRAY_TEMPLATE_DECL, Dqn_FixedArray_Init(T const *item, int num))
{ {
@ -1020,7 +1040,7 @@ DQN_HEADER_COPY_PROTOTYPE(void, Dqn_FixedArray_Clear(DQN_FIXED_ARRAY_TEMPLATE_DE
DQN_FIXED_ARRAY_TEMPLATE DQN_FIXED_ARRAY_TEMPLATE
DQN_HEADER_COPY_PROTOTYPE(void, Dqn_FixedArray_EraseStable(DQN_FIXED_ARRAY_TEMPLATE_DECL *a, Dqn_isize index)) DQN_HEADER_COPY_PROTOTYPE(void, Dqn_FixedArray_EraseStable(DQN_FIXED_ARRAY_TEMPLATE_DECL *a, Dqn_isize index))
{ {
Dqn__EraseStableFromCArray<T>(a->data, a->len--, a->Max(), index); Dqn__EraseStableFromCArray<T>(a->data, a->len--, MAX_, index);
} }
DQN_FIXED_ARRAY_TEMPLATE DQN_FIXED_ARRAY_TEMPLATE
@ -1220,7 +1240,6 @@ struct Dqn_FixedString
{ {
union { char data[MAX_]; char str[MAX_]; char buf[MAX_]; }; union { char data[MAX_]; char str[MAX_]; char buf[MAX_]; };
Dqn_isize len; Dqn_isize len;
Dqn_isize Max() const { return MAX_; }
Dqn_FixedString() { data[0] = 0; len = 0; } Dqn_FixedString() { data[0] = 0; len = 0; }
Dqn_FixedString(char const *fmt, ...) Dqn_FixedString(char const *fmt, ...)
@ -1232,6 +1251,15 @@ struct Dqn_FixedString
va_end(va); va_end(va);
} }
Dqn_b32 operator==(Dqn_FixedString const &other) const
{
if (len != other.len) return false;
bool result = memcmp(data, other.data, len);
return result;
}
Dqn_b32 operator!=(Dqn_FixedString const &other) const { return !(*this == other); }
char const &operator[] (Dqn_isize i) const { DQN_ASSERT_MSG(i >= 0 && i < len, "%d >= 0 && %d < %d", i, len); return data[i]; } char const &operator[] (Dqn_isize i) const { DQN_ASSERT_MSG(i >= 0 && i < len, "%d >= 0 && %d < %d", i, len); return data[i]; }
char &operator[] (Dqn_isize i) { DQN_ASSERT_MSG(i >= 0 && i < len, "%d >= 0 && %d < %d", i, len); return data[i]; } char &operator[] (Dqn_isize i) { DQN_ASSERT_MSG(i >= 0 && i < len, "%d >= 0 && %d < %d", i, len); return data[i]; }
char const *begin () const { return data; } char const *begin () const { return data; }
@ -1241,36 +1269,53 @@ struct Dqn_FixedString
}; };
DQN_HEADER_COPY_END DQN_HEADER_COPY_END
DQN_HEADER_COPY_PROTOTYPE(template <Dqn_isize MAX_> int, Dqn_FixedString_Capacity(Dqn_FixedString<MAX_> *))
{
int result = MAX_;
return result;
}
DQN_HEADER_COPY_PROTOTYPE(template <Dqn_isize MAX_> void, Dqn_FixedString_Clear(Dqn_FixedString<MAX_> *str)) { *str = {}; } DQN_HEADER_COPY_PROTOTYPE(template <Dqn_isize MAX_> void, Dqn_FixedString_Clear(Dqn_FixedString<MAX_> *str)) { *str = {}; }
DQN_HEADER_COPY_PROTOTYPE(template <Dqn_isize MAX_> void, Dqn_FixedString_AppendVFmt(Dqn_FixedString<MAX_> *str, char const *fmt, va_list va)) DQN_HEADER_COPY_PROTOTYPE(template <Dqn_isize MAX_> Dqn_b32, Dqn_FixedString_AppendVFmt(Dqn_FixedString<MAX_> *str, char const *fmt, va_list va))
{ {
Dqn_isize require = stbsp_vsnprintf(nullptr, 0, fmt, va) + 1; Dqn_isize require = stbsp_vsnprintf(nullptr, 0, fmt, va) + 1;
Dqn_isize space = MAX_ - str->len; Dqn_isize space = MAX_ - str->len;
Dqn_b32 result = require <= space;
DQN_ASSERT(require <= space); DQN_ASSERT(require <= space);
str->len += stbsp_vsnprintf(str->data + str->len, static_cast<int>(space), fmt, va); str->len += stbsp_vsnprintf(str->data + str->len, static_cast<int>(space), fmt, va);
return result;
} }
DQN_HEADER_COPY_PROTOTYPE(template <Dqn_isize MAX_> void, Dqn_FixedString_AppendFmt(Dqn_FixedString<MAX_> *str, char const *fmt, ...)) DQN_HEADER_COPY_PROTOTYPE(template <Dqn_isize MAX_> Dqn_b32, Dqn_FixedString_AppendFmt(Dqn_FixedString<MAX_> *str, char const *fmt, ...))
{ {
va_list va; va_list va;
va_start(va, fmt); va_start(va, fmt);
Dqn_FixedString_AppendVFmt(str, fmt, va); Dqn_b32 result = Dqn_FixedString_AppendVFmt(str, fmt, va);
va_end(va); va_end(va);
return result;
} }
DQN_HEADER_COPY_PROTOTYPE(template <Dqn_isize MAX_> void, Dqn_FixedString_Append(Dqn_FixedString<MAX_> *str, char const *src, Dqn_isize len = -1)) DQN_HEADER_COPY_PROTOTYPE(template <Dqn_isize MAX_> Dqn_b32, Dqn_FixedString_Append(Dqn_FixedString<MAX_> *str, char const *src, Dqn_isize len = -1))
{ {
if (len == -1) len = (Dqn_isize)strlen(src); if (len == -1) len = (Dqn_isize)strlen(src);
Dqn_isize space = MAX_ - str->len; Dqn_isize space = MAX_ - str->len;
DQN_ASSERT(len <= space);
Dqn_b32 result = true;
DQN_IF_ASSERT_MSG(len < space, "len: %jd, space: %jd", len, space)
{
len = space;
result = false;
}
memcpy(str->data + str->len, src, len); memcpy(str->data + str->len, src, len);
str->len += len; str->len += len;
str->str[str->len] = 0; str->str[str->len] = 0;
return result;
} }
// @ ------------------------------------------------------------------------------------------------- // @ -------------------------------------------------------------------------------------------------
// @ // @
// @ NOTE: Dqn_Dqn_U64Str // @ NOTE: Dqn_U64Str
// @ // @
// @ ------------------------------------------------------------------------------------------------- // @ -------------------------------------------------------------------------------------------------
DQN_HEADER_COPY_BEGIN DQN_HEADER_COPY_BEGIN
@ -1327,12 +1372,14 @@ DQN_HEADER_COPY_PROTOTYPE(void, Dqn_LogV(Dqn_LogType type, char const *file, Dqn
fprintf(handle, "\n"); fprintf(handle, "\n");
} }
DQN_HEADER_COPY_PROTOTYPE(void, Dqn_Log(Dqn_LogType type, char const *file, Dqn_usize file_len, char const *func, Dqn_usize func_len, Dqn_usize line, char const *fmt, ...)) // @ return: This returns a boolean as a hack so you can combine it in if expressions. I use it for my IF_ASSERT macro
DQN_HEADER_COPY_PROTOTYPE(Dqn_b32, Dqn_Log(Dqn_LogType type, char const *file, Dqn_usize file_len, char const *func, Dqn_usize func_len, Dqn_usize line, char const *fmt, ...))
{ {
va_list va; va_list va;
va_start(va, fmt); va_start(va, fmt);
Dqn_LogV(type, file, file_len, func, func_len, line, fmt, va); Dqn_LogV(type, file, file_len, func, func_len, line, fmt, va);
va_end(va); va_end(va);
return true;
} }
void *Dqn_MemArena_Alloc(Dqn_MemArena *arena, Dqn_usize size DQN_DEBUG_ARGS); void *Dqn_MemArena_Alloc(Dqn_MemArena *arena, Dqn_usize size DQN_DEBUG_ARGS);
@ -1382,8 +1429,10 @@ DQN_HEADER_COPY_PROTOTYPE(void *, Dqn_Allocator_Allocate(Dqn_Allocator *allocato
{ {
result = malloc(size); result = malloc(size);
if (!result && allocator->type == Dqn_Allocator_Type::XHeap) if (!result && allocator->type == Dqn_Allocator_Type::XHeap)
{
DQN_ASSERT(result); DQN_ASSERT(result);
} }
}
break; break;
case Dqn_Allocator_Type::Arena: case Dqn_Allocator_Type::Arena:
@ -1408,8 +1457,10 @@ DQN_HEADER_COPY_PROTOTYPE(void *, Dqn_Allocator_Realloc(Dqn_Allocator *allocator
{ {
result = realloc(old_ptr, new_size); result = realloc(old_ptr, new_size);
if (!result && allocator->type == Dqn_Allocator_Type::XHeap) if (!result && allocator->type == Dqn_Allocator_Type::XHeap)
{
DQN_ASSERT(result); DQN_ASSERT(result);
} }
}
break; break;
case Dqn_Allocator_Type::Arena: case Dqn_Allocator_Type::Arena:

View File

@ -460,6 +460,29 @@ FILE_SCOPE void UnitTests()
} }
} }
// ---------------------------------------------------------------------------------------------
//
// NOTE: Dqn_FixedString
//
// ---------------------------------------------------------------------------------------------
{
TEST_DECLARE_GROUP_SCOPED(testing_state, "Dqn_FixedString");
// NOTE: Dqn_FixedString_Append
{
TEST_START_SCOPE(testing_state, "Append too much fails");
Dqn_FixedString<4> str = {};
TEST_EXPECT_MSG(testing_state, Dqn_FixedString_Append(&str, "abcd") == false, "We need space for the null-terminator");
}
// NOTE: Dqn_FixedString_AppendFmt
{
TEST_START_SCOPE(testing_state, "Append format string too much fails");
Dqn_FixedString<4> str = {};
TEST_EXPECT_MSG(testing_state, Dqn_FixedString_AppendFmt(&str, "abcd") == false, "We need space for the null-terminator");
}
}
// --------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------
// //
// NOTE: Dqn_Str_ToI64 // NOTE: Dqn_Str_ToI64