17#ifdef TOSHI_PROFILER_MEMORY
18# include "Profiler/tracy/Tracy.hpp"
28void* __CRTDECL
operator new(
TSIZE size )
30#ifdef TOSHI_PROFILER_MEMORY
31 return TMalloc( size,
TNULL, TMemory__FILE__, TMemory__LINE__ );
42void* __CRTDECL
operator new(
TSIZE size, ::std::nothrow_t
const& )
noexcept
44#ifdef TOSHI_PROFILER_MEMORY
45 return TMalloc( size,
TNULL, TMemory__FILE__, TMemory__LINE__ );
56void* __CRTDECL
operator new[](
TSIZE size )
58#ifdef TOSHI_PROFILER_MEMORY
59 return TMalloc( size,
TNULL, TMemory__FILE__, TMemory__LINE__ );
70void* __CRTDECL
operator new[](
TSIZE size, ::std::nothrow_t
const& )
noexcept
72#ifdef TOSHI_PROFILER_MEMORY
73 return TMalloc( size,
TNULL, TMemory__FILE__, TMemory__LINE__ );
83void __CRTDECL
operator delete(
void* ptr )
noexcept
92void __CRTDECL
operator delete(
void* ptr, ::std::nothrow_t
const& )
noexcept
101void __CRTDECL
operator delete[](
void* ptr )
noexcept
110void __CRTDECL
operator delete[](
void* ptr, ::std::nothrow_t
const& )
noexcept
120void __CRTDECL
operator delete[](
void* ptr,
TSIZE _Size )
noexcept
125#ifndef TMEMORY_USE_DLMALLOC
127# define MEM_TO_NODE( PTR ) ( ( (MemNode*)( ( (TUINTPTR)PTR ) + sizeof( void* ) ) ) - 1 )
143 m_TotalAllocatedSize = 0;
147 m_FreeBlocks.InsertTail( &m_aBlockSlots[ i ] );
164# define PP_CAT( A, B ) A##B
165# define PP_EXPAND( ... ) __VA_ARGS__
168# define PP_VA_ARG_SIZE( ... ) PP_EXPAND( PP_APPLY_ARG_N( ( PP_ZERO_ARGS_DETECT( __VA_ARGS__ ), PP_RSEQ_N ) ) )
170# define PP_ZERO_ARGS_DETECT( ... ) PP_EXPAND( PP_ZERO_ARGS_DETECT_PREFIX_##__VA_ARGS__##_ZERO_ARGS_DETECT_SUFFIX )
171# define PP_ZERO_ARGS_DETECT_PREFIX__ZERO_ARGS_DETECT_SUFFIX , , , , , , , , , , , 0
173# define PP_APPLY_ARG_N( ARGS ) PP_EXPAND( PP_ARG_N ARGS )
174# define PP_ARG_N( _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, N, ... ) N
175# define PP_RSEQ_N 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
177# define PP_OVERLOAD_SELECT( NAME, NUM ) PP_CAT( NAME##_, NUM )
178# define PP_MACRO_OVERLOAD( NAME, ... ) PP_OVERLOAD_SELECT( NAME, PP_VA_ARG_SIZE( __VA_ARGS__ ) )( __VA_ARGS__ )
180# define CALL_THIS_4( ADDR, TYPE, RET_TYPE, THIS ) ( ( RET_TYPE( __thiscall* )( TYPE pThis ) )( ADDR ) )( THIS )
181# define CALL_THIS_6( ADDR, TYPE, RET_TYPE, THIS, TYPE1, VALUE1 ) ( ( RET_TYPE( __thiscall* )( TYPE, TYPE1 ) )( ADDR ) )( THIS, VALUE1 )
182# define CALL_THIS_8( ADDR, TYPE, RET_TYPE, THIS, TYPE1, VALUE1, TYPE2, VALUE2 ) ( ( RET_TYPE( __thiscall* )( TYPE, TYPE1, TYPE2 ) )( ADDR ) )( THIS, VALUE1, VALUE2 )
183# define CALL_THIS_10( ADDR, TYPE, RET_TYPE, THIS, TYPE1, VALUE1, TYPE2, VALUE2, TYPE3, VALUE3 ) ( ( RET_TYPE( __thiscall* )( TYPE, TYPE1, TYPE2, TYPE3 ) )( ADDR ) )( THIS, VALUE1, VALUE2, VALUE3 )
184# define CALL_THIS_12( ADDR, TYPE, RET_TYPE, THIS, TYPE1, VALUE1, TYPE2, VALUE2, TYPE3, VALUE3, TYPE4, VALUE4 ) ( ( RET_TYPE( __thiscall* )( TYPE, TYPE1, TYPE2, TYPE3, TYPE4 ) )( ADDR ) )( THIS, VALUE1, VALUE2, VALUE3, VALUE4 )
185# define CALL_THIS_14( ADDR, TYPE, RET_TYPE, THIS, TYPE1, VALUE1, TYPE2, VALUE2, TYPE3, VALUE3, TYPE4, VALUE4, TYPE5, VALUE5 ) ( ( RET_TYPE( __thiscall* )( TYPE, TYPE1, TYPE2, TYPE3, TYPE4, TYPE5 ) )( ADDR ) )( THIS, VALUE1, VALUE2, VALUE3, VALUE4, VALUE5 )
186# define CALL_THIS( ... ) PP_MACRO_OVERLOAD( CALL_THIS, __VA_ARGS__ )
188# define CALL_2( ADDR, RET_TYPE ) ( ( RET_TYPE( __stdcall* )() )( ADDR ) )()
189# define CALL_4( ADDR, RET_TYPE, TYPE1, VALUE1 ) ( ( RET_TYPE( __stdcall* )( TYPE1 ) )( ADDR ) )( VALUE1 )
190# define CALL_6( ADDR, RET_TYPE, TYPE1, VALUE1, TYPE2, VALUE2 ) ( ( RET_TYPE( __stdcall* )( TYPE1, TYPE2 ) )( ADDR ) )( VALUE1, VALUE2 )
191# define CALL_8( ADDR, RET_TYPE, TYPE1, VALUE1, TYPE2, VALUE2, TYPE3, VALUE3 ) ( ( RET_TYPE( __stdcall* )( TYPE1, TYPE2, TYPE3 ) )( ADDR ) )( VALUE1, VALUE2, VALUE3 )
192# define CALL_10( ADDR, RET_TYPE, TYPE1, VALUE1, TYPE2, VALUE2, TYPE3, VALUE3, TYPE4, VALUE4 ) ( ( RET_TYPE( __stdcall* )( TYPE1, TYPE2, TYPE3, TYPE4 ) )( ADDR ) )( VALUE1, VALUE2, VALUE3, VALUE4 )
193# define CALL_12( ADDR, RET_TYPE, TYPE1, VALUE1, TYPE2, VALUE2, TYPE3, VALUE3, TYPE4, VALUE4, TYPE5, VALUE5 ) ( ( RET_TYPE( __stdcall* )( TYPE1, TYPE2, TYPE3, TYPE4, TYPE5 ) )( ADDR ) )( VALUE1, VALUE2, VALUE3, VALUE4, VALUE5 )
194# define CALL( ... ) PP_MACRO_OVERLOAD( CALL, __VA_ARGS__ )
219 volatile TSIZE uiSize = a_uiSize;
220 volatile TSIZE uiAlignment = a_uiAlignment;
226 if ( uiAlignment < 16 )
231 TDebug_FinalPrintf(
"MEMORY ERROR: CANT ALLOC Alignment(%d)<TMEMORY_ROUNDUP\n", uiAlignment );
239 pMemBlock = m_pGlobalBlock;
243 volatile TSIZE uiRequiredSize = uiAlignedSize +
sizeof(
MemNode );
247 volatile void* pAllocatedAddress;
248 volatile TUINTPTR uiDataRegionStart;
257 pMemNode = pMemBlock->
m_apHoles[ uiNodeId ];
259 while ( pMemNode !=
TNULL )
261 pAllocatedAddress =
TAlignPointerUp( pMemNode->GetDataRegionStart(), uiAlignment );
264 uiDataRegionSize = uiDataRegionEnd - uiDataRegionStart;
266 if ( uiDataRegionEnd > uiDataRegionStart && uiDataRegionSize >= uiAlignedSize )
270 pMemNode = pMemNode->pNextHole;
287# ifdef TOSHI_PROFILER_MEMORY
289 tracy::ScopedZone zone( TMemory__LINE__, TMemory__FILE__,
T2String8::Length( TMemory__FILE__ ),
"", 0, TMemory__FUNC__ ? TMemory__FUNC__ :
"", TMemory__FUNC__ ?
T2String8::Length( TMemory__FUNC__ ) : 0 );
298 else if ( pAllocNode != pMemNode )
307 if ( uiDataRegionSize > uiRequiredSize )
313 pPrev->pNextHole = pMemNode->pNextHole;
321 if ( pMemNode != pAllocNode )
323 TSIZE uiNodeSize = GetNodeSize( pMemNode );
325 *(
MemNode**)( (
TUINTPTR)pMemNode->GetDataRegionStart() + uiNodeSize ) = pAllocNode;
331 SetProcess( pMemBlock, pAllocNode, uiDataRegionSize );
332 SetHoleSize( pNewNode, (
TUINTPTR)pAllocNode + GetNodeSize( pAllocNode ) - uiDataRegionStart - uiAlignedSize );
334 pNewNode->
pOwner = pAllocNode;
347 pMemBlock->
m_apHoles[ uiNewHoleId ] = pNewNode;
352# ifdef TOSHI_PROFILER_MEMORY
353 TracyAlloc( (
void*)pAllocatedAddress, uiAlignedSize );
355 return (
void*)pAllocatedAddress;
363 pPrev->pNextHole = pMemNode->pNextHole;
371 if ( pMemNode != pAllocNode )
373 TSIZE uiNodeSize = GetNodeSize( pMemNode );
375 *(
MemNode*
volatile*)( (
TUINTPTR)pMemNode->GetDataRegionStart() + uiNodeSize ) = pAllocNode;
378 SetProcess( pMemBlock, pAllocNode, uiDataRegionSize );
380# ifdef TOSHI_PROFILER_MEMORY
381 TracyAlloc( (
void*)pAllocatedAddress, uiAlignedSize );
383 return (
void*)pAllocatedAddress;
411# ifdef TOSHI_PROFILER_MEMORY
412 TracyFree( a_pAllocated );
417 TSIZE uiAllocationSize = GetNodeSize( pAllocationNode );
418 MemBlock* pMemBlock = GetProcessMemBlock( pAllocationNode );
420 SetHoleSize( pAllocationNode, uiAllocationSize );
427 if ( pOwner && !IsProcess( pOwner ) )
429 pAllocationNode = pOwner;
430 TSIZE uiOwnerSize = GetNodeSize( pOwner );
433 pNextLyingNode->
pOwner = pOwner;
445 if ( !IsProcess( pNextLyingNode ) )
447 TSIZE uiNextNodeSize = GetNodeSize( pNextLyingNode );
450 pPrev->pNextHole = pNextLyingNode->
pNextHole;
463 *ppNextNode = pMemBlock->
m_apHoles[ uiId ];
466 ( *ppNextNode )->
pPrevHole = pAllocationNode;
468 pMemBlock->
m_apHoles[ uiId ] = pAllocationNode;
490 void* pMem =
Alloc( a_uiSize, 16, a_pOwnerBlock,
TNULL, -1 );
512 if ( a_pMem && a_uiSize != 0 && !m_FreeBlocks.IsEmpty() )
519 auto pSlot = m_FreeBlocks.RemoveHead();
520 m_UsedBlocks.InsertHead( pSlot );
522 pBlock->m_pSlot = pSlot;
523 pBlock->m_pSlot->m_pPtr = pBlock;
526 if ( uiBlockTotalSize != 0 )
528 constexpr TSIZE CHUNK_RESERVED_SIZE = (
sizeof(
MemBlock ) + (
sizeof(
MemNode ) -
sizeof(
void* ) ) );
530 pBlock->m_uiTotalSize1 = uiBlockTotalSize;
532 pBlock->m_pFirstHole = &pBlock->m_RootHole;
534 auto pHole = &pBlock->m_RootHole;
535 pHole->uiSize = uiBlockTotalSize - CHUNK_RESERVED_SIZE;
536 pHole->pNextHole =
TNULL;
537 pHole->pPrevHole =
TNULL;
538 pHole->pOwner =
TNULL;
541 pBlock->m_apHoles[ uiFreeListId ] = pHole;
544 pBlockFooter->m_pBlockOwner =
TNULL;
545 pBlockFooter->m_Unk4 = 0;
546 pBlockFooter->m_Unk1 = 0;
548 pBlockFooter->m_pBlockOwner = pBlock;
550 pBlock->m_pNextBlock = pBlock;
551 pBlock->m_uiTotalSize2 = uiBlockTotalSize;
574 FreeMemBlock( a_pMemBlock );
584 return m_pGlobalBlock;
598TBOOL TMemory::FreeMemBlock( MemBlock* a_pMemBlock )
602 SetMemBlockUnused( a_pMemBlock );
603 a_pMemBlock->m_pSlot->Remove();
604 m_FreeBlocks.InsertHead( a_pMemBlock->m_pSlot );
618void TMemory::SetMemBlockUnused( MemBlock* a_pMemBlock )
620 a_pMemBlock->m_pSlot->Remove();
621 m_FreeBlocks.InsertHead( a_pMemBlock->m_pSlot );
637Toshi::TMemory::MemNode* TMemory::GetMemNodeFromAddress(
void* a_pMem )
658int TMemory::TestMemIntegrity( MemBlock* a_pMemBlock )
674int TMemory::DebugTestMemoryBlock( MemBlock* a_pMemBlock )
713 tmemory->m_pMemory =
TNULL;
714 tmemory->m_pGlobalBlock =
TNULL;
715 tmemory->m_uiGlobalFlags = 0;
716 tmemory->m_Unknown2 = 0;
719 new ( ms_pGlobalMutex )
TMutex();
721 tmemory->m_ReservedSize = a_uiReservedSize;
722 tmemory->m_TotalAllocatedSize = ( a_uiHeapSize == 0 ) ? 128 * 1024 * 1024 : a_uiHeapSize;
723 tmemory->m_MainBlockSize = tmemory->m_TotalAllocatedSize - a_uiReservedSize;
724 tmemory->m_pMemory = malloc( tmemory->m_TotalAllocatedSize );
725 tmemory->m_pGlobalBlock = tmemory->CreateMemBlockInPlace(
727 tmemory->m_TotalAllocatedSize,
746 auto pMainBlockMemory =
g_pMemory->m_pMemory;
753 free( pMainBlockMemory );
770 TUINT uiExponentSign = ( *(
TINT*)&fSize ) >> 23;
771 TUINT uiResult = uiExponentSign - 127;
774 uiResult = uiExponentSign - 126;
776 uiResult = uiResult >> 1;
779 uiResult = uiResult - 1;
795 MemBlock* pOldMemBlock = m_pGlobalBlock;
796 m_pGlobalBlock = a_pMemBlock;
813 for (
auto it = m_UsedBlocks.Tail(); it != m_UsedBlocks.End(); --it )
831 DebugPrintHALMemInfo(
"\t%%Logical Used : %f\n", ( fLogicTotalUsed / fLogicTotalSize ) * 100.0 );
848 va_start( args, a_szFormat );
899 TSIZE uiHoleSize = pHole->uiSize;
906 if ( ( pHole->uiSize & 1 ) == 0 )
937 auto pOldHole = pHole;
939 uiHoleSize = pHole->uiSize;
980 auto pMem =
Toshi::g_pMemory->Alloc( a_uiSize, 16, a_pMemBlock, a_szFileName, a_iLineNum );
984 Toshi::TMemory::DebugPrintHALMemInfo(
"Out of Toshi Memory on block [%s]\n", a_pMemBlock->m_szName );
994 auto pMem =
Toshi::g_pMemory->Alloc( a_uiSize, 16, pMemBlock, a_szFileName, a_iLineNum );
998 Toshi::TMemory::DebugPrintHALMemInfo(
"Out of Toshi Memory on block [%s]\n", pMemBlock->m_szName );
1013 Toshi::TMemory::DebugPrintHALMemInfo(
"Out of Toshi Memory on block [%s]\n", pMemBlock->m_szName );
1031 Toshi::TMemory::DebugPrintHALMemInfo(
"Out of Toshi Memory on block [%s]\n", a_pMemBlock->m_szName );
1046 Toshi::TMemory::DebugPrintHALMemInfo(
"Out of Toshi Memory on block [%s]\n", pMemBlock->m_szName );
1067 m_pMemModule =
TNULL;
1081 TMemoryDL* pMemModule = (TMemoryDL*)GlobalAlloc( GMEM_ZEROINIT,
sizeof( TMemoryDL ) );
1084 if ( a_uiHeapSize == 0 )
1085 a_uiHeapSize = 128 * 1024 * 1024;
1087 new ( pMemModule ) TMemoryDL( a_eFlags, a_uiHeapSize + a_uiReservedSize );
1089 g_pMemoryDL = pMemModule;
1092 TBOOL bInitialised = pMemModule->Init() == TMemoryDL::Error_Ok;
1094 g_pMemory->m_pGlobalBlock = g_pMemoryDL->GetHeap();
1096 return bInitialised;
1113 if ( !a_pOwnerBlock )
1114 a_pOwnerBlock = m_pMemModule->GetHeap();
1116 return g_pMemoryDL->dlheapcreatesubheap( a_pOwnerBlock, a_uiSize, TMemoryHeapFlags_UseMutex, a_szName );
1123 return g_pMemoryDL->dlheapcreateinplace( a_pMem, a_uiSize, TMemoryHeapFlags_UseMutex, a_szName );
1128 g_pMemoryDL->dlheapdestroy( a_pMemBlock );
1133 return g_pMemoryDL->GetHeap();
1138 MemBlock* pOldHeap = g_pMemoryDL->GetHeap();
1139 m_pGlobalBlock = a_pMemBlock;
1140 g_pMemoryDL->SetHeap( a_pMemBlock );
1156void*
TMalloc(
TUINT a_uiSize, Toshi::TMemory::MemBlock* a_pMemBlock,
const TCHAR* a_szFileName,
TINT a_iLineNum )
1160 a_pMemBlock = Toshi::g_pMemoryDL->GetHeap();
1164 return a_pMemBlock->Malloc( a_uiSize );
1166 return Toshi::g_pMemoryDL->GetContext().Malloc( a_uiSize );
1171 return Toshi::g_pMemoryDL->GetContext().Malloc( a_uiSize );
1176 return Toshi::g_pMemoryDL->GetContext().Malloc( a_uiSize );
1179void*
TMemalign(
TUINT a_uiAlignment,
TUINT a_uiSize, Toshi::TMemory::MemBlock* a_pMemBlock )
1182 a_pMemBlock = Toshi::g_pMemoryDL->GetHeap();
1185 return a_pMemBlock->Memalign( a_uiAlignment, a_uiSize );
1187 return Toshi::g_pMemoryDL->GetContext().Memalign( a_uiAlignment, a_uiSize );
1192 return Toshi::g_pMemoryDL->GetContext().Memalign( a_uiAlignment, a_uiSize );
1195void TFree(
void* a_pMem )
1197 Toshi::g_pMemoryDL->GetContext().Free( a_pMem );
void * TMalloc(TSIZE a_uiSize, Toshi::TMemory::MemBlock *a_pMemBlock, const TCHAR *a_szFileName, TINT a_iLineNum)
Allocates memory from a specific memory block.
void TFree(void *a_pMem)
Frees previously allocated memory.
Core memory management system for the Toshi engine.
#define TMEMORY_NUM_FREELISTS
Number of free list buckets for different sizes.
#define TMEMORY_ROUNDUP
Minimum alignment for memory blocks.
void * TMemalign(TSIZE a_uiSize, TSIZE a_uiAlignment)
Allocates aligned memory.
TOSHI_NAMESPACE_START class TMemory * g_pMemory
#define TMEMORY_NUM_BLOCK_SLOTS
Maximum number of memory block slots.
TOSHI_NAMESPACE_END void * TMalloc(TSIZE a_uiSize)
Allocates memory with default alignment.
#define TMEMORY_FLAGS_HOLE_PROCESS
Flag indicating a memory block is in use.
#define TMEMORY_ALLOC_RESERVED_SIZE
Reserved space in allocations.
void TFree(void *a_pMem)
Frees previously allocated memory.
#define TMEMORY_FLAGS_MASK
Mask for memory block flags.
void TDebug_FinalPrintf(const TCHAR *a_szFormat,...)
void TDebug_FinalVPrintf(const TCHAR *a_szFormat, va_list a_Args)
#define TMUTEX_LOCK_SCOPE(mutex)
#define TSTATICCAST(POINTERTYPE, VALUE)
#define HASANYFLAG(STATE, FLAG)
#define TREINTERPRETCAST(TYPE, VALUE)
#define TOSHI_NAMESPACE_START
#define TOSHI_NAMESPACE_END
TFORCEINLINE constexpr T * TAlignPointerUp(T *a_pMem, TSIZE a_uiAlignment=sizeof(T *))
TFORCEINLINE constexpr T TAlignNumUp(T a_iValue, TSIZE a_uiAlignment=4)
TFORCEINLINE constexpr T TAlignNumDown(T a_iValue, TSIZE a_uiAlignment=4)
TFORCEINLINE TBOOL TIsPointerAligned(const void *a_pPointer, TSIZE a_uiAlignment=sizeof(void *))
TFORCEINLINE TFLOAT Abs(TFLOAT fVal)
Core memory management class that handles all memory allocations and deallocations.
static TBOOL Initialise(TSIZE a_uiHeapSize, TSIZE a_uiReservedSize, TUINT a_uiUnused=0)
Initializes the memory system.
TBOOL Free(const void *a_pMem)
Frees previously allocated memory.
static TUINT MapSizeToFreeList(TSIZE a_uiSize)
static void GetMemInfo(MemInfo &a_rMemInfo, MemBlock *a_pMemBlock)
static void Deinitialise()
Deinitializes the memory system.
MemBlock * GetGlobalBlock() const
Gets the global memory block.
MemBlock * CreateMemBlockInPlace(void *a_pMem, TSIZE a_uiSize, const TCHAR *a_szName)
Creates a memory block at a specific location.
static void GetHALMemInfo(HALMemInfo &a_rHALMemInfo)
void DestroyMemBlock(MemBlock *a_pMemBlock)
Destroys a memory block.
static void DebugPrintHALMemInfo(const TCHAR *a_szFormat,...)
Debug print of HAL memory info.
void * Alloc(TSIZE a_uiSize, TSIZE a_uiAlignment, MemBlock *a_pMemBlock, const TCHAR *a_szFileName, TINT a_iLineNum)
Allocates memory with specified size and alignment.
TMemory::MemBlock * SetGlobalBlock(MemBlock *a_pMemBlock)
Sets the global memory block.
MemBlock * CreateMemBlock(TSIZE a_uiSize, const TCHAR *a_szName, MemBlock *a_pOwnerBlock, TINT a_iUnused)
Creates a new memory block.
TMemory()
Constructor for TMemory class Initializes the memory management system.
~TMemory()
Destructor for TMemory class Cleans up the memory management system.
Represents a node in the memory allocation system.
MemNode * pOwner
Owner node if this is a sub-allocation.
MemNode * pNextHole
Next free hole in the list.
MemNode * pPrevHole
Previous free hole in the list.
void * GetDataRegionEnd() const
Gets the end address of the data region for this node.
Represents a contiguous block of memory that can be allocated from.
MemNode * m_apHoles[9]
Array of free lists by size.
MemNode * m_pFirstHole
First free hole in the block.
TCHAR m_szName[52]
Name of the memory block.
TSIZE m_uiTotalSize1
Total size of the block.
Footer structure at the end of each memory block for validation.
Structure containing memory usage statistics.
TSIZE m_uiTotalFree
Total free memory.
TSIZE m_uiSmallestProcess
Size of smallest allocation.
TINT m_iNumProcesses
Number of allocated regions.
TSIZE m_uiUnk4
Unknown field 4.
TSIZE m_uiLogicTotalSize
Logical total size.
TSIZE m_uiUnk3
Unknown field 3.
TSIZE m_uiLogicTotalUsed
Logical total used memory.
TSIZE m_uiSmallestHole
Size of smallest free hole.
TSIZE m_uiLargestProcess
Size of largest allocation.
TSIZE m_uiLargestHole
Size of largest free hole.
TSIZE m_uiLogicTotalFree
Logical total free memory.
TSIZE m_uiTotalSize
Total size of memory block.
TINT m_iNumHoles
Number of free holes.
TSIZE m_uiTotalUsed
Total used memory.
Hardware abstraction layer memory information.
HALMemInfo()
Constructor for HALMemInfo Initializes all fields to zero.
static TSIZE Length(const TCHAR *str)
static TCHAR * String8Copy(TCHAR *dst, const TCHAR *src, TSIZE size=-1)
static void MemClear(void *ptr, TSIZE size)