Get latest tely changes, w/ new OS primitives from internal project

This commit is contained in:
2026-09-29 22:28:31 +10:00
parent e9c25bae9c
commit d85b66d1da
9 changed files with 4631 additions and 2045 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+184
View File
@@ -1057,6 +1057,36 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Str8Slice cmd_line, DN_OSExecArgs
return result; return result;
} }
DN_API void DN_OS_W32Init(DN_OSW32Core *w32)
{
InitializeCriticalSection(&w32->sync_primitive_free_list_mutex);
QueryPerformanceFrequency(&w32->qpc_frequency);
// NOTE: DPI
HMODULE user32 = LoadLibraryA("user32.dll");
if (user32) {
w32->get_dpi_for_window = (DN_OSW32GetDpiForWindowFunc* )GetProcAddress(user32, "GetDpiForWindow");
w32->get_dpi_for_monitor = (DN_OSW32GetDpiForMonitorFunc * )GetProcAddress(user32, "GetDpiForMonitor");
w32->get_system_metrics_for_dpi = (DN_OSW32GetSystemMetricsForDpiFunc *)GetProcAddress(user32, "GetSystemMetricsForDpi");
FreeLibrary(user32);
}
// NOTE: SetThreadDesc
HMODULE kernel32 = LoadLibraryA("kernel32.dll");
if (kernel32) {
w32->set_thread_description = DN_Cast(DN_OSW32SetThreadDescriptionFunc *) GetProcAddress(kernel32, "SetThreadDescription");
FreeLibrary(kernel32);
}
// NOTE: win32 bcrypt
wchar_t const BCRYPT_ALGORITHM[] = L"RNG";
long /*NTSTATUS*/ init_status = BCryptOpenAlgorithmProvider(&w32->bcrypt_rng_handle, BCRYPT_ALGORITHM, nullptr /*implementation*/, 0 /*flags*/);
if (w32->bcrypt_rng_handle && init_status == 0)
w32->bcrypt_init_success = true;
else
DN_LogErrorF("Failed to initialise Windows secure random number generator, error: %d", init_status);
}
DN_API DN_OSW32Core *DN_OS_W32GetCore() DN_API DN_OSW32Core *DN_OS_W32GetCore()
{ {
DN_Core *dn = DN_Get(); DN_Core *dn = DN_Get();
@@ -1456,6 +1486,160 @@ DN_API void DN_OS_W32ThreadSetName(DN_Str8 name)
DN_TcScratchEnd(&scratch); DN_TcScratchEnd(&scratch);
} }
DN_API DN_OSW32Window* DN_OS_W32WindowFromHwndMaybeAlloc(DN_OSW32Core *w32, HWND hwnd, DN_Arena *arena)
{
DN_OSW32Window *result = nullptr;
for (DN_OSW32Window *check = w32->windows; !result && check; check = check->next) {
if (check->hwnd == hwnd)
result = check;
}
if (!result && arena) {
result = DN_ArenaNewZ(arena, DN_OSW32Window);
if (result) {
result->hwnd = hwnd;
if (w32->windows)
w32->windows->next = result;
result->next = w32->windows;
w32->windows = result;
}
}
return result;
}
DN_API LRESULT __stdcall DN_OS_W32WindowProcCustomTitlebar(HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param)
{
DN_OSW32Core *w32 = DN_OS_W32GetCore();
DN_AssertF(w32, "Using this window proc requires that DN's OS layer has been initialised");
LRESULT result = 0;
bool handled = true;
switch (msg) {
// NOTE: Sent when the size and position of a window's client area must be calculated. By
// processing this message, an application can control the content of the window's client area
// when the size or position of the window changes.
case WM_NCCALCSIZE: {
DN_OSW32Window *w32_window = DN_OS_W32WindowFromHwndMaybeAlloc(w32, hwnd, nullptr);
if (w32_window && w32_window->custom_title_bar) {
// NOTE: Code adapted from raddebugger
// https://github.com/EpicGames/raddebugger/blob/7a5a649b89f6a06abdbaee61540468fca9db58f9/src/win32/window_manager/win32_window_manager.c#L668
//
// The goal here is to subtract away the title bar from the window and restore the pixel
// border that native Windows renders windows with. Note that on Windows 11 a non-maximised
// window has rounded corners which eats into the available client space that is normally
// otherwise eaten into from the native titlebar.
DWORD window_style = GetWindowLongW(hwnd, GWL_STYLE);
bool is_fullscreen = !(window_style & WS_OVERLAPPEDWINDOW);
if (is_fullscreen) {
handled = false;
} else {
DN_UInt dpi = w32->get_dpi_for_window ? w32->get_dpi_for_window(hwnd) : 96;
int frame_x = w32->get_system_metrics_for_dpi ? w32->get_system_metrics_for_dpi(SM_CXFRAME, dpi) : GetSystemMetrics(SM_CXFRAME);
int frame_y = w32->get_system_metrics_for_dpi ? w32->get_system_metrics_for_dpi(SM_CYFRAME, dpi) : GetSystemMetrics(SM_CYFRAME);
int padding = w32->get_system_metrics_for_dpi ? w32->get_system_metrics_for_dpi(SM_CXPADDEDBORDER, dpi) : GetSystemMetrics(SM_CXPADDEDBORDER);
RECT *rect = w_param == 0 ? DN_Cast(RECT *)l_param : (DN_Cast(NCCALCSIZE_PARAMS *)l_param)->rgrc;
rect->right -= frame_x + padding;
rect->left += frame_x + padding;
rect->bottom -= frame_y + padding;
bool is_maximised = IsZoomed(hwnd) != 0;
if (is_maximised) {
rect->top += frame_y + padding;
// If we do not do this hidden taskbar can not be unhidden on mouse hover
// Unfortunately it can create an ugly bottom border when maximized...
rect->bottom -= 1;
} else {
int edge_height = w32->get_system_metrics_for_dpi ? w32->get_system_metrics_for_dpi(SM_CYEDGE, dpi) : GetSystemMetrics(SM_CYEDGE);
rect->top += edge_height;
}
}
} else {
handled = false;
}
} break;
// NOTE: Sent to a window in order to determine what part of the window corresponds to a
// particular screen coordinate. This can happen, for example, when the cursor moves, when a
// mouse button is pressed or released, or in response to a call to a function such as
// WindowFromPoint. If the mouse is not captured, the message is sent to the window beneath
// the cursor. Otherwise, the message is sent to the window that has captured the mouse.
case WM_NCHITTEST: {
DN_OSW32Window *w32_window = DN_OS_W32WindowFromHwndMaybeAlloc(w32, hwnd, nullptr);
if (w32_window && w32_window->custom_title_bar) {
// NOTE: Code adapted from raddebugger
// https://github.com/EpicGames/raddebugger/blob/7a5a649b89f6a06abdbaee61540468fca9db58f9/src/win32/window_manager/win32_window_manager.c#L668
//
// Since we removed the titlebar from the window, the resize handlers/grabbers at the top of
// the window are no longer functional. We have to reimplement it ourselves.
DWORD window_style = GetWindowLongW(hwnd, GWL_STYLE);
bool is_fullscreen = !(window_style & WS_OVERLAPPEDWINDOW);
handled = false;
if (!is_fullscreen) {
// Let the default procedure handle resizing areas
if (w32->fallback_wnd_proc)
result = CallWindowProcW(w32->fallback_wnd_proc, hwnd, msg, w_param, l_param);
else
result = DefWindowProcW(hwnd, msg, w_param, l_param);
switch (result) {
case HTNOWHERE:
case HTRIGHT:
case HTLEFT:
case HTTOPLEFT:
case HTTOPRIGHT:
case HTBOTTOMRIGHT:
case HTBOTTOM:
case HTBOTTOMLEFT: {
handled = true;
} break;
}
if (!handled) {
POINT pos_monitor = {};
pos_monitor.x = GET_X_LPARAM(l_param);
pos_monitor.y = GET_Y_LPARAM(l_param);
handled = true;
POINT pos_client = pos_monitor;
ScreenToClient(hwnd, &pos_client);
DN_V2F32 title_bar_min = w32_window->custom_title_bar_rect_that_is_draggable.pos;
DN_V2F32 title_bar_max = title_bar_min + w32_window->custom_title_bar_rect_that_is_draggable.size;
DN_UInt dpi = w32->get_dpi_for_window ? w32->get_dpi_for_window(hwnd) : 96;
int frame_y = w32->get_system_metrics_for_dpi ? w32->get_system_metrics_for_dpi(SM_CYFRAME, dpi) : GetSystemMetrics(SM_CYFRAME);
int padding = w32->get_system_metrics_for_dpi ? w32->get_system_metrics_for_dpi(SM_CXPADDEDBORDER, dpi) : GetSystemMetrics(SM_CXPADDEDBORDER);
bool is_over_top_resize = pos_client.y >= 0 && pos_client.y < (frame_y + padding);
bool is_over_title_bar = pos_client.x >= title_bar_min.x && pos_client.x < title_bar_max.x &&
pos_client.y >= title_bar_min.y && pos_client.y < title_bar_max.y;
bool is_maximised = IsZoomed(hwnd) != 0;
if (!is_maximised && is_over_top_resize)
result = HTTOP;
else if (is_over_title_bar)
result = HTCAPTION;
else
result = HTCLIENT;
}
}
} else {
handled = false;
}
} break;
default: {
handled = false;
} break;
}
if (!handled) {
if (w32->fallback_wnd_proc) {
result = CallWindowProcW(w32->fallback_wnd_proc, hwnd, msg, w_param, l_param);
} else {
result = DefWindowProcW(hwnd, msg, w_param, l_param);
}
}
return result;
}
DN_API DN_Str16 DN_OS_W32ErrorCodeToMsg16Alloc(DN_U32 error_code) DN_API DN_Str16 DN_OS_W32ErrorCodeToMsg16Alloc(DN_U32 error_code)
{ {
DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
+33 -4
View File
@@ -20,6 +20,18 @@ struct DN_OSW32FolderIteratorW
wchar_t file_name_buf[512]; wchar_t file_name_buf[512];
}; };
struct DN_OSW32Window
{
HWND hwnd;
// NOTE: For windows with custom title bars, this should be the rect in framebuffer units that
// when the mouse is down will move the window, or if the mouse is double-clicked then toggle the
// maximisation of the window. This rect should not include any custom drawn menu buttons so that
// those buttons can be handled by your application.
DN_Rect custom_title_bar_rect_that_is_draggable;
bool custom_title_bar;
DN_OSW32Window *next;
};
enum DN_OSW32SyncPrimitiveType enum DN_OSW32SyncPrimitiveType
{ {
DN_OSW32SyncPrimitiveType_Semaphore, DN_OSW32SyncPrimitiveType_Semaphore,
@@ -41,21 +53,38 @@ struct DN_OSW32SyncPrimitive
DN_OSW32SyncPrimitive *next; DN_OSW32SyncPrimitive *next;
}; };
typedef HRESULT DN_OSW32SetThreadDescriptionFunc(HANDLE hThread, PWSTR const lpThreadDescription); typedef HRESULT DN_OSW32SetThreadDescriptionFunc (HANDLE hThread, PWSTR const lpThreadDescription);
typedef BOOL DN_OSW32SetProcessDpiAwarenessContextFunc(void* value);
typedef UINT DN_OSW32GetDpiForWindowFunc (HWND hwnd);
typedef HRESULT DN_OSW32GetDpiForMonitorFunc (HMONITOR hmonitor, MONITOR_DPI_TYPE dpiType, UINT *dpiX, UINT *dpiY);
typedef int DN_OSW32GetSystemMetricsForDpiFunc (int nIndex, UINT dpi);
#define DN_OSW32DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((void*)-4)
struct DN_OSW32Core struct DN_OSW32Core
{ {
// NOTE: These functions are dynamically loaded because they might not be present on the user's
// machine. For example the GetDpiForWindow is Windows 10+ only.
DN_OSW32SetThreadDescriptionFunc *set_thread_description; DN_OSW32SetThreadDescriptionFunc *set_thread_description;
DN_OSW32GetDpiForWindowFunc *get_dpi_for_window;
DN_OSW32GetDpiForMonitorFunc *get_dpi_for_monitor;
DN_OSW32GetSystemMetricsForDpiFunc *get_system_metrics_for_dpi;
LARGE_INTEGER qpc_frequency; LARGE_INTEGER qpc_frequency;
void *bcrypt_rng_handle; void* bcrypt_rng_handle;
bool bcrypt_init_success; bool bcrypt_init_success;
bool sym_initialised; bool sym_initialised;
CRITICAL_SECTION sync_primitive_free_list_mutex; CRITICAL_SECTION sync_primitive_free_list_mutex;
DN_OSW32SyncPrimitive *sync_primitive_free_list; DN_OSW32SyncPrimitive* sync_primitive_free_list;
DN_OSW32Window* windows;
WNDPROC fallback_wnd_proc;
}; };
DN_API void DN_OS_W32Init (DN_OSW32Core *w32);
DN_API DN_OSW32Core* DN_OS_W32GetCore (); DN_API DN_OSW32Core* DN_OS_W32GetCore ();
DN_API void DN_OS_W32ThreadSetName (DN_Str8 name); DN_API void DN_OS_W32ThreadSetName (DN_Str8 name);
DN_API DN_OSW32Window* DN_OS_W32WindowFromHwndMaybeAlloc(DN_OSW32Core *w32, HWND hwnd, DN_Arena *arena);
DN_API LRESULT __stdcall DN_OS_W32WindowProcCustomTitlebar(HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param);
DN_API DN_Str16 DN_OS_W32ErrorCodeToMsg16Alloc(DN_U32 error_code); DN_API DN_Str16 DN_OS_W32ErrorCodeToMsg16Alloc(DN_U32 error_code);
DN_API DN_OSW32Error DN_OS_W32ErrorCodeToMsg (DN_Arena *arena, DN_U32 error_code); DN_API DN_OSW32Error DN_OS_W32ErrorCodeToMsg (DN_Arena *arena, DN_U32 error_code);
+165
View File
@@ -13,19 +13,27 @@
#pragma comment(lib, "pathcch") #pragma comment(lib, "pathcch")
#pragma comment(lib, "Shell32") // ShellExecuteW #pragma comment(lib, "Shell32") // ShellExecuteW
#pragma comment(lib, "shlwapi") #pragma comment(lib, "shlwapi")
#pragma comment(lib, "user32")
// TODO: Technically we only need this library for custom window titlebars to get access to DWM
// functions. Otherwise this API surface is not used in the DN OS layer.
#pragma comment(lib, "dwmapi")
#endif #endif
#if defined(DN_NO_WINDOWS_H_REPLACEMENT_HEADER) || defined(_INC_WINDOWS) #if defined(DN_NO_WINDOWS_H_REPLACEMENT_HEADER) || defined(_INC_WINDOWS)
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <Windows.h> // LONG #include <Windows.h> // LONG
#include <dwmapi.h> // DwmExtendFrameIntoClientArea...
#include <bcrypt.h> // DN_OS_SecureRNGBytes -> BCryptOpenAlgorithmProvider ... etc #include <bcrypt.h> // DN_OS_SecureRNGBytes -> BCryptOpenAlgorithmProvider ... etc
#include <shellapi.h> // DN_Win_MakeProcessDPIAware -> SetProcessDpiAwareProc #include <shellapi.h> // DN_Win_MakeProcessDPIAware -> SetProcessDpiAwareProc
#include <ShellScalingApi.h> // MONITOR_DPI_TYPE
#include <shlwapi.h> // PathRelativePathTO #include <shlwapi.h> // PathRelativePathTO
#include <pathcch.h> // PathCchCanonicalizeEx #include <pathcch.h> // PathCchCanonicalizeEx
#include <winhttp.h> // WinHttp* #include <winhttp.h> // WinHttp*
#include <psapi.h> // PROCESS_MEMORY_COUNTERS_EX2 #include <psapi.h> // PROCESS_MEMORY_COUNTERS_EX2
#include <commdlg.h> // OPENFILENAMEW #include <commdlg.h> // OPENFILENAMEW
#include <DbgHelp.h> #include <DbgHelp.h>
#include <windowsx.h> // GET_X_PARAM
#else #else
DN_MSVC_WARNING_PUSH DN_MSVC_WARNING_PUSH
DN_MSVC_WARNING_DISABLE(4201) // warning C4201: nonstandard extension used: nameless struct/union DN_MSVC_WARNING_DISABLE(4201) // warning C4201: nonstandard extension used: nameless struct/union
@@ -60,6 +68,7 @@
typedef unsigned __int64 WPARAM; typedef unsigned __int64 WPARAM;
typedef LONG_PTR LPARAM; typedef LONG_PTR LPARAM;
typedef LONG_PTR LRESULT; typedef LONG_PTR LRESULT;
typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR;
#define MAX_PATH 260 #define MAX_PATH 260
@@ -68,6 +77,11 @@
DWORD dwHighDateTime; DWORD dwHighDateTime;
} FILETIME, *PFILETIME, *LPFILETIME; } FILETIME, *PFILETIME, *LPFILETIME;
#define LOWORD(l) ((WORD)(((DWORD_PTR)(l)) & 0xffff))
#define HIWORD(l) ((WORD)((((DWORD_PTR)(l)) >> 16) & 0xffff))
#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
// NOTE: shared/winerror.h ///////////////////////////////////////////////////////////////////// // NOTE: shared/winerror.h /////////////////////////////////////////////////////////////////////
// NOTE: GetModuleFileNameW // NOTE: GetModuleFileNameW
#define ERROR_INSUFFICIENT_BUFFER 122L // dderror #define ERROR_INSUFFICIENT_BUFFER 122L // dderror
@@ -87,6 +101,7 @@
typedef wchar_t WCHAR; // wc, 16-bit UNICODE character typedef wchar_t WCHAR; // wc, 16-bit UNICODE character
typedef CHAR * NPSTR, *LPSTR, *PSTR; typedef CHAR * NPSTR, *LPSTR, *PSTR;
typedef WCHAR * NWPSTR, *LPWSTR, *PWSTR; typedef WCHAR * NWPSTR, *LPWSTR, *PWSTR;
typedef const WCHAR* LPCWSTR, *PCWSTR;
typedef long HRESULT; typedef long HRESULT;
// NOTE: VirtualAlloc: Allocation Type // NOTE: VirtualAlloc: Allocation Type
@@ -372,6 +387,11 @@
LONG y; LONG y;
} POINT, *PPOINT, *NPPOINT, *LPPOINT; } POINT, *PPOINT, *NPPOINT, *LPPOINT;
struct HMONITOR__ {
int unused;
};
typedef struct HMONITOR__ *HMONITOR;
// NOTE: handleapi.h /////////////////////////////////////////////////////////////////////////// // NOTE: handleapi.h ///////////////////////////////////////////////////////////////////////////
#define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1) #define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1)
@@ -670,7 +690,59 @@
RECT rcDevice; RECT rcDevice;
#endif #endif
} WINDOWPLACEMENT; } WINDOWPLACEMENT;
typedef struct tagWINDOWPOS {
HWND hwnd;
HWND hwndInsertAfter;
int x;
int y;
int cx;
int cy;
UINT flags;
} WINDOWPOS, *LPWINDOWPOS, *PWINDOWPOS;
typedef struct tagNCCALCSIZE_PARAMS {
RECT rgrc[3];
PWINDOWPOS lppos;
} NCCALCSIZE_PARAMS, *LPNCCALCSIZE_PARAMS;
typedef WINDOWPLACEMENT *PWINDOWPLACEMENT, *LPWINDOWPLACEMENT; typedef WINDOWPLACEMENT *PWINDOWPLACEMENT, *LPWINDOWPLACEMENT;
typedef LRESULT (__stdcall* WNDPROC)(HWND, UINT, WPARAM, LPARAM);
#define WM_NCHITTEST 0x0084
#define WS_OVERLAPPED 0x00000000L
#define WS_POPUP 0x80000000L
#define WS_CHILD 0x40000000L
#define WS_MINIMIZE 0x20000000L
#define WS_VISIBLE 0x10000000L
#define WS_DISABLED 0x08000000L
#define WS_CLIPSIBLINGS 0x04000000L
#define WS_CLIPCHILDREN 0x02000000L
#define WS_MAXIMIZE 0x01000000L
#define WS_CAPTION 0x00C00000L /* WS_BORDER | WS_DLGFRAME */
#define WS_BORDER 0x00800000L
#define WS_DLGFRAME 0x00400000L
#define WS_VSCROLL 0x00200000L
#define WS_HSCROLL 0x00100000L
#define WS_SYSMENU 0x00080000L
#define WS_THICKFRAME 0x00040000L
#define WS_GROUP 0x00020000L
#define WS_TABSTOP 0x00010000L
#define WS_MINIMIZEBOX 0x00020000L
#define WS_MAXIMIZEBOX 0x00010000L
#define WS_TILED WS_OVERLAPPED
#define WS_ICONIC WS_MINIMIZE
#define WS_SIZEBOX WS_THICKFRAME
#define WS_TILEDWINDOW WS_OVERLAPPEDWINDOW
#define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED | \
WS_CAPTION | \
WS_SYSMENU | \
WS_THICKFRAME | \
WS_MINIMIZEBOX | \
WS_MAXIMIZEBOX)
#define SW_HIDE 0 #define SW_HIDE 0
#define SW_NORMAL 1 #define SW_NORMAL 1
@@ -678,9 +750,71 @@
#define SW_MAXIMIZE 3 #define SW_MAXIMIZE 3
#define SW_SHOWNOACTIVATE 4 #define SW_SHOWNOACTIVATE 4
#define SW_SHOW 5 #define SW_SHOW 5
#define SW_MINIMIZE 6
#define SW_RESTORE 9 #define SW_RESTORE 9
#define SW_FORCEMINIMIZE 11 #define SW_FORCEMINIMIZE 11
#define SWP_NOSIZE 0x0001
#define SWP_NOMOVE 0x0002
#define SWP_NOZORDER 0x0004
#define SWP_NOREDRAW 0x0008
#define SWP_NOACTIVATE 0x0010
#define SWP_FRAMECHANGED 0x0020 /* The frame changed: send WM_NCCALCSIZE */
#define SWP_SHOWWINDOW 0x0040
#define SWP_HIDEWINDOW 0x0080
#define SWP_NOCOPYBITS 0x0100
#define SWP_NOOWNERZORDER 0x0200 /* Don't do owner Z ordering */
#define SWP_NOSENDCHANGING 0x0400 /* Don't send WM_WINDOWPOSCHANGING */
#define SWP_DRAWFRAME SWP_FRAMECHANGED
#define SWP_NOREPOSITION SWP_NOOWNERZORDER
#define SM_CXEDGE 45
#define SM_CYEDGE 46
#define SM_CXFRAME 32
#define SM_CYFRAME 33
#define SM_CXPADDEDBORDER 92
#define GWLP_WNDPROC (-4)
#define GWL_STYLE (-16)
#define WS_OVERLAPPED 0x00000000L
#define WM_NCCALCSIZE 0x0083
// WM_NCHITTEST and MOUSEHOOKSTRUCT Mouse Position Codes
#define HTERROR (-2)
#define HTTRANSPARENT (-1)
#define HTNOWHERE 0
#define HTCLIENT 1
#define HTCAPTION 2
#define HTSYSMENU 3
#define HTGROWBOX 4
#define HTSIZE HTGROWBOX
#define HTMENU 5
#define HTHSCROLL 6
#define HTVSCROLL 7
#define HTMINBUTTON 8
#define HTMAXBUTTON 9
#define HTLEFT 10
#define HTRIGHT 11
#define HTTOP 12
#define HTTOPLEFT 13
#define HTTOPRIGHT 14
#define HTBOTTOM 15
#define HTBOTTOMLEFT 16
#define HTBOTTOMRIGHT 17
#define HTBORDER 18
#define HTREDUCE HTMINBUTTON
#define HTZOOM HTMAXBUTTON
#define HTSIZEFIRST HTLEFT
#define HTSIZELAST HTBOTTOMRIGHT
#if(WINVER >= 0x0400)
#define HTOBJECT 19
#define HTCLOSE 20
#define HTHELP 21
#endif /* WINVER >= 0x0400 */
extern "C" extern "C"
{ {
__declspec(dllimport) BOOL __stdcall GetWindowRect (HWND hWnd, RECT *lpRect); __declspec(dllimport) BOOL __stdcall GetWindowRect (HWND hWnd, RECT *lpRect);
@@ -689,11 +823,34 @@
__declspec(dllimport) BOOL __stdcall ShowWindow (HWND hWnd, int nCmdShow); __declspec(dllimport) BOOL __stdcall ShowWindow (HWND hWnd, int nCmdShow);
__declspec(dllimport) BOOL __stdcall GetWindowPlacement (HWND hWnd, WINDOWPLACEMENT *lpwndpl); __declspec(dllimport) BOOL __stdcall GetWindowPlacement (HWND hWnd, WINDOWPLACEMENT *lpwndpl);
__declspec(dllimport) BOOL __stdcall IsIconic (HWND hWnd); __declspec(dllimport) BOOL __stdcall IsIconic (HWND hWnd);
__declspec(dllimport) BOOL __stdcall IsZoomed (HWND hWnd);
__declspec(dllimport) BOOL __stdcall BringWindowToTop (HWND hWnd); __declspec(dllimport) BOOL __stdcall BringWindowToTop (HWND hWnd);
__declspec(dllimport) BOOL __stdcall SetForegroundWindow (HWND hWnd); __declspec(dllimport) BOOL __stdcall SetForegroundWindow (HWND hWnd);
__declspec(dllimport) HWND __stdcall SetFocus (HWND hWnd); __declspec(dllimport) HWND __stdcall SetFocus (HWND hWnd);
__declspec(dllimport) HWND __stdcall GetForegroundWindow (); __declspec(dllimport) HWND __stdcall GetForegroundWindow ();
__declspec(dllimport) BOOL __stdcall SetWindowTextW (HWND hWnd, LPCWSTR lpString); __declspec(dllimport) BOOL __stdcall SetWindowTextW (HWND hWnd, LPCWSTR lpString);
__declspec(dllimport) UINT __stdcall GetDoubleClickTime ();
__declspec(dllimport) LONG_PTR __stdcall GetWindowLongPtrW (HWND hWnd, int nIndex);
__declspec(dllimport) LONG_PTR __stdcall SetWindowLongPtrW (HWND hWnd, int nIndex, LONG_PTR dwNewLong);
__declspec(dllimport) LONG __stdcall GetWindowLongW (HWND hWnd, int nIndex);
__declspec(dllimport) LRESULT __stdcall CallWindowProcW (WNDPROC lpPrevWndFunc, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
__declspec(dllimport) int __stdcall GetSystemMetrics (int nIndex);
__declspec(dllimport) BOOL __stdcall ScreenToClient (HWND hWnd, LPPOINT lpPoint);
__declspec(dllimport) LRESULT __stdcall DefWindowProcW (HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
}
// NOTE: um/dwmapi.h //////////////////////////////////////////////////////////////////////////
typedef struct _MARGINS
{
int cxLeftWidth; // width of left border that retains its size
int cxRightWidth; // width of right border that retains its size
int cyTopHeight; // height of top border that retains its size
int cyBottomHeight; // height of bottom border that retains its size
} MARGINS, *PMARGINS;
extern "C"
{
__declspec(dllimport) HRESULT __stdcall DwmExtendFrameIntoClientArea(HWND hWnd, const MARGINS* pMarInset);
} }
// NOTE: um/wininet.h ////////////////////////////////////////////////////////////////////////// // NOTE: um/wininet.h //////////////////////////////////////////////////////////////////////////
@@ -1363,6 +1520,14 @@
#define EXCEPTION_CONTINUE_SEARCH 0 #define EXCEPTION_CONTINUE_SEARCH 0
#define EXCEPTION_CONTINUE_EXECUTION (-1) #define EXCEPTION_CONTINUE_EXECUTION (-1)
// NOTE: um/shellscalingapi.h
typedef enum MONITOR_DPI_TYPE {
MDT_EFFECTIVE_DPI = 0,
MDT_ANGULAR_DPI = 1,
MDT_RAW_DPI = 2,
MDT_DEFAULT = MDT_EFFECTIVE_DPI
} MONITOR_DPI_TYPE;
DN_MSVC_WARNING_POP DN_MSVC_WARNING_POP
#endif // !defined(_INC_WINDOWS) #endif // !defined(_INC_WINDOWS)
#endif // !defined(DN_OS_WINDOWS_H) #endif // !defined(DN_OS_WINDOWS_H)
+1 -1
View File
@@ -800,7 +800,7 @@ DN_TestCore DN_SHA3_TestSuite(DN_Arena *arena)
void DN_SHA3_TestSuiteThenOutput(DN_Str8FromTestCoreFlags flags) void DN_SHA3_TestSuiteThenOutput(DN_Str8FromTestCoreFlags flags)
{ {
DN_Arena arena = DN_ArenaFromHeap(DN_Megabytes(1), DN_Kilobytes(64), DN_MemFlags_Nil, DN_OS_HeapInitDefault()); DN_Arena arena = DN_ArenaFromHeap(DN_Megabytes(1), DN_Kilobytes(64), DN_MemFlags_Nil, DN_OS_HeapInitDefault(), "DN SHA3 Tests");
DN_TestCore test = DN_SHA3_TestSuite(&arena); DN_TestCore test = DN_SHA3_TestSuite(&arena);
DN_Str8 output = DN_Str8FromTestCore(&test, &arena, flags); DN_Str8 output = DN_Str8FromTestCore(&test, &arena, flags);
printf("%.*s", DN_Str8PrintFmt(output)); printf("%.*s", DN_Str8PrintFmt(output));
+841 -360
View File
File diff suppressed because it is too large Load Diff
+406 -117
View File
@@ -182,11 +182,17 @@
// the stacktrace that is stored per region to report to the user when a UAF guard violation // the stacktrace that is stored per region to report to the user when a UAF guard violation
// occurs. // occurs.
// Memory Debugger
// Set `DN_MEM_DEBUGGER` to `1` to enable memory debugging which enables the `DN_Core`'s
// `mem_debugger` field, tracks all allocations in the application and reports leaks.
//
// #define DN_MEM_DEBUGGER 1
// Paranoia Level // Paranoia Level
// Set the `DN_PARANOIA_LEVEL` to an integer value to enable various validation layers and // Set the `DN_PARANOIA_LEVEL` to an integer value to enable various validation layers and
// error checking mechanisms in the codebase and primitives exposed by the library // error checking mechanisms in the codebase and primitives exposed by the library
// (default: PARANOID level 1 in debug builds, 0 otherwise) // (default: PARANOIA level 1 in debug builds, 0 otherwise) paranoia level 0 in release builds
// paranoia level 0 in release builds and level 1 for debug. // and level 1 for debug.
// //
// #define DN_PARANOIA_LEVEL 1 // #define DN_PARANOIA_LEVEL 1
// //
@@ -559,7 +565,7 @@
#define DN_ForIndexU(index, count) DN_USize index = 0; index < count; index++ #define DN_ForIndexU(index, count) DN_USize index = 0; index < count; index++
#define DN_ForIndexI(index, count) DN_ISize index = 0; index < count; index++ #define DN_ForIndexI(index, count) DN_ISize index = 0; index < count; index++
#define DN_ForItSize(it, T, array, count) struct { DN_USize index; T *data; } it = {0, &(array)[0]}; it.index < (count); it.index++, it.data = (array) + it.index #define DN_ForItSize(it, T, array, count) struct { DN_USize index; T *data; } it = {0, &(array)[0]}; it.index < (count); it.index++, it.data = (array) + it.index
#define DN_ForItSizeReverse(it, T, array, count) struct { DN_USize index; T *data; } it = {(count) - 1, &(array)[count - 1]}; it.index < (count); it.index--, it.data = (array) + it.index #define DN_ForItSizeReverse(it, T, array, count) struct { DN_USize index; T *data; } it = {(count) ? (count) - 1 : 0, (count) ? &(array)[count - 1] : 0}; it.index < (count); it.index--, it.data = (array) + it.index
#define DN_ForIt(it, T, array) struct { DN_USize index; T *data; } it = {0, &(array)->data[0]}; it.index < (array)->count; it.index++, it.data = ((array)->data) + it.index #define DN_ForIt(it, T, array) struct { DN_USize index; T *data; } it = {0, &(array)->data[0]}; it.index < (array)->count; it.index++, it.data = ((array)->data) + it.index
#define DN_ForLinkedListIt(it, T, list) struct { DN_USize index; T *data; } it = {0, list}; it.data; it.index++, it.data = ((it).data->next) #define DN_ForLinkedListIt(it, T, list) struct { DN_USize index; T *data; } it = {0, list}; it.data; it.index++, it.data = ((it).data->next)
#define DN_ForItCArray(it, T, array) struct { DN_USize index; T *data; } it = {0, &(array)[0]}; it.index < DN_ArrayCountU(array); it.index++, it.data = (array) + it.index #define DN_ForItCArray(it, T, array) struct { DN_USize index; T *data; } it = {0, &(array)[0]}; it.index < DN_ArrayCountU(array); it.index++, it.data = (array) + it.index
@@ -786,6 +792,14 @@ typedef enum DN_ZMem {
DN_ZMem_Yes, // Memory should be zero-ed out before giving to the callee DN_ZMem_Yes, // Memory should be zero-ed out before giving to the callee
} DN_ZMem; } DN_ZMem;
typedef enum DN_Side {
DN_Side_Left,
DN_Side_Right,
DN_Side_Top,
DN_Side_Bottom,
DN_Side_Count,
} DN_Side;
typedef enum DN_AddType { typedef enum DN_AddType {
DN_AddType_Prepend, DN_AddType_Prepend,
DN_AddType_Append, DN_AddType_Append,
@@ -1000,12 +1014,14 @@ DN_MSVC_WARNING_POP
typedef struct DN_CallSite DN_CallSite; typedef struct DN_CallSite DN_CallSite;
struct DN_CallSite struct DN_CallSite
{ {
DN_Str8 name;
DN_Str8 file; DN_Str8 file;
DN_Str8 function; DN_Str8 function;
DN_U32 line; DN_U32 line;
}; };
#define DN_CallSiteNow DN_Literal(DN_CallSite){DN_Str8Lit(__FILE__), DN_Str8Lit(__func__), __LINE__ } #define DN_CallSiteNow DN_Literal(DN_CallSite){DN_Str8Lit(""), DN_Str8Lit(__FILE__), DN_Str8Lit(__func__), __LINE__ }
#define DN_CallSiteNowNamed(name_cstr) DN_Literal(DN_CallSite){DN_Str8Lit(name_cstr), DN_Str8Lit(__FILE__), DN_Str8Lit(__func__), __LINE__ }
#if defined(__cplusplus) #if defined(__cplusplus)
template <typename Procedure> template <typename Procedure>
@@ -1131,9 +1147,9 @@ enum DN_MemPage_
// This flag must only be used in DN_Mem_Protect // This flag must only be used in DN_Mem_Protect
DN_MemPage_Guard = 1 << 3, DN_MemPage_Guard = 1 << 3,
// If leak tracing is enabled, this flag will allow the allocation recorded // If memory debugging is enabled, this flag will allow the allocation
// from the reserve call to be leaked, e.g. not printed when leaks are // recorded from the reserve call to be leaked, e.g. not printed when leaks
// dumped to the console. // are dumped to the console.
DN_MemPage_AllocRecordLeakPermitted = 1 << 4, DN_MemPage_AllocRecordLeakPermitted = 1 << 4,
// If leak tracing is enabled this flag will prevent any allocation record // If leak tracing is enabled this flag will prevent any allocation record
@@ -1165,15 +1181,31 @@ typedef enum DN_HeapType {
DN_HeapType_Virtual, DN_HeapType_Virtual,
} DN_HeapType; } DN_HeapType;
typedef DN_U32 DN_HeapAllocFlag;
enum DN_HeapAllocFlag_ {
DN_HeapAllocFlag_Nil = 0,
DN_HeapAllocFlag_MemDebuggerCanLeakPtr = 1 << 0,
DN_HeapAllocFlag_MemDebuggerExcludePtr = 1 << 1,
};
typedef DN_U32 DN_HeapFlags;
enum DN_HeapFlags_ {
DN_HeapFlags_Nil = 0,
DN_HeapFlags_ExcludeFromMemDebugger = 1 << 0,
DN_HeapFlags_MemDebuggerCanLeakPtr = 1 << 1,
};
typedef void *(DN_HeapBasicAllocFunc) (DN_USize count); typedef void *(DN_HeapBasicAllocFunc) (DN_USize count);
typedef void (DN_HeapBasicDeallocFunc)(void *ptr); typedef void (DN_HeapBasicDeallocFunc)(void *ptr);
typedef void *(DN_HeapVirtualReserveFunc)(DN_USize count, DN_MemCommit commit, DN_MemPage page_flags); typedef void *(DN_HeapVirtualReserveFunc)(DN_USize count, DN_MemCommit commit, DN_MemPage page_flags);
typedef bool (DN_HeapVirtualCommitFunc)(void *ptr, DN_USize count, DN_U32 page_flags); typedef bool (DN_HeapVirtualCommitFunc)(void *ptr, DN_USize count, DN_U32 page_flags);
typedef void (DN_HeapVirtualReleaseFunc)(void *ptr, DN_USize count); typedef void (DN_HeapVirtualReleaseFunc)(void *ptr, DN_USize count);
typedef struct DN_Heap DN_Heap; typedef struct DN_Heap DN_Heap;
struct DN_Heap struct DN_Heap
{ {
DN_HeapFlags flags;
DN_HeapType type; DN_HeapType type;
DN_USize bytes_alloc_total; DN_USize bytes_alloc_total;
DN_USize bytes_alloc; DN_USize bytes_alloc;
@@ -1220,8 +1252,6 @@ enum DN_MemFlags_
DN_MemFlags_Nil = 0, DN_MemFlags_Nil = 0,
DN_MemFlags_NoGrow = 1 << 0, DN_MemFlags_NoGrow = 1 << 0,
DN_MemFlags_NoPoison = 1 << 1, DN_MemFlags_NoPoison = 1 << 1,
DN_MemFlags_NoAllocTrack = 1 << 2,
DN_MemFlags_AllocCanLeak = 1 << 3,
DN_MemFlags_SimAlloc = 1 << 4, DN_MemFlags_SimAlloc = 1 << 4,
// NOTE: Records stack traces of temp memory regions on construction to provide more diagnostics // NOTE: Records stack traces of temp memory regions on construction to provide more diagnostics
@@ -1251,12 +1281,16 @@ enum DN_MemFlags_
typedef struct DN_MemList DN_MemList; typedef struct DN_MemList DN_MemList;
struct DN_MemList struct DN_MemList
{ {
DN_MemBlock* curr; DN_MemBlock* curr; // Contiguous blocks of memory, chained for growth, parcelled for object allocation
DN_MemFlags flags; DN_MemFlags flags;
DN_Heap heap; DN_Heap heap; // Backing allocator for the memory blocks
DN_MemStats stats; DN_MemStats stats;
DN_Str8 label; DN_Str8 label;
#if DN_MEM_DEBUGGER
DN_USize mem_debugger_id;
#endif
#if DN_ARENA_TEMP_MEM_UAF_GUARD #if DN_ARENA_TEMP_MEM_UAF_GUARD
DN_U32 uaf_guard_next_id; DN_U32 uaf_guard_next_id;
DN_U32 uaf_guard_active_id; DN_U32 uaf_guard_active_id;
@@ -1387,7 +1421,8 @@ struct DN_Utf32FromIterator
bool init; bool init;
bool success; bool success;
DN_Str8 remaining; DN_Str8 remaining;
DN_USize bytes_decoded; DN_USize bytes_decoded_;
DN_USize bytes_decoded_total;
DN_USize codepoint_index; DN_USize codepoint_index;
DN_U32 codepoint; DN_U32 codepoint;
}; };
@@ -1635,6 +1670,97 @@ struct DN_Profiler
DN_F64 frame_avg_tsc; DN_F64 frame_avg_tsc;
}; };
struct DN_Profiler2Marker
{
DN_Str8 name;
DN_U64 tsc_begin;
DN_U64 tsc_end;
DN_U64 tsc_children_duration;
DN_CallSite call_site;
DN_U32 parent_index;
DN_U32 next_index;
DN_U32 first_child_index;
DN_U32 last_child_index;
};
struct DN_Profiler2Frame
{
// NOTE: The frame number that this frame was part of. Frame number is incremented each time
// frame-begin is called.
DN_U32 frame_num;
// NOTE: The markers array is not contiguous. We using a ring-buffer so accessing the marker must
// be done like `profiler->markers + ((frame->begin_offset + i) % profiler->markers_max)`. A
// helper function is available `DN_Profiler2MarkerFromFrameIndex(profiler, frame, i)`
DN_U32 begin_offset;
DN_U32 count;
DN_U32 max;
// NOTE: The profiling marker that the profiler makes and closes when frame-begin is called.
// Encapsulates essentially the duration of 1 update loop in an interactive application.
DN_Profiler2Marker* begin_marker;
};
struct DN_Profiler2Zone
{
struct DN_Profiler2* profiler;
DN_Profiler2Marker* marker;
bool ended;
bool scope_once;
};
enum DN_Profiler2State
{
DN_Profiler2State_Run,
DN_Profiler2State_Paused,
DN_Profiler2State_UnpauseEnqueued,
};
struct DN_Profiler2
{
DN_Profiler2State state;
DN_U32 frame_num;
DN_ProfilerTscNowFunc* tsc_now;
DN_U64 tsc_frequency;
DN_Profiler2Frame* frames;
DN_U32 frames_max;
DN_U32 frames_write_index_unwrapped;
DN_Profiler2Marker* markers;
DN_U32 markers_max;
DN_Profiler2Frame* active_frame;
DN_U32 active_parent_index;
struct DN_Profiler2Zone frame_begin_zone;
};
struct DN_Profiler2Iterator
{
bool init;
DN_USize iteration_count;
DN_U32 marker_index;
DN_U32 last_visited_index;
DN_Profiler2Marker* marker;
};
struct DN_Profiler2FunctionTime
{
DN_CallSite call_site;
DN_Str8 name;
DN_USize hit_count;
DN_U64 tsc_total;
DN_U64 tsc_children_total;
};
struct DN_Profiler2FunctionTimes
{
DN_Profiler2FunctionTime *data;
DN_USize count;
DN_USize max;
};
typedef bool (DN_QSortCompareFunc) (void const *lhs, void const *rhs, void *user_context); typedef bool (DN_QSortCompareFunc) (void const *lhs, void const *rhs, void *user_context);
typedef bool (DN_BSearchLessThanFunc)(void const *lhs, void const *rhs, void *user_context); typedef bool (DN_BSearchLessThanFunc)(void const *lhs, void const *rhs, void *user_context);
enum DN_BSearchType enum DN_BSearchType
@@ -1761,8 +1887,13 @@ typedef enum DN_TcDeinitArenas {
typedef struct DN_Pcg32 DN_Pcg32; typedef struct DN_Pcg32 DN_Pcg32;
struct DN_Pcg32 { DN_U64 state; }; struct DN_Pcg32 { DN_U64 state; };
typedef struct DN_Murmur3 DN_Murmur3; typedef struct DN_Murmur3Context DN_Murmur3Context;
struct DN_Murmur3 { DN_U64 e[2]; }; struct DN_Murmur3Context
{
DN_U32 it;
DN_U32 carry;
DN_U32 bytes_count;
};
typedef enum DN_LogType { typedef enum DN_LogType {
DN_LogType_Debug, DN_LogType_Debug,
@@ -1941,18 +2072,11 @@ typedef enum DN_RectCutClip {
DN_RectCutClip_Yes, DN_RectCutClip_Yes,
} DN_RectCutClip; } DN_RectCutClip;
typedef enum DN_RectCutSide {
DN_RectCutSide_Left,
DN_RectCutSide_Right,
DN_RectCutSide_Top,
DN_RectCutSide_Bottom,
} DN_RectCutSide;
typedef struct DN_RectCut DN_RectCut; typedef struct DN_RectCut DN_RectCut;
struct DN_RectCut struct DN_RectCut
{ {
DN_Rect* rect; DN_Rect* rect;
DN_RectCutSide side; DN_Side side;
}; };
typedef struct DN_RaycastV2 DN_RaycastV2; typedef struct DN_RaycastV2 DN_RaycastV2;
@@ -2110,39 +2234,56 @@ enum DN_HTableAllowTombstone
DN_HTableAllowTombstone_Yes, DN_HTableAllowTombstone_Yes,
}; };
enum DN_LeakAllocFlag enum DN_MemDebuggerPtrFlag
{ {
DN_LeakAllocFlag_Freed = 1 << 0, DN_MemDebuggerPtrFlag_Freed = 1 << 0,
DN_LeakAllocFlag_LeakPermitted = 1 << 1, DN_MemDebuggerPtrFlag_LeakPermitted = 1 << 1,
}; };
typedef struct DN_LeakAlloc DN_LeakAlloc; typedef struct DN_MemDebuggerPtrData DN_MemDebuggerPtrData;
struct DN_LeakAlloc struct DN_MemDebuggerPtrData
{ {
void *ptr; // 8 Pointer to the allocation being tracked DN_CallSite call_site;
DN_USize size; // 16 Size of the allocation DN_U16 flags; // Bit flags from `DN_MemDebuggerPtrFlag`
DN_USize freed_size; // 24 Store the size of the allocation when it is freed void* ptr; // Pointer to the allocation being tracked
DN_Str8 stack_trace; // 40 Stack trace at the point of allocation DN_USize size; // Size of the allocation
DN_Str8 freed_stack_trace; // 56 Stack trace of where the allocation was freed DN_USize freed_size; // Store the size of the allocation when it is freed
DN_U16 flags; // 72 Bit flags from `DN_LeakAllocFlag` DN_Str8 stack_trace; // Stack trace at the point of allocation
DN_Str8 freed_stack_trace; // Stack trace of where the allocation was freed
}; };
// NOTE: We aim to keep the allocation record as light as possible as memory tracking can get typedef struct DN_MemDebuggerKV DN_MemDebuggerKV;
// expensive. Enforce that there is no unexpected padding. struct DN_MemDebuggerKV
DN_StaticAssert(sizeof(DN_LeakAlloc) == 64 || sizeof(DN_LeakAlloc) == 32); // NOTE: 64 bit vs 32 bit pointers respectively
typedef struct DN_LeakTrackerKV DN_LeakTrackerKV;
struct DN_LeakTrackerKV
{ {
DN_HTableHashType hash; DN_HTableHashType hash;
DN_UPtr key; DN_UPtr key;
DN_LeakAlloc value; DN_MemDebuggerPtrData value;
}; };
typedef struct DN_LeakTracker DN_LeakTracker; typedef struct DN_MemDebuggerSnapshotPtrData DN_MemDebuggerSnapshotPtrData;
struct DN_LeakTracker struct DN_MemDebuggerSnapshotPtrData
{ {
DN_LeakTrackerKV *alloc_table_kvs; void* ptr;
DN_USize size;
DN_U16 flags;
DN_CallSite call_site;
DN_Str8 stack_trace;
};
typedef struct DN_MemDebuggerSnapshot DN_MemDebuggerSnapshot;
struct DN_MemDebuggerSnapshot
{
DN_MemDebuggerSnapshotPtrData *data;
DN_USize count;
DN_U64 active_bytes;
DN_U64 freed_count;
DN_U64 freed_bytes;
};
typedef struct DN_MemDebugger DN_MemDebugger;
struct DN_MemDebugger
{
DN_MemDebuggerKV *alloc_table_kvs;
DN_HTable alloc_table; DN_HTable alloc_table;
DN_TicketMutex alloc_table_mutex; DN_TicketMutex alloc_table_mutex;
DN_U64 alloc_table_bytes_allocated_for_stack_traces; DN_U64 alloc_table_bytes_allocated_for_stack_traces;
@@ -2156,7 +2297,6 @@ enum DN_InitFlags_
// NOTE: Query the OS for information and enable functionality that requires the OS (like virtual // NOTE: Query the OS for information and enable functionality that requires the OS (like virtual
// memory APIs, mutexes, secure RNG) as well as per-thread persistent and scratch allocators. // memory APIs, mutexes, secure RNG) as well as per-thread persistent and scratch allocators.
DN_InitFlags_OS = (1 << 0), DN_InitFlags_OS = (1 << 0),
DN_InitFlags_LeakTracker = (1 << 1) | DN_InitFlags_OS,
DN_InitFlags_LogLibFeatures = (1 << 2), DN_InitFlags_LogLibFeatures = (1 << 2),
DN_InitFlags_LogCPUFeatures = (1 << 3) | DN_InitFlags_OS, DN_InitFlags_LogCPUFeatures = (1 << 3) | DN_InitFlags_OS,
DN_InitFlags_LogAllFeatures = DN_InitFlags_LogLibFeatures | DN_InitFlags_LogCPUFeatures, DN_InitFlags_LogAllFeatures = DN_InitFlags_LogLibFeatures | DN_InitFlags_LogCPUFeatures,
@@ -2653,7 +2793,8 @@ struct DN_Core
DN_InitFlags init_flags; DN_InitFlags init_flags;
DN_TcCore main_tc; DN_TcCore main_tc;
DN_USize mem_allocs_frame; DN_USize mem_allocs_frame;
DN_LeakTracker leak; DN_MemDebugger mem_debugger;
DN_USize mem_debugger_mem_list_id_counter;
DN_LogType log_level_to_show_from; DN_LogType log_level_to_show_from;
DN_LogPrintFunc* print_func; DN_LogPrintFunc* print_func;
@@ -2850,14 +2991,17 @@ DN_API DN_MemStats DN_MemStatsSumArray
// API // API
// DN_HeapAlloc // DN_HeapAlloc
// DN_HeapDealloc // Allocate memory using the given heap's configured allocation functions. For a heap using the
// Allocate and deallocate memory. Note that `DN_HeapAlloc` takes reserve and commit even for // basic allocation routines, `commit` is ignored, `reserve` is the amount of bytes to be
// the basic allocator. In the basic allocator which does not have a concept of reserving and // allocated and implicitly committed. For virtual memory then `reserve` is the amount of
// committing, the `commit` value is ignored and the `reserve` amount is the amount that will be // address space to reserve for the application from the OS. `commit` is the amount of memory in
// allocated. // pages that the OS will give your application.
#define DN_MemMetadataInit(name_cstr) DN_Literal(DN_MemMetadata){DN_CallSiteNow, DN_Str8Lit(name_cstr)}
DN_API DN_Heap DN_HeapInitBasic (DN_HeapBasicAllocFunc *basic_alloc, DN_HeapBasicDeallocFunc *basic_dealloc); DN_API DN_Heap DN_HeapInitBasic (DN_HeapBasicAllocFunc *basic_alloc, DN_HeapBasicDeallocFunc *basic_dealloc);
DN_API DN_Heap DN_HeapInitVirtual (DN_U32 page_size, DN_HeapVirtualReserveFunc *virtual_reserve, DN_HeapVirtualCommitFunc *virtual_commit, DN_HeapVirtualReleaseFunc *virtual_release); DN_API DN_Heap DN_HeapInitVirtual (DN_U32 page_size, DN_HeapVirtualReserveFunc *virtual_reserve, DN_HeapVirtualCommitFunc *virtual_commit, DN_HeapVirtualReleaseFunc *virtual_release);
DN_API void* DN_HeapAlloc (DN_Heap *heap, DN_USize reserve, DN_USize commit); DN_API void* DN_HeapAllocCallSite (DN_Heap *heap, DN_USize reserve, DN_USize commit, DN_HeapAllocFlag flags, DN_CallSite call_site);
#define DN_HeapAlloc(heap, reserve, commit, flags, name_cstr) DN_HeapAllocMetadata(heap, reserve, commit, flags, DN_MemMetadataInit(name_cstr));
DN_API void DN_HeapDealloc (DN_Heap *heap, void *ptr, DN_USize size); DN_API void DN_HeapDealloc (DN_Heap *heap, void *ptr, DN_USize size);
// NOTE: MemList // NOTE: MemList
@@ -2870,7 +3014,8 @@ DN_API void DN_HeapDealloc
// In general for 99% of use-cases you want an `Arena` and if some API is not exposed on the // In general for 99% of use-cases you want an `Arena` and if some API is not exposed on the
// `Arena` to then use the `MemList` API on the embedded `mem_list` backing the Arena. // `Arena` to then use the `MemList` API on the embedded `mem_list` backing the Arena.
DN_API DN_MemList DN_MemListFromBuffer (void *buffer, DN_USize size, DN_MemFlags flags); DN_API DN_MemList DN_MemListFromBuffer (void *buffer, DN_USize size, DN_MemFlags flags);
DN_API DN_MemList DN_MemListFromHeap (DN_U64 reserve, DN_U64 commit, DN_MemFlags flags, DN_Heap heap); DN_API DN_MemList DN_MemListFromHeapCallSite (DN_U64 reserve, DN_U64 commit, DN_MemFlags flags, DN_Heap heap, DN_CallSite call_site);
#define DN_MemListFromHeap(reserve, commit, flags, heap, name_cstr) DN_MemListFromHeapCallSite(reserve, commit, flags, heap, DN_CallSiteNowNamed(name_cstr))
DN_API void DN_MemListDeinit (DN_MemList *mem); DN_API void DN_MemListDeinit (DN_MemList *mem);
DN_API bool DN_MemListCommit (DN_MemList *mem, DN_U64 size); DN_API bool DN_MemListCommit (DN_MemList *mem, DN_U64 size);
DN_API bool DN_MemListCommitTo (DN_MemList *mem, DN_U64 pos); DN_API bool DN_MemListCommitTo (DN_MemList *mem, DN_U64 pos);
@@ -2941,7 +3086,8 @@ DN_API void DN_MemListTempEnd
DN_ArenaDeinit(&arena); // Frees the memory DN_ArenaDeinit(&arena); // Frees the memory
*/ */
DN_API DN_Arena DN_ArenaFromMemList (DN_MemList *mem); DN_API DN_Arena DN_ArenaFromMemList (DN_MemList *mem);
DN_API DN_Arena DN_ArenaFromHeap (DN_U64 reserve, DN_U64 commit, DN_MemFlags flags, DN_Heap heap); DN_API DN_Arena DN_ArenaFromHeapCallSite (DN_U64 reserve, DN_U64 commit, DN_MemFlags flags, DN_Heap heap, DN_CallSite call_site);
#define DN_ArenaFromHeap(reserve, commit, flags, heap, name_cstr) DN_ArenaFromHeapCallSite(reserve, commit, flags, heap, DN_CallSiteNowNamed(name_cstr))
DN_API DN_Arena DN_ArenaTempBeginFromMemList (DN_MemList *mem); DN_API DN_Arena DN_ArenaTempBeginFromMemList (DN_MemList *mem);
DN_API DN_Arena DN_ArenaTempBeginFromArena (DN_Arena *arena); DN_API DN_Arena DN_ArenaTempBeginFromArena (DN_Arena *arena);
DN_API void DN_ArenaTempEnd (DN_Arena *arena, DN_ArenaReset reset); DN_API void DN_ArenaTempEnd (DN_Arena *arena, DN_ArenaReset reset);
@@ -3055,6 +3201,12 @@ DN_API DN_Allocator DN_AllocatorFromMemList
DN_API DN_Allocator DN_AllocatorFromArena (DN_Arena *arena); DN_API DN_Allocator DN_AllocatorFromArena (DN_Arena *arena);
DN_API DN_Allocator DN_AllocatorFromPool (DN_Pool *pool); DN_API DN_Allocator DN_AllocatorFromPool (DN_Pool *pool);
DN_API void* DN_AllocatorAlloc (DN_Allocator allocator, DN_USize count, DN_U8 align, DN_ZMem z_mem); DN_API void* DN_AllocatorAlloc (DN_Allocator allocator, DN_USize count, DN_U8 align, DN_ZMem z_mem);
#define DN_AllocatorNew(allocator, T, zmem) (T *)DN_AllocatorAlloc(allocator, sizeof(T), alignof(T), zmem)
#define DN_AllocatorNewZ(allocator, T) (T *)DN_AllocatorAlloc(allocator, sizeof(T), alignof(T), DN_ZMem_Yes)
#define DN_AllocatorNewNoZ(allocator, T) (T *)DN_AllocatorAlloc(allocator, sizeof(T), alignof(T), DN_ZMem_No)
#define DN_AllocatorNewArray(allocator, T, count, zmem) (T *)DN_AllocatorAlloc(allocator, sizeof(T) * (count), alignof(T), zmem)
#define DN_AllocatorNewArrayZ(allocator, T, count) (T *)DN_AllocatorAlloc(allocator, sizeof(T) * (count), alignof(T), DN_ZMem_Yes)
#define DN_AllocatorNewArrayNoZ(allocator, T, count) (T *)DN_AllocatorAlloc(allocator, sizeof(T) * (count), alignof(T), DN_ZMem_No)
DN_API DN_USize DN_FmtVCount (DN_FMT_ATTRIB char const *fmt, va_list args); DN_API DN_USize DN_FmtVCount (DN_FMT_ATTRIB char const *fmt, va_list args);
DN_API DN_USize DN_FmtCount (DN_FMT_ATTRIB char const *fmt, ...); DN_API DN_USize DN_FmtCount (DN_FMT_ATTRIB char const *fmt, ...);
@@ -3361,6 +3513,17 @@ DN_API void DN_ProfilerFmtToStdout
DN_API DN_F64 DN_ProfilerSecFromTsc (DN_Profiler *profiler, DN_U64 duration_tsc); DN_API DN_F64 DN_ProfilerSecFromTsc (DN_Profiler *profiler, DN_U64 duration_tsc);
DN_API DN_F64 DN_ProfilerMsFromTsc (DN_Profiler *profiler, DN_U64 duration_tsc); DN_API DN_F64 DN_ProfilerMsFromTsc (DN_Profiler *profiler, DN_U64 duration_tsc);
DN_API DN_Profiler2 DN_Profiler2Init (DN_ProfilerTscNowFunc *tsc_now_func, DN_U64 tsc_frequency, DN_Profiler2Marker *markers, DN_U32 markers_count, DN_Profiler2Frame *frames, DN_U32 frames_count);
DN_API void DN_Profiler2FrameBegin (DN_Profiler2 *profiler);
DN_API DN_Profiler2Zone DN_Profiler2ZoneBegin (DN_Profiler2 *profiler, DN_Str8 name, DN_CallSite call_site);
DN_API void DN_Profiler2ZoneEnd (DN_Profiler2Zone *zone);
#define DN_Profiler2ZoneBeginName(profiler, name_cstr) DN_Profiler2ZoneBegin(profiler, DN_Str8Lit(name_cstr), DN_CallSiteNow)
#define DN_Profiler2ZoneBeginUnnamed(profiler) DN_Profiler2ZoneBegin(profiler, DN_Str8Lit(""), DN_CallSiteNow)
#define DN_Profiler2ZoneScopeName(profiler, name_cstr) DN_Profiler2Zone DN_UniqueName(zone) = DN_Profiler2ZoneBeginName(profiler, name_cstr); !DN_UniqueName(zone).scope_once; DN_Profiler2ZoneEnd(DN_UniqueName(&zone))
DN_API bool DN_Profiler2MarkerWalkDfsPreOrder (DN_Profiler2 *profiler, DN_Profiler2Iterator *it);
DN_API DN_V2USize DN_Profiler2MarkerOffsetFromFrame (DN_Profiler2 const *profiler, DN_Profiler2Frame const *frame);
DN_API DN_Profiler2Marker* DN_Profiler2MarkerFromFrameIndex (DN_Profiler2 *profiler, DN_Profiler2Frame *frame, DN_U32 index);
DN_API void DN_QSort_ (void *array, DN_USize array_size, DN_USize elem_size, void *user_context, DN_QSortCompareFunc *compare); DN_API void DN_QSort_ (void *array, DN_USize array_size, DN_USize elem_size, void *user_context, DN_QSortCompareFunc *compare);
#if defined(__cplusplus) #if defined(__cplusplus)
template <typename T> void DN_QSortT (T *array, DN_USize array_size, void *user_context, DN_QSortCompareFunc *compare); template <typename T> void DN_QSortT (T *array, DN_USize array_size, void *user_context, DN_QSortCompareFunc *compare);
@@ -3408,16 +3571,12 @@ DN_API void DN_Pcg32Advance
DN_API DN_U32 DN_Fnv1aHashU32FromBytes (void const *bytes, DN_USize count, DN_U32 seed); DN_API DN_U32 DN_Fnv1aHashU32FromBytes (void const *bytes, DN_USize count, DN_U32 seed);
DN_API DN_U64 DN_Fnv1aHashU64FromBytes (void const *bytes, DN_USize count, DN_U64 seed); DN_API DN_U64 DN_Fnv1aHashU64FromBytes (void const *bytes, DN_USize count, DN_U64 seed);
DN_API DN_U32 DN_Murmur3HashU32FromBytesX86 (void const *bytes, int len, DN_U32 seed); DN_API void DN_Murmur3HashRawProcess (DN_U32 *ph1, DN_U32 *pcarry, const void *key, int len);
DN_API DN_Murmur3 DN_Murmur3HashU128FromBytesX64 (void const *bytes, int len, DN_U32 seed); DN_API DN_U32 DN_Murmur3HashRawResult (DN_U32 h1, DN_U32 carry, DN_U32 total_length);
DN_API DN_U64 DN_Murmur3HashU64FromBytesX64 (void const *bytes, int len, DN_U32 seed); DN_API DN_U32 DN_Murmur3Hash (DN_U32 seed, const void *key, int len);
DN_API DN_U32 DN_Murmur3HashU32FromBytesX64 (void const *bytes, int len, DN_U32 seed); DN_API DN_Murmur3Context DN_Murmur3HashInit (DN_U32 seed);
DN_API void DN_Murmur3HashUpdate (DN_Murmur3Context *ctx, const void *key, int len);
#if defined(DN_64_BIT) DN_API DN_U32 DN_Murmur3HashFinish (DN_Murmur3Context const *ctx);
#define DN_Murmur3HashU32FromBytes(bytes, len, seed) DN_Murmur3HashU32FromBytesX64(bytes, len, seed)
#else
#define DN_Murmur3HashU32FromBytes(bytes, len, seed) DN_Murmur3HashU32FromBytesX86(bytes, len, seed)
#endif
#define DN_AnsiCodeBoldLit "\x1b[1m" #define DN_AnsiCodeBoldLit "\x1b[1m"
#define DN_AnsiCodeResetLit "\x1b[0m" #define DN_AnsiCodeResetLit "\x1b[0m"
@@ -3668,17 +3827,17 @@ DN_API DN_V3F32 DN_V3F32Normalise
#define DN_V4F32From1N(x) DN_Literal(DN_V4F32){{(DN_F32)(x), (DN_F32)(x), (DN_F32)(x), (DN_F32)(x)}} #define DN_V4F32From1N(x) DN_Literal(DN_V4F32){{(DN_F32)(x), (DN_F32)(x), (DN_F32)(x), (DN_F32)(x)}}
#define DN_V4F32From4N(x, y, z, w) DN_Literal(DN_V4F32){{(DN_F32)(x), (DN_F32)(y), (DN_F32)(z), (DN_F32)(w)}} #define DN_V4F32From4N(x, y, z, w) DN_Literal(DN_V4F32){{(DN_F32)(x), (DN_F32)(y), (DN_F32)(z), (DN_F32)(w)}}
#define DN_V4F32FromV3And1N(xyz, w) DN_Literal(DN_V4F32){{xyz.x, xyz.y, xyz.z, w}} #define DN_V4F32FromV3And1N(xyz, w) DN_Literal(DN_V4F32){{(xyz).x, (xyz).y, (xyz).z, (w)}}
#define DN_V4F32Rgba01FromRgbaU8(r, g, b, a) DN_Literal(DN_V4F32){{r / 255.f, g / 255.f, b / 255.f, a / 255.f}} #define DN_V4F32FromRgba255ToRgba01(r, g, b, a) DN_Literal(DN_V4F32){{r / 255.f, g / 255.f, b / 255.f, a / 255.f}}
#define DN_V4F32Rgba01FromRgbU8(r, g, b) DN_Literal(DN_V4F32){{r / 255.f, g / 255.f, b / 255.f, 1.f}} #define DN_V4F32FromRgb255ToRgba01(r, g, b) DN_Literal(DN_V4F32){{r / 255.f, g / 255.f, b / 255.f, 1.f}}
DN_API DN_V4F32 DN_V4F32Lerp (DN_V4F32 lhs, DN_F32 t01, DN_V4F32 rhs); DN_API DN_V4F32 DN_V4F32Lerp (DN_V4F32 lhs, DN_F32 t01, DN_V4F32 rhs);
DN_API bool DN_V4F32Rgba01IsValid (DN_V4F32 rgba01); DN_API bool DN_V4F32Rgba01IsValid (DN_V4F32 rgba01);
DN_API DN_V4F32 DN_V4F32Rgba01FromRgbU32 (DN_U32 u32); DN_API DN_V4F32 DN_V4F32FromRgbU32ToRgba01 (DN_U32 u32);
DN_API DN_V4F32 DN_V4F32Rgba01FromRgbaU32 (DN_U32 u32); DN_API DN_V4F32 DN_V4F32FromRgbaU32ToRgba01 (DN_U32 u32);
DN_API DN_V4F32 DN_V4F32Linear01FromSrgb01 (DN_V4F32 rgb01); DN_API DN_V4F32 DN_V4F32FromSrgb01ToLinear01 (DN_V4F32 rgb01);
DN_API DN_V4F32 DN_V4F32Linear01Desaturate (DN_V4F32 linear01, DN_F32 t01); DN_API DN_V4F32 DN_V4F32Linear01Desaturate (DN_V4F32 linear01, DN_F32 t01);
DN_API DN_V4F32 DN_V4F32Srgb01FromLinear01 (DN_V4F32 linear01); DN_API DN_V4F32 DN_V4F32FromLinear01ToSrgb01 (DN_V4F32 linear01);
#define DN_V4F32FromV4Alpha(v4, alpha) DN_V4F32FromV3And1N(v4.xyz, alpha) #define DN_V4F32FromV4Alpha(v4, alpha) DN_V4F32FromV3And1N(v4.xyz, alpha)
@@ -3723,6 +3882,7 @@ DN_API DN_Str8x256 DN_M4ColumnMajorString
DN_API bool DN_M2x3Eq (DN_M2x3 const *lhs, DN_M2x3 const *rhs); DN_API bool DN_M2x3Eq (DN_M2x3 const *lhs, DN_M2x3 const *rhs);
DN_API bool DN_M2x3NotEq (DN_M2x3 const *lhs, DN_M2x3 const *rhs); DN_API bool DN_M2x3NotEq (DN_M2x3 const *lhs, DN_M2x3 const *rhs);
DN_API DN_M2x3 DN_M2x3Identity (); DN_API DN_M2x3 DN_M2x3Identity ();
DN_API bool DN_M2x3IsIdentity (DN_M2x3 m2x3);
DN_API DN_M2x3 DN_M2x3Translate (DN_V2F32 offset); DN_API DN_M2x3 DN_M2x3Translate (DN_V2F32 offset);
DN_API DN_V2F32 DN_M2x3ScaleGet (DN_M2x3 m2x3); DN_API DN_V2F32 DN_M2x3ScaleGet (DN_M2x3 m2x3);
DN_API DN_M2x3 DN_M2x3Scale (DN_V2F32 scale); DN_API DN_M2x3 DN_M2x3Scale (DN_V2F32 scale);
@@ -3778,50 +3938,175 @@ DN_API DN_Rect DN_RectCutCut
DN_API DN_RaycastV2 DN_RaycastLineIntersectV2 (DN_V2F32 origin_a, DN_V2F32 dir_a, DN_V2F32 origin_b, DN_V2F32 dir_b); DN_API DN_RaycastV2 DN_RaycastLineIntersectV2 (DN_V2F32 origin_a, DN_V2F32 dir_a, DN_V2F32 origin_b, DN_V2F32 dir_b);
// NOTE: Containers that are imlpemented using primarily macros for operating on data structures // NOTE: Containers that are implemented using primarily macros for operating on data structures
// that are embedded into a C style struct or from a set of defined variables from the available // that are embedded into a C style struct or from a set of defined variables from the available
// scope. Keep it stupid simple, structs and functions. Minimal amount of container types with // scope. Keep it stupid simple, structs and functions. Minimal amount of container types with
// flexible construction leads to less duplicated container code and less template meta-programming. // flexible construction leads to less duplicated container code and less template meta-programming.
// NOTE: Intrusive Singly Linked List // NOTE: Lists (Linked, Queue, Stack)
// Define a struct with the members `next`:
// //
// struct MyLinkItem { // 1. Fully double-linked with first and last pointers (linked list)
// int data; // 2. Singly linked with first and last pointers from the list head (queue list)
// MyLinkItem *next; // 3. Singly linked with just a single first pointer from the header (stack list)
// } my_link = {};
//
// MyLinkItem *first_item = DN_ISinglyLLDetach(&my_link, MyLinkItem);
#define DN_ISinglyLLDetach(list) (decltype(list))DN_SinglyLLDetach((void **)&(list), (void **)&(list)->next)
// NOTE: Singly Linked List with Head and Tail pointer #if defined(NDEBUG)
/* #define DN_ListDebugVerifyListContainsPtr(Type, first_ptr, field_for_next, check_ptr)
struct MyLinkItem { #else
int data; #define DN_ListDebugVerifyListContainsPtr(Type, first_ptr, field_for_next, check_ptr) \
MyLinkItem *next; bool DN_UniqueName(dbg_verify_pointer_in_list) = false; \
} my_list = {}; for (Type *dbg_it_ = first_ptr; dbg_it_; dbg_it_ = dbg_it_->field_for_next) { \
if (dbg_it_ == check_ptr) { \
DN_UniqueName(dbg_verify_pointer_in_list) = true; \
break; \
} \
} \
DN_AssertF(DN_UniqueName(dbg_verify_pointer_in_list), "Pointer %p is not a part of the linked list at %p", check_ptr, first_ptr);
#endif
struct MyContainer { #define DN_ForList(Type, var_it_name, first_ptr, field_for_next) \
MyLinkItem *head; Type *var_it_name = (first_ptr), *var_it_name##_next = nullptr; (var_it_name ? (var_it_name##_next = var_it_name->field_for_next, 1) : 0); var_it_name = var_it_name##_next
MyLinkItem *tail;
};
MyLinkItem item = {}; #define DN_ListQueueAdd(Type, first_ptr, last_ptr, field_for_next, item_to_add_ptr, add) \
MyContainer container = {};
DN_ISinglyHeadTailLLAppend(container, item);
// ... or alternatively, DN_SinglyHeadTailLLAppend(container.head, container.tail, item);
for (MyLinkItem *it = container.head; it; it = it->next) { }
*/
#define DN_SinglyHeadTailLLAppend(head, tail, to_append) \
do { \ do { \
if (!head) \ if (first_ptr) { \
head = to_append; \ DN_AssertF(last_ptr, "Invalid list: first is set (%p) but last is null", first_ptr); \
if (tail) \ DN_ListDebugVerifyListContainsPtr(Type, first_ptr, field_for_next, last_ptr); \
tail->next = to_append; \ } else { \
tail = to_append; \ DN_AssertF(!last_ptr, "Invalid list: first is null but last is set (%p)"); \
} \
DN_AssertF(!item_to_add_ptr->field_for_next, "Invalid list: pointer to add already has next set (%p), should be null", item_to_add_ptr->field_for_next); \
if (add == DN_AddType_Append) { \
if (!first_ptr) \
first_ptr = item_to_add_ptr; \
if (last_ptr) \
last_ptr->field_for_next = item_to_add_ptr; \
last_ptr = item_to_add_ptr; \
} else { \
DN_Assert(add == DN_AddType_Prepend); \
item_to_add_ptr->field_for_next = first_ptr; \
first_ptr = item_to_add_ptr; \
if (!last_ptr) \
last_ptr = item_to_add_ptr; \
} \
} while (0) } while (0)
#define DN_ISinglyHeadTailLLAppend(container_ptr, to_append) DN_SinglyHeadTailLLAppend((container_ptr)->head, (container_ptr)->tail, to_append)
#define DN_ListQueueAppend(Type, first_ptr, last_ptr, field_for_next, item_to_add_ptr) DN_ListQueueAdd(Type, first_ptr, last_ptr, field_for_next, item_to_add_ptr, DN_AddType_Append)
#define DN_ListQueuePrepend(Type, first_ptr, last_ptr, field_for_next, item_to_add_ptr) DN_ListQueueAdd(Type, first_ptr, last_ptr, field_for_next, item_to_add_ptr, DN_AddType_Prepend)
#define DN_ListQueueDetach(Type, first_ptr, last_ptr, field_for_next, detach_ptr) \
do { \
if ((detach_ptr)) { \
DN_ListDebugVerifyListContainsPtr(Type, first_ptr, field_for_next, detach_ptr); \
if ((detach_ptr) == (first_ptr)) { \
if ((first_ptr) == (last_ptr)) \
(last_ptr) = nullptr; \
(first_ptr) = (detach_ptr)->field_for_next; \
} else { \
Type *prev_ = (first_ptr); \
while (prev_ && prev_->field_for_next != (detach_ptr)) \
prev_ = prev_->field_for_next; \
prev_->field_for_next = (detach_ptr)->field_for_next; \
if ((detach_ptr) == (last_ptr)) \
(last_ptr) = prev_; \
} \
(detach_ptr)->field_for_next = nullptr; \
} \
} while (0)
#define DN_ListLinkedAddTo(Type, first_ptr, last_ptr, field_for_next, field_for_prev, src_ptr, dest_ptr, add) \
do { \
if ((first_ptr)) { \
DN_AssertF((last_ptr), "Invalid list: first is set (%p) but last is null", (first_ptr)); \
} else { \
DN_AssertF(!(last_ptr), "Invalid list: first is null but last is set (%p)", (last_ptr)); \
(first_ptr) = (dest_ptr); \
(last_ptr) = (dest_ptr); \
DN_AssertF(!(dest_ptr)->field_for_next, "Invalid list: First and last is being initialised to dest (%p) but dest has next (%p) set, dest cannot be assigned as the last pointer", (dest_ptr), (dest_ptr)->field_for_next); \
DN_AssertF(!(dest_ptr)->field_for_prev, "Invalid list: First and last is being initialised to dest (%p) but dest has prev (%p) set, dest cannot be assigned as the first pointer", (dest_ptr), (dest_ptr)->field_for_prev); \
} \
if ((src_ptr)) { \
if (add == DN_AddType_Append) { \
(src_ptr)->field_for_next = (dest_ptr) ? (dest_ptr)->field_for_next : nullptr; \
(src_ptr)->field_for_prev = (dest_ptr); \
} else { \
DN_Assert(add == DN_AddType_Prepend); \
(src_ptr)->field_for_next = (dest_ptr); \
(src_ptr)->field_for_prev = (dest_ptr) ? (dest_ptr)->field_for_prev : nullptr; \
} \
} \
if ((dest_ptr)) { \
DN_ListDebugVerifyListContainsPtr(Type, first_ptr, field_for_next, dest_ptr); \
if (add == DN_AddType_Append) { \
if ((dest_ptr)->field_for_next) \
(dest_ptr)->field_for_next->field_for_prev = (src_ptr); \
(dest_ptr)->field_for_next = (src_ptr); \
} else { \
DN_Assert(add == DN_AddType_Prepend); \
if ((dest_ptr)->field_for_prev) \
(dest_ptr)->field_for_prev->field_for_next = (src_ptr); \
(dest_ptr)->field_for_prev = (src_ptr); \
} \
} \
if ((dest_ptr) == (first_ptr) && add == DN_AddType_Prepend) \
(first_ptr) = (src_ptr); \
if ((dest_ptr) == (last_ptr) && add == DN_AddType_Append) \
(last_ptr) = (src_ptr); \
} while (0)
#define DN_ListLinkedAppendTo(Type, first_ptr, last_ptr, field_for_next, field_for_prev, src_ptr, dest_ptr) DN_ListLinkedAddTo(Type, first_ptr, last_ptr, field_for_next, field_for_prev, src_ptr, dest_ptr, DN_AddType_Append)
#define DN_ListLinkedPrependTo(Type, first_ptr, last_ptr, field_for_next, field_for_prev, src_ptr, dest_ptr) DN_ListLinkedAddTo(Type, first_ptr, last_ptr, field_for_next, field_for_prev, src_ptr, dest_ptr, DN_AddType_Prepend)
#define DN_ListLinkedAppend(Type, first_ptr, last_ptr, field_for_next, field_for_prev, src_ptr) DN_ListLinkedAddTo(Type, first_ptr, last_ptr, field_for_next, field_for_prev, src_ptr, last_ptr, DN_AddType_Append)
#define DN_ListLinkedPrepend(Type, first_ptr, last_ptr, field_for_next, field_for_prev, src_ptr) DN_ListLinkedAddTo(Type, first_ptr, last_ptr, field_for_next, field_for_prev, src_ptr, first_ptr, DN_AddType_Prepend)
#define DN_ListLinkedDetach(Type, first_ptr, last_ptr, field_for_next, field_for_prev, detach_ptr) \
do { \
if ((first_ptr) && (last_ptr) && (detach_ptr)) { \
DN_ListDebugVerifyListContainsPtr(Type, first_ptr, field_for_next, detach_ptr); \
if ((detach_ptr) == (first_ptr)) \
(first_ptr) = (detach_ptr)->field_for_next; \
if ((detach_ptr) == (last_ptr)) \
(last_ptr) = (detach_ptr)->field_for_prev; \
if ((detach_ptr)->field_for_prev) \
(detach_ptr)->field_for_prev->field_for_next = (detach_ptr)->field_for_next; \
if ((detach_ptr)->field_for_next) \
(detach_ptr)->field_for_next->field_for_prev = (detach_ptr)->field_for_prev; \
(detach_ptr)->field_for_next = nullptr; \
(detach_ptr)->field_for_prev = nullptr; \
} \
} while (0)
#define DN_ListStackPush(Type, first_ptr, field_for_next, item_ptr) \
do { \
DN_AssertF(!(item_ptr)->field_for_next, \
"Invalid list: pointer to push already has next set (%p), should be null", \
(void *)(item_ptr)->field_for_next); \
(item_ptr)->field_for_next = (first_ptr); \
(first_ptr) = (item_ptr); \
} while (0)
#define DN_ListStackDetach(Type, first_ptr, field_for_next, detach_ptr) \
do { \
/* NOTE: `detach_` caches `detach_ptr` into a local because `detach_ptr` can alias `first_ptr`. \
DN_ListStackPop() passes `first_ptr` as both arguments and mutates `first_ptr` which would \
also modify `detach_ptr` causing unwanted side-effects like a null-ptr deref. */ \
Type *detach_ = (detach_ptr); \
if ((first_ptr) && (detach_)) { \
DN_ListDebugVerifyListContainsPtr(Type, first_ptr, field_for_next, detach_); \
if (detach_ == (first_ptr)) { \
(first_ptr) = detach_->field_for_next; \
} else { \
Type *prev_ = (first_ptr); \
while (prev_ && prev_->field_for_next != detach_) \
prev_ = prev_->field_for_next; \
DN_Assert(prev_); \
if (prev_) \
prev_->field_for_next = detach_->field_for_next; \
} \
detach_->field_for_next = nullptr; \
} \
} while (0)
#define DN_ListStackPop(Type, first_ptr, field_for_next) \
DN_ListStackDetach(Type, first_ptr, field_for_next, first_ptr)
// NOTE: Sentinel Doubly Linked List // NOTE: Sentinel Doubly Linked List
// Uses a sentinel/dummy node as the list head. The sentinel points to itself when empty. // Uses a sentinel/dummy node as the list head. The sentinel points to itself when empty.
@@ -4294,7 +4579,6 @@ template <typename T> DN_USize DN_TArrayCopyPtrPool (T **da
template <typename T> DN_USize DN_TArrayCopyPtrPoolAssert (T **data, T const *src, DN_USize count, DN_Pool *pool, DN_CallSite call_site); template <typename T> DN_USize DN_TArrayCopyPtrPoolAssert (T **data, T const *src, DN_USize count, DN_Pool *pool, DN_CallSite call_site);
#endif #endif
DN_API void* DN_SinglyLLDetach (void **link, void **next);
DN_API bool DN_RingHasSpace (DN_Ring const *ring, DN_U64 size); DN_API bool DN_RingHasSpace (DN_Ring const *ring, DN_U64 size);
DN_API bool DN_RingHasData (DN_Ring const *ring, DN_U64 size); DN_API bool DN_RingHasData (DN_Ring const *ring, DN_U64 size);
DN_API void DN_RingWrite (DN_Ring *ring, void const *src, DN_U64 src_size); DN_API void DN_RingWrite (DN_Ring *ring, void const *src, DN_U64 src_size);
@@ -4561,18 +4845,20 @@ DN_API void DN_TestVerifyBytesF
DN_API DN_TestCore DN_TestSuite (DN_Arena *arena_); DN_API DN_TestCore DN_TestSuite (DN_Arena *arena_);
#endif #endif
DN_API void DN_LeakTrackAlloc_ (DN_LeakTracker *leak, void *ptr, DN_USize size, bool alloc_can_leak); DN_API DN_MemDebuggerSnapshot DN_MemDebuggerSnapshotMake (DN_MemDebugger *debugger, DN_Arena *arena);
DN_API void DN_LeakTrackDealloc_ (DN_LeakTracker *leak, void *ptr); DN_API bool DN_MemDebuggerSnapshotPtrDataQSortComparePtrLT (void const *lhs, void const *rhs, void*);
DN_API void DN_LeakDump_ (DN_LeakTracker *leak); DN_API void DN_MemDebuggerAlloc_ (DN_MemDebugger *debugger, void *ptr, DN_USize size, bool alloc_can_leak, DN_CallSite call_site);
DN_API void DN_MemDebuggerDealloc_ (DN_MemDebugger *debugger, void *ptr);
DN_API void DN_MemDebuggerDump_ (DN_MemDebugger *debugger);
#if defined(DN_LEAK_TRACKING) #if defined(DN_MEM_DEBUGGER)
#define DN_LeakTrackAlloc(leak, ptr, size, alloc_can_leak) DN_LeakTrackAlloc_(leak, ptr, size, alloc_can_leak) #define DN_MemDebuggerAlloc(debugger, ptr, size, alloc_can_leak, call_site) DN_MemDebuggerAlloc_(debugger, ptr, size, alloc_can_leak, call_site)
#define DN_LeakTrackDealloc(leak, ptr) DN_LeakTrackDealloc_(leak, ptr) #define DN_MemDebuggerDealloc(debugger, ptr) DN_MemDebuggerDealloc_(debugger, ptr)
#define DN_LeakDump(leak) DN_LeakDump_(leak) #define DN_MemDebuggerDump(debugger) DN_MemDebuggerDump_(debugger)
#else #else
#define DN_LeakTrackAlloc(leak, ptr, size, alloc_can_leak) do { (void)ptr; (void)size; (void)alloc_can_leak; } while (0) #define DN_MemDebuggerAlloc(debugger, ptr, size, alloc_can_leak, call_site) do { (void)ptr; (void)size; (void)alloc_can_leak; } while (0)
#define DN_LeakTrackDealloc(leak, ptr) do { (void)ptr; } while (0) #define DN_MemDebuggerDealloc(debugger, ptr) do { (void)ptr; } while (0)
#define DN_LeakDump(leak) do { } while (0) #define DN_MemDebuggerDump(debugger) do { } while (0)
#endif #endif
#if DN_WITH_OS #if DN_WITH_OS
@@ -4639,8 +4925,10 @@ DN_API DN_Heap DN_OS_HeapInitBasic ()
DN_API DN_Heap DN_OS_HeapInitVirtual (); DN_API DN_Heap DN_OS_HeapInitVirtual ();
DN_API DN_Heap DN_OS_HeapInitDefault (); DN_API DN_Heap DN_OS_HeapInitDefault ();
DN_API DN_Arena DN_OS_ArenaFromHeapVirtual (DN_U64 reserve, DN_U64 commit, DN_MemFlags flags); DN_API DN_Arena DN_OS_ArenaFromHeapVirtualCallSite (DN_U64 reserve, DN_U64 commit, DN_MemFlags flags);
DN_API DN_Arena DN_OS_ArenaFromHeapBasic (DN_U64 size, DN_MemFlags flags); #define DN_OS_ArenaFromHeapVirtual(reserve, commit, flags, name_cstr) DN_OS_ArenaFromHeapVirtualCallSite(reserve, commit, flags, DN_CallSiteNowNamed(name_cstr))
DN_API DN_Arena DN_OS_ArenaFromHeapBasicCallSite (DN_U64 size, DN_MemFlags flags);
#define DN_OS_ArenaFromHeapBasic(size, flags, name_cstr) DN_OS_ArenaFromHeapBasic(size, flags, DN_CallSiteNowNamed(name_cstr))
DN_API void * DN_OS_MemReserve (DN_USize count, DN_MemCommit commit, DN_MemPage page_flags); DN_API void * DN_OS_MemReserve (DN_USize count, DN_MemCommit commit, DN_MemPage page_flags);
DN_API bool DN_OS_MemCommit (void *ptr, DN_USize count, DN_U32 page_flags); DN_API bool DN_OS_MemCommit (void *ptr, DN_USize count, DN_U32 page_flags);
@@ -4793,6 +5081,7 @@ DN_API void DN_OS_WindowMinimise (D
DN_API void DN_OS_WindowBringToFront (DN_OSWindow *window); DN_API void DN_OS_WindowBringToFront (DN_OSWindow *window);
DN_API void DN_OS_WindowFocus (DN_OSWindow *window); DN_API void DN_OS_WindowFocus (DN_OSWindow *window);
DN_API bool DN_OS_WindowIsFocused (DN_OSWindow *window); DN_API bool DN_OS_WindowIsFocused (DN_OSWindow *window);
DN_API void DN_OS_WindowCustomTitlebarSet (DN_OSWindow *window, bool custom_titlebar);
// NOTE: Thread // NOTE: Thread
// Overview // Overview
+8 -6
View File
@@ -34,17 +34,18 @@ pushd %build_dir%
:: GR- Disable C RTTI :: GR- Disable C RTTI
:: Oi Use CPU Intrinsics :: Oi Use CPU Intrinsics
:: Z7 Combine multi-debug files to one debug file :: Z7 Combine multi-debug files to one debug file
set flags=
set flags=%flags% %script_dir%\Source\dn_tests.cpp set flags=%flags% %script_dir%\Source\dn_tests.cpp
set msvc_driver_flags=-EHa -GR- -Od -Oi -Z7 -wd4201 -W4 -nologo %flags% -fsanitize=address set msvc_driver_flags=-EHa -GR- -Od -Oi -Z7 -wd4201 -W4 -nologo %flags% -fsanitize=address
where /q emcc && ( where /q emcc && (
echo [BUILD] Emscripten emcc detected, compiling ... echo [BUILD] Emscripten emcc detected, compiling ...
call emcc -g -msimd128 -msse2 %flags% -o %build_dir%\dn_tests_emcc.js -s FETCH=1 -pthread -s ASYNCIFY=1 -lwebsocket -Wall || echo EMCC build failed&& exit /b 1 call emcc -g -msimd128 -msse2 !flags! -o %build_dir%\dn_tests_emcc.js -s FETCH=1 -pthread -s ASYNCIFY=1 -lwebsocket -Wall || echo EMCC build failed&& exit /b 1
) )
where /q cl && ( where /q cl && (
echo [BUILD] MSVC cl detected, compiling ... echo [BUILD] MSVC cl detected, compiling ...
set msvc_cmd=cl -MTd %msvc_driver_flags% -analyze -Fe:dn_tests_msvc -Fo:dn_tests_msvc set msvc_cmd=cl -MTd !msvc_driver_flags! -analyze -Fe:dn_tests_msvc -Fo:dn_tests_msvc
if exist %build_dir%/Curl/Install/lib/libcurl-d.lib ( if exist %build_dir%/Curl/Install/lib/libcurl-d.lib (
set msvc_cmd=!msvc_cmd! -D DN_WITH_NET_CURL=1 -I %build_dir%/Curl/Install/include %build_dir%/Curl/Install/lib/libcurl-d.lib crypt32.lib ws2_32.lib advapi32.lib wldap32.lib iphlpapi.lib secur32.lib set msvc_cmd=!msvc_cmd! -D DN_WITH_NET_CURL=1 -I %build_dir%/Curl/Install/include %build_dir%/Curl/Install/lib/libcurl-d.lib crypt32.lib ws2_32.lib advapi32.lib wldap32.lib iphlpapi.lib secur32.lib
) )
@@ -52,20 +53,21 @@ pushd %build_dir%
REM Build the single header REM Build the single header
powershell -Command "$time = Measure-Command { !msvc_cmd! | Out-Default }; Write-Host '[BUILD] msvc:'$time.TotalSeconds's'; exit $LASTEXITCODE" || echo MSVC build failed&& exit /b 1 powershell -Command "$time = Measure-Command { !msvc_cmd! | Out-Default }; Write-Host '[BUILD] msvc:'$time.TotalSeconds's'; exit $LASTEXITCODE" || echo MSVC build failed&& exit /b 1
echo [BUILD] Single header generator ... echo [BUILD] Single header generator: USE_SINGLE_HEADER not defined...
call cl %script_dir%\single_header_generator.cpp -Z7 -nologo -link || echo Single header generator build failed&& exit /b 1 call cl %script_dir%\single_header_generator.cpp -Z7 -nologo -link || echo Single header generator build failed&& exit /b 1
call %build_dir%\single_header_generator.exe %script_dir%\Source %script_dir%\Single-Header || echo Single header generation failed&& exit /b 1 call %build_dir%\single_header_generator.exe %script_dir%\Source %script_dir%\Single-Header || echo Single header generation failed&& exit /b 1
REM Build the single header using the single header (to test that the generated single header) REM Build the single header using the single header (to test that the generated single header)
echo [BUILD] Single header generator: USE_SINGLE_HEADER defined...
call cl %script_dir%\single_header_generator.cpp -Z7 -nologo -D USE_SINGLE_HEADER -link || echo Single header generator build failed&& exit /b 1 call cl %script_dir%\single_header_generator.cpp -Z7 -nologo -D USE_SINGLE_HEADER -link || echo Single header generator build failed&& exit /b 1
call %build_dir%\single_header_generator.exe %script_dir%\Source %script_dir%\Single-Header || echo Single header generation failed&& exit /b 1 call %build_dir%\single_header_generator.exe %script_dir%\Source %script_dir%\Single-Header || echo Single header generation failed&& exit /b 1
) )
where /q clang-cl && ( where /q clang-cl && (
echo [BUILD] LLVM clang-cl detected, compiling ... echo [BUILD] LLVM clang-cl detected, compiling ...
set clang_cmd=clang-cl -MT %msvc_driver_flags% -fsanitize=undefined -Fe:dn_tests_clang -link set clang_cmd=clang-cl -MT !msvc_driver_flags! -fsanitize=undefined -Fe:dn_tests_clang -link
powershell -Command "$time = Measure-Command { !clang_cmd! | Out-Default }; Write-Host '[BUILD] clang-cl:'$time.TotalSeconds's'; exit $LASTEXITCODE" || echo CLANG build failed&& exit /b 1 powershell -Command "$time = Measure-Command { !clang_cmd! | Out-Default }; Write-Host '[BUILD] clang-cl:'$time.TotalSeconds's'; exit $LASTEXITCODE" || echo CLANG build failed&& exit /b 1
) )
exit /b 1 popd
popd exit /b 0