SUNENGINE 0.0.2
A simple and bright C++ game engine.
 
Loading...
Searching...
No Matches
Framework.h
1//----------------------------------------------------------------------------
2// Copyright 2019, Ed Keenan, all rights reserved.
3//----------------------------------------------------------------------------
4//
5// Framework - for Keenan's C++ classes
6//
7// One header to rule them all,
8// one header to find them,
9// one header to bring them all
10// and in the Linker bind them. <thank you Tolkien>
11//
12// Don't try to understand it... its very complicated
13//
14// Systems:
15// Memory Tracking - dynamic memory leak tracking
16// C++ Unit Testing - unit testing with teardown
17// Trace - debug printing to visual studio output window
18// Performance timer - hardware cycle count micro timer for performance tracking
19// File logging - dumping data to an external logging file
20// Memory Alignment Base class - keeping alignment to 16 bytes for SIMD
21//
22// ---------------------------------------------------------------------------
23// v.2.5.0
24// v.2.6 - Baseline
25// v.2.6.1 - fixed warning TestRegistry
26// v.2.7 - Baseline
27// v.2.8 - warning 5039 windows.h
28// v.2.9 - fence
29// v.2.10 - msc_ver 1914, win 10.0.17
30// v.2.11 - warning fixes
31// v.2.12 - mutex on all trace::out
32// v.2.13 - fixed warnings on mutex and default copy const / assignment
33// v.2.14 - FileIO remove new... so you can overload new/delete
34// v.2.15 - number tests pass reformat
35// v.2.16 - fixing static analysis issues
36// v.2.18 - teardown issue
37// v.2.19 - WinSDK, Compiler, Framework version reporting
38// v.2.20 - WinSDK, Compiler, Framework version reporting in Release mode
39// v.2.21 - x64 info header
40// v.2.22 - Timer renamed to PerformanceTimer
41// v.2.23 - Mem Tracking now works with placement and alignment new
42// v.2.24 - new tracking with file names and line numbers
43// v.2.25 - fixing collision with unused_var() macros in align16
44// v.2.26 - any order for the link, removed FileIO.cpp and PerformanceTimer.cpp
45// v.2.27 - atomics in Timer
46// v.2.28 - remove dynamic cast, warnings on atomic
47// v.2.29 - placement new on align16
48// v.2.30 - HUGE rework of UnitTest.h removed UnitTest.cpp
49// v.3.00 - Flatten into 2 files
50// v.3.01 - reduce includes
51// v.3.02 - removed framework main... std::call_once() now only one include <period>
52// v.3.03 - MemoryTracking reporting improvements
53// v.3.04 - Clean up of framework
54// v.3.05 - consolidate warnings
55// v.3.06 - Tweaked several settings on configurations 8 in total {debug/release,x86/64, mem_enable/disabled}
56// v.3.07 - nothrow is a problem
57// v.3.08 - application vs external memory tracking
58// v.3.09 - added log file
59// v.3.10 - modes printing
60// v.3.11 - banner before leak print out
61// v.3.12 - project settings
62// v.3.13 - UnitStats, mkdir only it doesn't exist
63// v.3.14 - file open errors... need a cleaner way to deal with them
64// v.3.15 - log directory - fixed for Memory: todo FileIO
65// v.3.16 - added default if MEMORY_LOGS_DIR is missing
66//-----------------------------------------------------------------------------
67
68#ifndef FRAMEWORK_H
69#define FRAMEWORK_H
70
71#define FRAMEWORK_VER "3.16"
72
73// --------------------------------------------------------
74// General Guidelines
75//
76// Using C-Strings for the project
77// You need to set your project settings
78// Properties / General / Advanced / Character Set->Use Multi - Byte Character Set
79//
80// Forced include this this header
81// Properties/C++/Advanced/Forced Include File -> "Framework.h"
82// Make sure Framework.h is any project include directory
83//
84// Add to your defines:
85// Properties/C++/Preprocessor/Preprocessor Definition
86// -> add WINDOWS_TARGET_PLATFORM="$(TargetPlatformVersion)";
87// -> add MEMORY_LOGS_DIR=R"($(SolutionDir))";
88//
89// Turn off Memory Tracking...
90// Comment out the #define MEM_TRACKING_ENABLED
91//
92// --------------------------------------------------------
93
94
95// Comment out this line to turn off memory tracking
96#define MEM_TRACKER_ENABLED
97
98// default warning... please setup correctly
99#ifndef WINDOWS_TARGET_PLATFORM
100 #define WINDOWS_TARGET_PLATFORM "- MISSING - "
101#endif
102
103// Build Mode:
104#ifdef _DEBUG
105 #ifdef _M_X64
106 #define BUILD_CONFIG_MODE "x64 Debug "
107 #else
108 #define BUILD_CONFIG_MODE "x86 Debug "
109 #endif
110#else
111 #ifdef _M_X64
112 #define BUILD_CONFIG_MODE "x64 Release"
113 #else
114 #define BUILD_CONFIG_MODE "x86 Release"
115 #endif
116#endif
117
118// -----------------------------------------------------------------------------
119// Warning levels turned on for Wall... that Should be supressed globally
120// Set here to avoid surpressing them in the settings
121// -----------------------------------------------------------------------------
122
123#pragma warning( disable : 4127 ) // conditional expression is constant
124#pragma warning( disable : 4201 ) // nonstandard extension used: nameless struct/union
125#pragma warning( disable : 4355 ) // 'this' : used in base member initializer list
126#pragma warning( disable : 4514 ) // 'function': unreferenced inline function has been removed
127#pragma warning( disable : 4571 ) // Informational: catch(...) semantics changed since Visual C++ 7.1; structured exceptions (SEH) are no longer caught
128#pragma warning( disable : 4625 ) // 'derived class' : copy constructor was implicitly defined as deleted because a base class copy constructor is inaccessible or deleted
129#pragma warning( disable : 4626 ) // 'derived class' : assignment operator was implicitly defined as deleted because a base class assignment operator is inaccessible or deleted
130#pragma warning( disable : 4668 ) // 'symbol' is not defined as a preprocessor macro, replacing with '0' for 'directive'
131#pragma warning( disable : 4587 ) // 'anonymous_structure': behavior change: constructor is no longer implicitly called
132#pragma warning( disable : 4588 ) // 'anonymous_structure': behavior change: destructor is no longer implicitly called
133#pragma warning( disable : 4710 ) // 'function': function not inlined
134#pragma warning( disable : 4711 ) // function 'function' selected for automatic inline expansion
135#pragma warning( disable : 4820 ) // 'bytes' bytes padding added after construct 'member_name'
136#pragma warning( disable : 5025 ) // 'type': move assignment operator was implicitly defined as deleted
137#pragma warning( disable : 5026 ) // 'type': move constructor was implicitly defined as deleted
138#pragma warning( disable : 5027 ) // 'type': move assignment operator was implicitly defined as deleted
139#pragma warning( disable : 5039 ) // function': pointer or reference to potentially throwing function passed to extern C function under -EHc. Undefined behavior may occur if this function throws an exception.
140#pragma warning( disable : 5045 ) // Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified
141
142#include "ProjectSettings.h"
143
144// --------------------------------------
145// General includes
146// --------------------------------------
147
148#include <assert.h>
149#include <stdio.h>
150#include <cmath>
151#include <stdlib.h>
152#include <crtdbg.h>
153#include <string>
154
155// -----------------------------------------------------
156// Many standard includes have serious warnings
157// need to wrap for Wall warnings
158//
159// Todo: reverify with major compiler releases...
160// Come on Microsoft.. clean up your code
161// -----------------------------------------------------
162
163#pragma warning( push )
164 #pragma warning( disable : 4820 ) // 'bytes' bytes padding added after construct 'member_name'
165#define NOMINMAX
166 #include <Windows.h>
167#pragma warning( pop )
168
169#pragma warning( push )
170 #pragma warning( disable : 4365 ) // 'classname': class has virtual functions, but destructor is not virtual\n instances of this class may not be destructed correctly
171 #pragma warning( disable : 4623 ) // 'derived class': default constructor was implicitly defined as deleted because a base class default constructor is inaccessible or deleted
172 #pragma warning( disable : 4625 ) // 'derived class': copy constructor was implicitly defined as deleted because a base class copy constructor is inaccessible or deleted
173 #pragma warning( disable : 4626 ) // 'derived class': assignment operator was implicitly defined as deleted because a base class assignment operator is inaccessible or deleted
174 #pragma warning( disable : 4820 ) // 'bytes' bytes padding added after construct 'member_name'
175 #pragma warning( disable : 5026 ) // 'type': move constructor was implicitly defined as deleted
176 #pragma warning( disable : 5027 ) // 'type': move assignment operator was implicitly defined as deleted
177 #include <mutex>
178#pragma warning( pop )
179
180#pragma warning( push )
181 #pragma warning( disable : 4365 ) // 'classname': class has virtual functions, but destructor is not virtual\n instances of this class may not be destructed correctly
182 #pragma warning( disable : 4625 ) // 'derived class': copy constructor was implicitly defined as deleted because a base class copy constructor is inaccessible or deleted
183 #pragma warning( disable : 4626 ) // 'derived class': assignment operator was implicitly defined as deleted because a base class assignment operator is inaccessible or deleted
184 #pragma warning( disable : 5026 ) // 'type': move constructor was implicitly defined as deleted
185 #pragma warning( disable : 5027 ) // 'type': move assignment operator was implicitly defined as deleted
186 #include <atomic>
187#pragma warning( pop )
188
189
190// -----------------------------------------------------------------------
191// Copyright 2019, Ed Keenan, all rights reserved.
192//
193// Memory Tracker
194// Homemade Memory Tracker sitting on top of CRTDEBUG
195// Works by macro trick.. replacing everyone's new with macro
196// Problems with placement new() need to follow instructions
197// If using aligned allocations... need to overload new/delete operator see Align16 for example
198// Only works in Debug and with MEM_TRACKER_ENABLE is defined not in RELEASE
199// Works in x86/64 and with external libraries that are leaking as well
200//
201// Used to be stand alone files... now all one include
202//
203// -----------------------------------------------------------------------
204
205#ifndef MEM_TRACKER_H
206#define MEM_TRACKER_H
207
208 // ---------------------------------------------------------------------------
209 // One instructions to rule them all:
210 //
211 // To Enable:
212 // #define MEM_TRACKER_ENABLED
213 // To Disable:
214 // Comment out #define MEM_TRACKER_ENABLED
215 //
216 // Include Framework.h to every file:
217 // Change your project settings
218 // Go to C / C++ tab
219 // Go to Advanced
220 // set Forced Include : Framework.h
221 // This will add this file automagically to all files (great!)
222 //
223 // Placement new changes:
224 // No memory tracking __SHOULD__ take place on placement new
225 // So you need to tell the Memory Tracking system to ignore this placement new
226 // Add 3 lines around placement new to allow it to compile
227 //
228 // example: Dog *pDog = new(address) Dog(); // original (new way below)
229 //
230 // PLACEMENT_NEW_BEGIN <----- Add 1/3 --------------
231 // #undef new <----- Add 2/3 --------------
232 //
233 // Dog *pDog = new(address) Dog();
234 //
235 // PLACEMENT_NEW_END <----- Add 3/3 --------------
236 //
237 // Issue with new(std::nothrow)
238 // This needs to be tracked... but the macro trick is a problem
239 //
240 // ---------------------------------------------------------------------------
241
242 enum class MemTracker
243 {
244 Disabled
245 };
246
247 #if defined(_DEBUG) && defined(MEM_TRACKER_ENABLED)
248 #define MEMORY_TRACKING_ENABLE_STRING "enabled "
249 #else
250 #define MEMORY_TRACKING_ENABLE_STRING "--> DISABLED <--"
251 #endif
252
253 class MemTrace
254 {
255 private:
256 static const unsigned int MemTraceBuffSize = 256;
257
258 public:
259 // -----------------------------------------------------
260 // Only found this structure in documentation
261 // created a shadow structure to allow error reporting
262 // -----------------------------------------------------
263 typedef struct _CrtMemBlockHeader
264 {
265 static const unsigned int nNoMansLandSize = 4; // said in doc that its 4
266
267 struct _CrtMemBlockHeader *pBlockHeaderNext;
268 struct _CrtMemBlockHeader *pBlockHeaderPrev;
269 char *szFileName; // File name
270 int nLine; // Line number
271 int nBlockUse; // Type of block
272 size_t nDataSize; // Size of user block
273 long lRequest; // Allocation number
274 unsigned char gap[nNoMansLandSize];
275
276 // ---------------------------------------------------
277 // In an actual memory block in the debug heap,
278 // this structure is followed by:
279 // unsigned char data[nDataSize];
280 // unsigned char anotherGap[nNoMansLandSize];
281 // ---------------------------------------------------
282
284
285 public:
286 // Big Six
287 MemTrace() noexcept
288 {
289 memset(&privBuff[0], 0, MemTraceBuffSize);
290 }
291 MemTrace(const MemTrace &) = delete;
292 MemTrace(MemTrace &&) = delete;
293 MemTrace & operator = (const MemTrace &) = delete;
294 MemTrace & operator = (MemTrace &&) = delete;
295 ~MemTrace() = default;
296
297 private:
298 // displays a printf to the output window
299 void privOut(const char * const fmt, ...)
300 {
301 MemTrace *pTrace = MemTrace::privGetInstance();
302 assert(pTrace);
303
304 pTrace->mtx.lock();
305
306 va_list args;
307
308 #pragma warning( push )
309 #pragma warning( disable : 26492 )
310 #pragma warning( disable : 26481 )
311 va_start(args, fmt);
312 #pragma warning( pop )
313
314 vsprintf_s(&pTrace->privBuff[0], MemTraceBuffSize, fmt, args);
315 OutputDebugString(&pTrace->privBuff[0]);
316
317 // va_end(args); - original.. below to new code
318 args = static_cast<va_list> (nullptr);
319
320 pTrace->mtx.unlock();
321 }
322
323 char *privStripDir( const char * const pInName)
324 {
325 char *pReturn = (char *)pInName;
326
327 const char *pch = pInName;
328
329 while (pch != 0)
330 {
331 pch = strstr(pch, "\\");
332 if (pch != 0)
333 {
334 pch += 1;
335 pReturn = (char *)pch;
336 }
337 }
338
339 return pReturn;
340 }
341
342 void privDisplayLogLink()
343 {
344 char sBuff[512] = { 0 };
345 GetCurrentDirectory(512, sBuff);
346
347 const char *pch = sBuff;
348 char *pSlash = nullptr;
349
350 while (pch != 0)
351 {
352 pch = strstr(pch, "\\");
353 if (pch != 0)
354 {
355 pch += 1;
356 pSlash = (char *)pch;
357 }
358 }
359
360 size_t numBytes = (size_t)(pSlash - sBuff);
361
362 char pBuff[512] = { 0 };
363 memcpy_s(pBuff, 512, sBuff, numBytes);
364
365#ifndef MEMORY_LOGS_DIR
366 std::string strLogFile = "";
367 strLogFile.append("Logs");
368 strLogFile.append("\\MemTrackerLog.txt");
369#else
370 std::string strLogFile = MEMORY_LOGS_DIR;
371 strLogFile.append("Logs");
372 strLogFile.append("\\MemTrackerLog.txt");
373#endif
374 this->privOut("\n");
375 this->privOut(" MemTrackerLog Link: \n");
376 this->privOut(" %s(1) : <Double Click>\n", strLogFile.c_str());
377 this->privOut("\n");
378 }
379
380 public:
381 static void ProcessEnd() noexcept
382 {
383 MemTrace *pTrace = MemTrace::privGetInstance();
384
385 // This is included so you can have one universal include
386 std::call_once(pTrace->ProcessEndFlag, [pTrace]()
387 {
388 FILE* pFile = nullptr;
389
390#ifndef MEMORY_LOGS_DIR
391 system("if not exist .\\..\\Logs mkdir .\\..\\Logs");
392 fopen_s(&pFile, ".\\..\\Logs\\MemTrackerLog.txt", "w");
393#else
394 std::string strLogDir = MEMORY_LOGS_DIR;
395 strLogDir.append("Logs");
396 strLogDir.append("\"");
397 strLogDir.insert(0, "\"");
398
399 std::string mkLogDir = "if not exist " + strLogDir + " mkdir " + strLogDir;
400 system(mkLogDir.c_str());
401
402 std::string strLogFile = MEMORY_LOGS_DIR;
403 strLogFile.append("Logs");
404 strLogFile.append("\\MemTrackerLog.txt");
405 fopen_s(&pFile, strLogFile.c_str(), "w");
406#endif
407
408 assert(pFile);
409 if (pFile != nullptr)
410 {
411 fprintf(pFile, "\n");
412 fprintf(pFile, "****************************************\n");
413 fprintf(pFile, "\n");
414 fprintf(pFile, " MemTrackerLog \n");
415 fprintf(pFile, "\n");
416 fprintf(pFile, " %s \n", __DATE__);
417 fprintf(pFile, " %s \n", __TIME__);
418 fprintf(pFile, "\n");
419 fprintf(pFile, "****************************************\n");
420 fprintf(pFile, "\n");
421 fprintf(pFile, "External Libs: \n");
422 fprintf(pFile, "\n");
423 }
424 _CrtMemState state;
425 _CrtMemCheckpoint(&state);
426
427 pTrace->privOut("\n");
428 _CrtMemBlockHeader *pTmp;
429 pTmp = reinterpret_cast<MemTrace::_CrtMemBlockHeader *> (state.pBlockHeader);
430
431 unsigned int i = 0;
432
433 size_t appMaxIndex = 0;
434 size_t appMaxSize = 0;
435 size_t appCount = 0;
436 size_t appTotalSize = 0;
437 _CrtMemBlockHeader *pAppMaxTmp = nullptr;
438
439 size_t extMaxIndex = 0;
440 size_t extMaxSize = 0;
441 size_t extCount = 0;
442 size_t extTotalSize = 0;
443 _CrtMemBlockHeader *pExtMaxTmp = nullptr;
444
445 int NormBlockLeakCount = 0;
446
447 // Walk to the end of list && see if there is any leaks
448 while (pTmp != nullptr)
449 {
450 if (pTmp->nBlockUse == _NORMAL_BLOCK)
451 {
452 NormBlockLeakCount++;
453 }
454
455 if (pTmp->pBlockHeaderNext == nullptr)
456 {
457 break;
458 }
459 pTmp = pTmp->pBlockHeaderNext;
460 }
461
462 if (NormBlockLeakCount > 0)
463 {
464 pTrace->privOut("------------------------------------------------------\n");
465 pTrace->privOut(">>> Memory Tracking: Leaks detected <<<\n");
466 pTrace->privOut(">>> Double click on file string to Leak location <<<\n");
467 pTrace->privOut("------------------------------------------------------\n");
468 pTrace->privOut("\n");
469
470 while (pTmp != nullptr)
471 {
472 if (pTmp->nBlockUse == _NORMAL_BLOCK)
473 {
474 // treat allocation with/without names as different groups
475 if (pTmp->szFileName == nullptr)
476 {
477 extTotalSize += pTmp->nDataSize;
478 extCount++;
479 if (extMaxSize < pTmp->nDataSize)
480 {
481 extMaxSize = pTmp->nDataSize;
482 extMaxIndex = i;
483 pExtMaxTmp = pTmp;
484 }
485 if (pFile != nullptr)
486 {
487 fprintf(pFile, "Leak(%d) %d bytes ref:%d \n", (int)i, (int)pTmp->nDataSize, (int)pTmp->lRequest);
488 }
489 }
490 else
491 {
492 appTotalSize += pTmp->nDataSize;
493 appCount++;
494 if (appMaxSize < pTmp->nDataSize)
495 {
496 appMaxSize = pTmp->nDataSize;
497 appMaxIndex = i;
498 pAppMaxTmp = pTmp;
499 }
500
501 pTrace->privOut("Leak(%d) %d bytes ref:%d %s \n", i, pTmp->nDataSize, pTmp->lRequest, pTrace->privStripDir(pTmp->szFileName));
502 pTrace->privOut(" %s(%d) : <Double Click> \n", pTmp->szFileName, pTmp->nLine);
503 pTrace->privOut("\n");
504 }
505
506 i++;
507 }
508 pTmp = pTmp->pBlockHeaderPrev;
509 }
510
511 pTrace->privOut("Memory Tracking statistics \n");
512 pTrace->privOut("\n");
513 pTrace->privOut(" Application files: \n");
514 pTrace->privOut(" num of leaks: %d \n", appCount);
515 pTrace->privOut(" total bytes leaked: %d \n", appTotalSize);
516 if (pAppMaxTmp != nullptr)
517 {
518 pTrace->privOut(" largest individual: Leak(%d) size: %d \n", appMaxIndex, pAppMaxTmp->nDataSize);
519 }
520 pTrace->privOut("\n");
521 pTrace->privOut(" External Libs: \n");
522 pTrace->privOut(" num of leaks: %d \n", extCount);
523 pTrace->privOut(" total bytes leaked: %d \n", extTotalSize);
524
525 if (pExtMaxTmp != nullptr)
526 {
527 pTrace->privOut(" largest individual: Leak(%d) size: %d \n", extMaxIndex, pExtMaxTmp->nDataSize);
528 }
529 if (pFile != nullptr)
530 {
531 fprintf(pFile, "\n");
532 fprintf(pFile, "Memory Tracking Stats:\n");
533 fprintf(pFile, "\n");
534 fprintf(pFile, " Application files: \n");
535 fprintf(pFile, " num of leaks: %d \n", (int)appCount);
536 fprintf(pFile, " total bytes leaked: %d \n", (int)appTotalSize);
537 if (pAppMaxTmp != nullptr)
538 {
539 fprintf(pFile, " largest individual: Leak(%d) size: %d \n", (int)appMaxIndex, (int)pAppMaxTmp->nDataSize);
540 }
541 fprintf(pFile, "\n");
542 fprintf(pFile, " External Libs: \n");
543 fprintf(pFile, " num of leaks: %d \n", (int)extCount);
544 fprintf(pFile, " total bytes leaked: %d \n", (int)extTotalSize);
545
546 if (pExtMaxTmp != nullptr)
547 {
548 fprintf(pFile, " largest individual: Leak(%d) size: %d \n", (int)extMaxIndex, (int)pExtMaxTmp->nDataSize);
549 }
550
551 fprintf(pFile, "\n");
552 fprintf(pFile, "CRT Debug Stats: \n");
553 fprintf(pFile, "\n");
554 fprintf(pFile, " %d bytes in %d Free Blocks \n", (int)state.lSizes[_FREE_BLOCK], (int)state.lCounts[_FREE_BLOCK]);
555 fprintf(pFile, " %d bytes in %d Normal Blocks \n", (int)state.lSizes[_NORMAL_BLOCK], (int)state.lCounts[_NORMAL_BLOCK]);
556 fprintf(pFile, " %d bytes in %d CRT Blocks \n", (int)state.lSizes[_CRT_BLOCK], (int)state.lCounts[_CRT_BLOCK]);
557 fprintf(pFile, " %d bytes in %d Ignore Blocks \n", (int)state.lSizes[_IGNORE_BLOCK], (int)state.lCounts[_IGNORE_BLOCK]);
558 fprintf(pFile, " %d bytes in %d Client Blocks \n", (int)state.lSizes[_CLIENT_BLOCK], (int)state.lCounts[_CLIENT_BLOCK]);
559 }
560 pTrace->privDisplayLogLink();
561
562 }
563
564 //pTrace->privOut("\n");
565 pTrace->privOut("--------------------------------\n");
566 //printf("\n");
567 printf("--------------------------------\n");
568 if (appCount)
569 {
570 pTrace->privOut(">>> Memory Tracking: FAIL <<<<<<\n");
571 printf(">>> Memory Tracking: FAIL <<<<<<\n");
572 }
573 else
574 {
575 pTrace->privOut(" Memory Tracking: passed \n");
576 printf(" Memory Tracking: passed \n");
577 }
578 pTrace->privOut("--------------------------------\n");
579 pTrace->privOut(" Memory Tracking: end() \n");
580 pTrace->privOut("--------------------------------\n");
581 printf("--------------------------------\n");
582 printf(" Memory Tracking: end() \n");
583 printf("--------------------------------\n");
584 printf("\n");
585
586 //_CrtMemDumpStatistics(&state);
587
588 if (pFile != nullptr)
589 {
590 fclose(pFile);
591 }
592
593 }
594 );
595 };
596
597 static void ProcessBegin() noexcept
598 {
599 MemTrace *pTrace = MemTrace::privGetInstance();
600
601 // This is included so you can have one universal include
602 std::call_once(pTrace->ProcessBeginFlag, [pTrace]()
603 {
604 pTrace->privOut("\n");
605 pTrace->privOut("****************************************\n");
606 pTrace->privOut("** Framework: %s **\n", FRAMEWORK_VER);
607 pTrace->privOut("** C++ Compiler: %d **\n", _MSC_FULL_VER);
608 pTrace->privOut("** Windows SDK: %s **\n", WINDOWS_TARGET_PLATFORM);
609 pTrace->privOut("** Mem Tracking: %s **\n", MEMORY_TRACKING_ENABLE_STRING);
610 pTrace->privOut("** Mode: %s **\n", BUILD_CONFIG_MODE);
611 pTrace->privOut("****************************************\n");
612 pTrace->privOut("\n");
613 printf("\n");
614 printf("****************************************\n");
615 printf("** Framework: %s **\n", FRAMEWORK_VER);
616 printf("** C++ Compiler: %d **\n", _MSC_FULL_VER);
617 printf("** Windows SDK: %s **\n", WINDOWS_TARGET_PLATFORM);
618 printf("** Mem Tracking: %s **\n", MEMORY_TRACKING_ENABLE_STRING);
619 printf("** Mode: %s **\n", BUILD_CONFIG_MODE);
620 printf("****************************************\n");
621 printf("\n");
622 pTrace->privOut("--------------------------------\n");
623 pTrace->privOut(" Memory Tracking: start() \n");
624 pTrace->privOut("--------------------------------\n");
625 pTrace->privOut("\n");
626 printf("--------------------------------\n");
627 printf(" Memory Tracking: start() \n");
628 printf("--------------------------------\n");
629 printf("\n");
630 }
631 );
632 }
633
634 static void ProcessBegin_Release() noexcept
635 {
636 MemTrace *pTrace = MemTrace::privGetInstance();
637
638 // This is included so you can have one universal include
639 std::call_once(pTrace->ProcessBeginFlag, [pTrace]()
640 {
641 pTrace->privOut("\n");
642 pTrace->privOut("****************************************\n");
643 pTrace->privOut("** Framework: %s **\n", FRAMEWORK_VER);
644 pTrace->privOut("** C++ Compiler: %d **\n", _MSC_FULL_VER);
645 pTrace->privOut("** Windows SDK: %s **\n", WINDOWS_TARGET_PLATFORM);
646 pTrace->privOut("** Mem Tracking: %s **\n", MEMORY_TRACKING_ENABLE_STRING);
647 pTrace->privOut("** Mode: %s **\n", BUILD_CONFIG_MODE);
648 pTrace->privOut("****************************************\n");
649 pTrace->privOut("\n");
650 printf("\n");
651 printf("****************************************\n");
652 printf("** Framework: %s **\n", FRAMEWORK_VER);
653 printf("** C++ Compiler: %d **\n", _MSC_FULL_VER);
654 printf("** Windows SDK: %s **\n", WINDOWS_TARGET_PLATFORM);
655 printf("** Mem Tracking: %s **\n", MEMORY_TRACKING_ENABLE_STRING);
656 printf("** Mode: %s **\n", BUILD_CONFIG_MODE);
657 printf("****************************************\n");
658 printf("\n");
659 }
660 );
661 }
662
663 std::once_flag ProcessBeginFlag;
664 std::once_flag ProcessEndFlag;
665
666 private:
667 static MemTrace *privGetInstance() noexcept
668 {
669 // This is where its actually stored (BSS section)
670 static MemTrace helper;
671 return &helper;
672 }
673 char privBuff[MemTraceBuffSize];
674 std::mutex mtx;
675 };
676
677 #define PLACEMENT_NEW_BEGIN __pragma(push_macro("new")) \
678 __pragma(warning( disable : 4291)) // placement new issue
679
680 #define PLACEMENT_NEW_END __pragma(pop_macro("new"))
681
682 #if defined(_DEBUG) && defined(MEM_TRACKER_ENABLED)
683 #define _CRTDBG_MAP_ALLOC
684 #define new new( _NORMAL_BLOCK , __FILE__ , __LINE__ )
685 #else
686 #pragma warning( push )
687 #pragma warning( disable : 4820 )
688 #pragma warning( disable : 4577 )
689 #pragma warning( disable : 4987 )
690 #include <new>
691 #pragma warning( pop )
692 #endif
693
694 #ifdef MEM_TRACKER_ENABLED
695 #ifdef _DEBUG
696 #define MEM_TRACKER_PROCESS_BEGIN \
697 MemTrace::ProcessBegin();
698
699 #define MEM_TRACKER_PROCESS_END \
700 MemTrace::ProcessEnd();
701 #else
702 #define MEM_TRACKER_PROCESS_BEGIN \
703 MemTrace::ProcessBegin_Release();
704
705 #define MEM_TRACKER_PROCESS_END
706
707 #endif
708 #else
709 #define MEM_TRACKER_PROCESS_BEGIN \
710 MemTrace::ProcessBegin_Release();
711
712 #define MEM_TRACKER_PROCESS_END
713
714 #endif
715
716 // MEM_TRACKER_BEGIN:
717 static struct _StaticMem
718 {
719 _StaticMem() noexcept
720 {
721 MEM_TRACKER_PROCESS_BEGIN
722 }
723 ~_StaticMem()
724 {
725 MEM_TRACKER_PROCESS_END
726 }
727 _StaticMem(const _StaticMem &) = delete;
728 _StaticMem(_StaticMem &&) = delete;
729 _StaticMem &operator = (const _StaticMem &) = delete;
730 _StaticMem &operator = (_StaticMem &&) = delete;
731 } _StaticMemInst;
732
733
734#endif MEM_TRACKER_H
735
736
737// -----------------------------------------------------------------------
738// Copyright 2019, Ed Keenan, all rights reserved.
739//
740// CPP Unit Test
741// Unit Test in C++ without exceptions (that was hard)
742// Includes TearDown.. so you can cleanup allocations even if test fails
743// Test aborts on first failed CHECK() in unit test, then continues to next
744//
745// Used to be stand alone files... now all one include
746//
747// -----------------------------------------------------------------------
748
749#ifndef UNIT_TEST_CPP_H
750#define UNIT_TEST_CPP_H
751
752 class UnitTrace
753 {
754 private:
755 static const unsigned int UnitTraceBuffSize = 256;
756
757 public:
758 // displays a printf to the output window
759 static void out(const char * const fmt, ...)
760 {
761 UnitTrace *pTrace = UnitTrace::privGetInstance();
762 assert(pTrace);
763
764 pTrace->mtx.lock();
765
766 va_list args;
767
768 #pragma warning( push )
769 #pragma warning( disable : 26492 )
770 #pragma warning( disable : 26481 )
771 va_start(args, fmt);
772 #pragma warning( pop )
773
774 vsprintf_s(&pTrace->privBuff[0], UnitTraceBuffSize, fmt, args);
775 OutputDebugString(&pTrace->privBuff[0]);
776
777 //va_end(args);
778 args = static_cast<va_list> (nullptr);
779
780 pTrace->mtx.unlock();
781 }
782
783 // Big Six
784 UnitTrace() noexcept
785 {
786 memset(&privBuff[0], 0x0, UnitTraceBuffSize);
787 }
788 UnitTrace(const UnitTrace &) = delete;
789 UnitTrace(UnitTrace &&) = delete;
790 UnitTrace & operator = (const UnitTrace &) = delete;
791 UnitTrace & operator = (UnitTrace &&) = delete;
792 ~UnitTrace() = default;
793
794 private:
795 static UnitTrace *privGetInstance() noexcept
796 {
797 // This is where its actually stored (BSS section)
798 static UnitTrace helper;
799 return &helper;
800 }
801 char privBuff[UnitTraceBuffSize];
802 std::mutex mtx;
803 };
805 {
806 public:
807 static bool AreEqual(float a, float b, float epsilon = 0.001f) noexcept
808 {
809 return (fabs(a - b) < epsilon);
810 }
811
812 static bool AreEqual(double a, double b, double epsilon = 0.001f) noexcept
813 {
814 return (fabs(a - b) < epsilon);
815 }
816 };
817 struct UnitStats
818 {
819 // Big six
820 UnitStats() noexcept
821 :testCount(0),
822 testPass(0),
823 testFail(0),
824 indvAsserts(0)
825 {
826 }
827 UnitStats(const UnitStats &) = default;
828 UnitStats(UnitStats &&) = default;
829 UnitStats & operator = (const UnitStats &) = default;
830 UnitStats & operator = (UnitStats &&) = default;
831 ~UnitStats() = default;
832
833 // data: ------------------
834 int testCount;
835 int testPass;
836 int testFail;
837 int indvAsserts;
838 };
839 struct UnitData
840 {
841 // Big six
842 UnitData() noexcept
843 : pMemberName(nullptr),
844 pSourceFilePath(nullptr),
845 sourceLineNumber(0),
846 result(false),
847 pad0(0),
848 pad1(0),
849 pad2(0)
850 {
851 }
852 UnitData(const UnitData &) = delete;
853 UnitData(UnitData &&) = delete;
854 UnitData & operator = (const UnitData &) = delete;
855 UnitData & operator = (UnitData &&) = delete;
856 ~UnitData() = default;
857
858 // data: -----------------
859 const char *pMemberName;
860 const char *pSourceFilePath;
861 int sourceLineNumber;
862 bool result;
863 char pad0;
864 char pad1;
865 char pad2;
866 };
867 class UnitSLink
868 {
869 public:
870 // Big Six
871 UnitSLink() noexcept
872 :_pNext(nullptr)
873 {
874 }
875 UnitSLink(const UnitSLink &) = delete;
876 UnitSLink(UnitSLink &&) = delete;
877 UnitSLink & operator = (const UnitSLink &) = delete;
878 UnitSLink & operator = (UnitSLink &&) = delete;
879 virtual ~UnitSLink() = default;
880
881 static void AddToFront(UnitSLink *&pRoot, UnitSLink &rNode) noexcept
882 {
883 if (pRoot == nullptr)
884 {
885 pRoot = &rNode;
886 assert(rNode._pNext == nullptr);
887 }
888 else
889 {
890 UnitSLink *pTmp = pRoot;
891 pRoot = &rNode;
892 rNode._pNext = pTmp;
893 }
894 }
895 static void AddToEnd(UnitSLink *&pRoot, UnitSLink *pNode) noexcept
896 {
897 if (nullptr == pRoot)
898 {
899 pRoot = pNode;
900
901 assert(pNode != nullptr);
902 assert(pNode->_pNext == nullptr);
903 }
904 else
905 {
906 UnitSLink *pTmpX = pRoot;
907
908 while (pTmpX != nullptr)
909 {
910 if (pTmpX->_pNext == nullptr)
911 {
912 // at the end
913 pTmpX->_pNext = pNode;
914 pNode->_pNext = nullptr;
915 }
916
917 pTmpX = pTmpX->_pNext;
918 }
919 }
920 }
921
922 public:
923 // Data
924 UnitSLink *_pNext;
925 };
926 class TestRegistry
927 {
928 public:
929 // Big four
930 TestRegistry(const TestRegistry &) = delete;
931 TestRegistry(TestRegistry &&) = delete;
932 TestRegistry & operator = (const TestRegistry &) = delete;
933 TestRegistry & operator = (TestRegistry &&) = delete;
934 ~TestRegistry() = default;
935
936 void AddTest(UnitSLink *pTest) noexcept
937 {
938 // add to End
939 UnitSLink::AddToEnd(this->_pRoot, pTest);
940 }
941 UnitStats &GetStats() noexcept
942 {
943 return this->_UnitStats;
944 }
945 UnitData &GetData() noexcept
946 {
947 return this->_UnitData;
948 }
949 UnitSLink *GetRoot() noexcept
950 {
951 return this->_pRoot;
952 }
953 static TestRegistry &GetInstance() noexcept
954 {
955 static TestRegistry tRegistry;
956 return tRegistry;
957 }
958 static UnitStats Stats()
959 {
960 TestRegistry &reg = TestRegistry::GetInstance();
961 return reg._UnitStats;
962 }
963
964 private:
965 TestRegistry() noexcept
966 {
967 this->_pRoot = nullptr;
968 }
969
970 // Data: ------------------------
971 UnitData _UnitData;
972 UnitStats _UnitStats;
973 UnitSLink *_pRoot;
974 };
975 class Test : public UnitSLink
976 {
977 public:
978
979 Test(const char * const pTestName) noexcept
980 :UnitSLink(),
981 pName(pTestName),
982 testFunc(nullptr)
983 {
984 // functional pointer
985 this->testFunc = this;
986
987 // register it
988 TestRegistry &tR = TestRegistry::GetInstance();
989 tR.AddTest(this);
990 }
991
992 // Big six
993 Test() = delete;
994 Test(const Test &) = delete;
995 Test(Test &&) = delete;
996 Test & operator = (const Test &) = delete;
997 Test & operator = (Test &&) = delete;
998 ~Test() = default;
999 virtual void run(UnitData &, UnitStats &) = 0;
1000
1001 // For Tests with NO Teardowns... do nothing
1002 virtual void teardown() noexcept
1003 {
1004 };
1005
1006 static void RunTests()
1007 {
1008 #ifdef _DEBUG
1009 UnitTrace::out("------------------- Testing DEBUG ------------------------\n");
1010
1011 #ifdef _M_X64
1012 const char * const mode = "x64 Debug";
1013 #else
1014 const char * const mode = "x86 Debug";
1015 #endif
1016 #else
1017 #ifdef _M_X64
1018 const char * const mode = "x64 Release";
1019 #else
1020 const char * const mode = "x86 Release";
1021 #endif
1022
1023 #ifdef MR_FAST // Only used in optimized class
1024 UnitTrace::out("------------------- Testing MR_FAST ----------------------\n");
1025 #else
1026 UnitTrace::out("------------------- Testing RELEASE ----------------------\n");
1027 #endif
1028 #endif
1029
1030 UnitTrace::out("\n");
1031 TestRegistry &rRegistry = TestRegistry::GetInstance();
1032 UnitSLink *pTmp = rRegistry.GetRoot();
1033
1034 UnitStats &unitStats = rRegistry.GetStats();
1035 UnitData &unitData = rRegistry.GetData();
1036
1037 while (pTmp != nullptr)
1038 {
1039 unitStats.testCount++;
1040
1041 // downcast to the test
1042 Test *pTest = (Test *)(pTmp);
1043
1044 assert(pTest);
1045 printf("Test:%s \n", pTest->pName);
1046
1047 // Needed to be added - for fencing issues between tests
1048 // Release rearranges.. and affects timing
1049
1050 // Forces a Fence...
1051 atomic_thread_fence(std::memory_order_acq_rel);
1052
1053 // run the test
1054 unitData.result = true;
1055
1056 assert(pTest->testFunc != nullptr);
1057 pTest->testFunc->run(unitData, unitStats);
1058
1059 // Forces a Fence...
1060 atomic_thread_fence(std::memory_order_acq_rel);
1061
1062 // Always call the teardown
1063 pTest->testFunc->teardown();
1064
1065 // Forces a Fence...
1066 atomic_thread_fence(std::memory_order_acq_rel);
1067
1068
1069 if (unitData.result == true)
1070 {
1071 unitStats.testPass++;
1072 }
1073 else
1074 {
1075 unitStats.testFail++;
1076 }
1077
1078 // next test
1079 pTmp = pTmp->_pNext;
1080 }
1081
1082 if (unitStats.testFail)
1083 {
1084 UnitTrace::out("\n");
1085 }
1086 UnitTrace::out(" (%s) testPass: %d\n", mode, unitStats.testPass);
1087 UnitTrace::out(" (%s) testFail: %d\n", mode, unitStats.testFail);
1088 UnitTrace::out("\n");
1089 UnitTrace::out(" testCount: %d\n", unitStats.testCount);
1090 UnitTrace::out("indvChecks: %d\n", unitStats.indvAsserts);
1091 UnitTrace::out("\n");
1092 UnitTrace::out("-----------------\n");
1093
1094 printf("\n");
1095 printf(" (%s) testPass: %d\n", mode, unitStats.testPass);
1096 printf(" (%s) testFail: %d\n", mode, unitStats.testFail);
1097 printf("\n");
1098 printf(" testCount: %d\n", unitStats.testCount);
1099 printf("indvChecks: %d\n", unitStats.indvAsserts);
1100 printf("\n");
1101 printf("-----------------\n");
1102 }
1103
1104 public:
1105 const char * const pName;
1106 Test *testFunc;
1107 };
1108
1109 // a trick to create a c-string
1110 #define STRING_ME(s) #s
1111
1112 // Increments total check count
1113 // Creates a clickable format in the output window for failure
1114 // Abort test on first fail
1115 #define CHECK( condition ) \
1116 { \
1117 _UnitStats.indvAsserts++;\
1118 if( !( condition ) ) \
1119 { \
1120 _UnitData.result = false; \
1121 _UnitData.pMemberName = this->pName; \
1122 _UnitData.pSourceFilePath = __FILE__; \
1123 _UnitData.sourceLineNumber = __LINE__; \
1124 UnitTrace::out("%s(%d): %s \n", _UnitData.pSourceFilePath, _UnitData.sourceLineNumber, _UnitData.pMemberName ); \
1125 printf("%s(%d): %s \n", _UnitData.pSourceFilePath, _UnitData.sourceLineNumber, _UnitData.pMemberName ); \
1126 return; \
1127 } \
1128 else\
1129 {\
1130 }\
1131 }
1132
1133 #define CHECK_EQUAL( value1, value2 ) \
1134 { \
1135 _UnitStats.indvAsserts++;\
1136 if( !( (value1) == (value2) ) ) \
1137 { \
1138 _UnitData.result = false; \
1139 _UnitData.pMemberName = this->pName; \
1140 _UnitData.pSourceFilePath = __FILE__; \
1141 _UnitData.sourceLineNumber = __LINE__; \
1142 UnitTrace::out("%s(%d): %s\n", _UnitData.pSourceFilePath, _UnitData.sourceLineNumber, _UnitData.pMemberName ); \
1143 printf("%s(%d): %s\n", _UnitData.pSourceFilePath, _UnitData.sourceLineNumber, _UnitData.pMemberName ); \
1144 return; \
1145 } \
1146 else\
1147 {\
1148 }\
1149 }
1150
1151 // -----------------------------------------------------------------------------
1152 // Here is the unit test magic
1153 //
1154 // 1) it creates a class, <TestName>_Test
1155 // it is derived from Test class
1156 // 2) it defines the constructor and calls the base constructor with the name
1157 // it registers the name of the test to a single class (TestRegistry)
1158 // 3) It also overloads the Test::run() method with the body of the macro
1159 //
1160 // -----------------------------------------------------------------------------
1161
1162 #define TEST_END }
1163
1164 #define TEST( TestName, GroupName, TestFlagEnable ) \
1165 class TestName##_##GroupName##_Test : public Test \
1166 { \
1167 public: \
1168 TestName##_##GroupName##_Test() noexcept : \
1169 Test( STRING_ME(TestName##_##GroupName##_Test)) \
1170 { \
1171 }; \
1172 TestName##_##GroupName##_Test & operator = (const TestName##_##GroupName##_Test &) = delete;\
1173 TestName##_##GroupName##_Test(const TestName##_##GroupName##_Test &) = delete;\
1174 \
1175 void run(UnitData &_UnitData, UnitStats &_UnitStats) override;\
1176 } TestName##_##GroupName##_instance; \
1177 \
1178 void TestName##_##GroupName##_Test::run( UnitData &_UnitData, UnitStats &_UnitStats ) \
1179 { \
1180 if(!TestFlagEnable) \
1181 { \
1182 _UnitStats.testCount--; \
1183 _UnitStats.testPass--; \
1184 } \
1185 else
1186
1187 #define TEST_WITH_TEARDOWN( TestName, GroupName, TestFlagEnable ) \
1188 class TestName##_##GroupName##_Test : public Test \
1189 { \
1190 public: \
1191 TestName##_##GroupName##_Test() noexcept : \
1192 Test( STRING_ME(TestName##_##GroupName##_Test)) \
1193 { \
1194 }; \
1195 TestName##_##GroupName##_Test & operator = ( const TestName##_##GroupName##_Test & ) = delete;\
1196 TestName##_##GroupName##_Test( const TestName##_##GroupName##_Test & ) = delete;\
1197 \
1198 void run(UnitData &_UnitData, UnitStats &_UnitStats) override;\
1199 void teardown() noexcept override;\
1200 } TestName##_##GroupName##_instance; \
1201 \
1202 void TestName##_##GroupName##_Test::run( UnitData &_UnitData, UnitStats &_UnitStats ) \
1203 { \
1204 if (!TestFlagEnable) \
1205 { \
1206 _UnitStats.testCount--; \
1207 _UnitStats.testPass--; \
1208 } \
1209 else
1210
1211
1212 #define TEST_TEARDOWN( TestName, GroupName ) \
1213 void TestName##_##GroupName##_Test::teardown() noexcept
1214
1215#endif UNIT_TEST_CPP_H
1216
1217// -----------------------------------------------------------------------
1218// Copyright 2019, Ed Keenan, all rights reserved.
1219//
1220// Performance timer
1221// Quick hardware timer
1222// Uses the hardware clock for timing
1223// Returns time as float (easier than Abstract Data Types for students)
1224// Not designed for timing event... but instead for measuring time
1225//
1226// Used to be stand alone files... now all one include
1227//
1228// -----------------------------------------------------------------------
1229
1230#ifndef PERFORMANCE_TIMER_H
1231#define PERFORMANCE_TIMER_H
1232
1233 class PerformanceTimer
1234 {
1235 public:
1236 // big six
1237 PerformanceTimer() noexcept
1238 :
1239 ticTime(),
1240 tocTime(),
1241 deltaTime(),
1242 SecondsPerCycle(0.0f),
1243 timeSeconds(0.0f)
1244 {
1245 this->privInitTimer();
1246 this->Reset();
1247 }
1248 PerformanceTimer(const PerformanceTimer &) = delete;
1249 PerformanceTimer(PerformanceTimer &&) = delete;
1250 PerformanceTimer & operator= (const PerformanceTimer &) = delete;
1251 PerformanceTimer & operator= (PerformanceTimer &&) = delete;
1252 ~PerformanceTimer() = default;
1253
1254 void Tic() noexcept
1255 {
1256 // Forces a Fence...
1257 atomic_thread_fence(std::memory_order_acq_rel);
1258
1259 this->ticTime = this->privGetTimer();
1260
1261 // Forces a Fence...
1262 atomic_thread_fence(std::memory_order_acq_rel);
1263 }
1264 void Toc() noexcept
1265 {
1266 // Forces a Fence...
1267 atomic_thread_fence(std::memory_order_acq_rel);
1268
1269 this->tocTime = this->privGetTimer();
1270 assert(this->tocTime.QuadPart >= this->ticTime.QuadPart);
1271 this->deltaTime.QuadPart = this->tocTime.QuadPart - this->ticTime.QuadPart;
1272
1273 // Forces a Fence...
1274 atomic_thread_fence(std::memory_order_acq_rel);
1275 }
1276 void Reset() noexcept
1277 {
1278 this->ticTime.QuadPart = 0;
1279 this->tocTime.QuadPart = 0;
1280 this->deltaTime.QuadPart = 0;
1281 }
1282 float TimeInSeconds() noexcept
1283 {
1284 float floatTime;
1285 floatTime = static_cast<float>(this->deltaTime.QuadPart);
1286 floatTime *= this->SecondsPerCycle;
1287 return floatTime;
1288 }
1289
1290 private:
1291
1292 void privInitTimer() noexcept
1293 {
1294 LARGE_INTEGER Frequency;
1295 QueryPerformanceFrequency(&Frequency);
1296 this->SecondsPerCycle = 1.0f / Frequency.QuadPart;
1297 }
1298 LARGE_INTEGER privGetTimer() noexcept
1299 {
1300 LARGE_INTEGER time;
1301 QueryPerformanceCounter(&time);
1302 return time;
1303 }
1304
1305 // ------------------------------------------
1306 // data
1307 // ------------------------------------------
1308
1309 LARGE_INTEGER ticTime;
1310 LARGE_INTEGER tocTime;
1311 LARGE_INTEGER deltaTime;
1312 float SecondsPerCycle;
1313 float timeSeconds;
1314 };
1315
1316#endif PERFORMANCE_TIMER_H
1317
1318// -----------------------------------------------------------------------
1319// Copyright 2019, Ed Keenan, all rights reserved.
1320//
1321// Output Debug print
1322// Same interface as printf(...) but outputs to the debug window
1323// Also protected with mutex for race conditions
1324//
1325// Used to be stand alone files... now all one include
1326//
1327// -----------------------------------------------------------------------
1328
1329#ifndef DEBUG_OUTPUT_H
1330#define DEBUG_OUTPUT_H
1331
1332 class Trace
1333 {
1334 private:
1335 static const unsigned int TraceBuffSize = 256;
1336
1337 public:
1338
1339 // Big six
1340 Trace() noexcept
1341 {
1342 memset(&privBuff[0], 0x0, TraceBuffSize);
1343 }
1344 Trace(const Trace &) = delete;
1345 Trace(Trace &&) = delete;
1346 Trace & operator = (const Trace &) = delete;
1347 Trace & operator = (Trace &&) = delete;
1348 ~Trace() = default;
1349
1350 // displays a printf to the output window
1351 static void out(const char * const fmt, ...)
1352 {
1353 Trace *pTrace = Trace::privGetInstance();
1354 assert(pTrace);
1355
1356 pTrace->mtx.lock();
1357
1358 va_list args;
1359
1360 #pragma warning( push )
1361 #pragma warning( disable : 26492 )
1362 #pragma warning( disable : 26481 )
1363 va_start(args, fmt);
1364 #pragma warning( pop )
1365
1366 vsprintf_s(&pTrace->privBuff[0], TraceBuffSize, fmt, args);
1367 OutputDebugString(&pTrace->privBuff[0]);
1368
1369 //va_end(args);
1370 args = static_cast<va_list> (nullptr);
1371
1372 pTrace->mtx.unlock();
1373 }
1374
1375 private:
1376 static Trace *privGetInstance() noexcept
1377 {
1378 static Trace helper;
1379 return &helper;
1380 }
1381 char privBuff[TraceBuffSize];
1382 std::mutex mtx;
1383 };
1384
1385#endif DEBUG_OUTPUT_H
1386
1387// -----------------------------------------------------------------------
1388// Copyright 2019, Ed Keenan, all rights reserved.
1389//
1390// File I/O for logging
1391// Need a clean an easy way to create and log to a file in ascii
1392// used in course for logging...
1393//
1394// Used to be stand alone files... now all one include
1395//
1396// -----------------------------------------------------------------------
1397
1398#ifndef FILE_IO_H
1399#define FILE_IO_H
1400
1401
1402 #ifdef _DEBUG
1403 #ifdef _M_X64
1404 const char* const pFileio_mode = "x64_Debug";
1405 #else
1406 const char* const pFileio_mode = "x86_Debug";
1407 #endif
1408 #else
1409 #ifdef _M_X64
1410 const char* const pFileio_mode = "x64_Release";
1411 #else
1412 const char* const pFileio_mode = "x86_Release";
1413 #endif
1414 #endif
1415
1416 class FileIO
1417 {
1418 public:
1419
1420 static void Open(const char * const pFirstName, const char * const pLastName) noexcept
1421 {
1422 assert(pFirstName);
1423 assert(pLastName);
1424 FileIO::privGetInstance()->privOpen(pFirstName, pLastName);
1425 }
1426 static void Close() noexcept
1427 {
1428 FileIO::privGetInstance()->privClose();
1429 }
1430 static FILE *GetHandle() noexcept
1431 {
1432 return FileIO::privGetInstance()->privGetHandle();
1433 }
1434
1435 private:
1436
1437 void privOpen(const char * const pFirstName, const char * const pLastName) noexcept
1438 {
1439 system("if not exist .\\..\\Logs mkdir .\\..\\Logs");
1440
1441 const char * const pFile_extension = ".txt";
1442 const char * const pFile_io_path = ".\\..\\Logs\\";
1443
1444 const int length = 256;
1445
1446 char pFileName[length] = { 0 };
1447 assert(pFileName);
1448
1449 errno_t fileError(0);
1450
1451 // wash the name to 0
1452 memset(&pFileName[0], 0, length);
1453
1454 // is there enough of space?
1455 assert( (strlen(pFile_io_path)
1456 + strlen(pFirstName)
1457 + strlen(pLastName)
1458 + strlen("-")
1459 + strlen(pFileio_mode)
1460 + strlen(pFile_extension)
1461 + strlen("/0") ) < length);
1462
1463 strcat_s(&pFileName[0], length, pFile_io_path);
1464 strcat_s(&pFileName[0], length, pFirstName);
1465 strcat_s(&pFileName[0], length, pLastName);
1466 strcat_s(&pFileName[0], length, "_");
1467 strcat_s(&pFileName[0], length, pFileio_mode);
1468 strcat_s(&pFileName[0], length, pFile_extension);
1469
1470
1471 fileError = fopen_s(&pFileHandle, &pFileName[0], "wt");
1472 assert(pFileHandle);
1473 if(pFileHandle != nullptr)
1474 {
1475 fprintf(this->pFileHandle, "-------------------------------------------------\n");
1476 fprintf(this->pFileHandle, "\n");
1477 fprintf(this->pFileHandle, "Log File \n");
1478 fprintf(this->pFileHandle, "\n");
1479 fprintf(this->pFileHandle, "Name: %s %s\n", pFirstName, pLastName);
1480 fprintf(this->pFileHandle, "Mode: %s\n", pFileio_mode);
1481 fprintf(this->pFileHandle, "\n");
1482 fprintf(this->pFileHandle, "-------------------------------------------------\n");
1483 fprintf(this->pFileHandle, "\n");
1484 }
1485 }
1486 FILE *privGetHandle() noexcept
1487 {
1488 assert(pFileHandle);
1489 return this->pFileHandle;
1490 }
1491 static FileIO *privGetInstance() noexcept
1492 {
1493 static FileIO instance;
1494 return &instance;
1495 }
1496 void privClose() noexcept
1497 {
1498 errno_t fileError(0);
1499 assert(pFileHandle);
1500
1501 fileError = fflush(this->pFileHandle);
1502 assert(!fileError);
1503
1504 fileError = fclose(this->pFileHandle);
1505 this->pFileHandle = nullptr;
1506 assert(!fileError);
1507 }
1508
1509 // big six
1510 constexpr FileIO() noexcept
1511 :pFileHandle(nullptr)
1512 {
1513
1514 };
1515 FileIO(const FileIO &) = delete;
1516 FileIO(FileIO &&) = delete;
1517 FileIO & operator=(const FileIO &) = delete;
1518 FileIO & operator=(FileIO &&) = delete;
1519 ~FileIO()
1520 {
1521 if (nullptr != this->pFileHandle)
1522 {
1523 this->privClose();
1524 }
1525 };
1526
1527 // ------------------------------------------
1528 // data
1529 // ------------------------------------------
1530
1531 FILE *pFileHandle;
1532 };
1533
1534#endif FILE_IO_H
1535
1536// -----------------------------------------------------------------------
1537// Copyright 2019, Ed Keenan, all rights reserved.
1538//
1539// Align16
1540// Needed a clean way to allocate aligned data for Matrix, Quat, and Vector
1541// Data is align by inheriting this class
1542//
1543//
1544// Used to be stand alone files... now all one include
1545//
1546// -----------------------------------------------------------------------
1547
1548
1549#ifndef ALIGN_16_H
1550#define ALIGN_16_H
1551
1552 #define ALIGN_UNUSED_VAR(x) (void(x))
1553
1554 #pragma push_macro("new")
1555 #undef new
1556
1558 {
1559 public:
1560
1561 // Placement new for align16
1562 void* operator new(size_t, void *p) noexcept
1563 {
1564 ALIGN_UNUSED_VAR(p);
1565 return p;
1566 }
1567
1568 void *operator new(size_t size) noexcept
1569 {
1570 void *p = _aligned_malloc(size, 16);
1571 return p;
1572 }
1573
1574 void operator delete(void *p)
1575 {
1576 _aligned_free(p);
1577 }
1578
1579 void *operator new[](size_t size) noexcept
1580 {
1581 void *p = _aligned_malloc(size, 16);
1582 return p;
1583 }
1584
1585 void operator delete[](void *p)
1586 {
1587 _aligned_free(p);
1588 }
1589
1590 void *operator new(size_t size,
1591 int _BlockUse,
1592 char const* _FileName,
1593 int _LineNumber) noexcept
1594 {
1595 ALIGN_UNUSED_VAR(_BlockUse);
1596 ALIGN_UNUSED_VAR(_FileName);
1597 ALIGN_UNUSED_VAR(_LineNumber);
1598
1599 void *p = _aligned_malloc_dbg(size, 16, _FileName, _LineNumber);
1600 return p;
1601 }
1602
1603 void operator delete(void *p,
1604 int _BlockUse,
1605 char const* _FileName,
1606 int _LineNumber)
1607 {
1608 ALIGN_UNUSED_VAR(_BlockUse);
1609 ALIGN_UNUSED_VAR(_FileName);
1610 ALIGN_UNUSED_VAR(_LineNumber);
1611 _aligned_free_dbg(p);
1612 }
1613
1614 void *operator new[](size_t size,
1615 int _BlockUse,
1616 char const* _FileName,
1617 int _LineNumber) noexcept
1618 {
1619 ALIGN_UNUSED_VAR(_BlockUse);
1620 ALIGN_UNUSED_VAR(_FileName);
1621 ALIGN_UNUSED_VAR(_LineNumber);
1622
1623 void *p = _aligned_malloc_dbg(size, 16, _FileName, _LineNumber);
1624 return p;
1625 }
1626
1627 void operator delete[](void *p,
1628 int _BlockUse,
1629 char const* _FileName,
1630 int _LineNumber)
1631 {
1632 ALIGN_UNUSED_VAR(_BlockUse);
1633 ALIGN_UNUSED_VAR(_FileName);
1634 ALIGN_UNUSED_VAR(_LineNumber);
1635 _aligned_free_dbg(p);
1636 }
1637
1638 };
1639
1640 #pragma pop_macro("new")
1641
1642#endif //ALIGN_16_H
1643
1644
1645#endif //FRAMEWORK_H
1646
1647// --- End of File ---------------
Definition Framework.h:1558
Definition Framework.h:254
Definition Framework.h:927
Definition Framework.h:805
Definition Framework.h:264
Definition Framework.h:840
Definition Framework.h:818