📄 tomslib.h
字号:
/* Copyright (C) Tom Forsyth, 2001.
* All rights reserved worldwide.
*
* This software is provided "as is" without express or implied
* warranties. You may freely copy and compile this source into
* applications you distribute provided that the copyright text
* below is included in the resulting source code, for example:
* "Portions Copyright (C) Tom Forsyth, 2001"
*/
// Some standard useful classes, templates, etc.
#ifndef TOMSLIB_INCLUDED
#define TOMSLIB_INCLUDED
#include <assert.h>
#include <math.h>
#include <memory.h>
#include <malloc.h>
#include <stdio.h>
#include <stdarg.h>
#include <windows.h>
#include <mmsystem.h>
#ifdef DEBUG
//#define ASSERT(exp) { assert(exp); __assume(exp); }
#define ASSERT(exp) { if (!(exp)){_asm { int 3 };} }
inline TRACE ( char *fmt, ... )
{
va_list vlist;
char pchTemp[1000];
va_start ( vlist, fmt );
vsprintf ( pchTemp, fmt, vlist );
OutputDebugString ( pchTemp );
va_end ( vlist );
}
#else //#ifdef DEBUG
#define ASSERT sizeof
#define TRACE sizeof
#endif //#else //#ifdef DEBUG
static void DumpFunction ( char *pchFormat, ... )
{
va_list va_ptr;
char pchTemp[256];
va_start ( va_ptr, pchFormat );
vsprintf ( pchTemp, pchFormat, va_ptr );
OutputDebugString ( pchTemp );
va_end ( va_ptr );
}
#if 1
#define DUMP(args) DumpFunction args
#else
#define DUMP(args) sizeof args
#endif
// Couldn't do it with classes and templates,
// have to do it the old fashioned way.
// Defines a link
#define DlinkDefine(classname,linkname)\
classname *linkname##pNextItem;\
classname *linkname##pPrevItem
// Defines the class methods for the link.
#define DlinkMethods(classname,linkname) \
void linkname##Init ( void ) { linkname##pNextItem = NULL; linkname##pPrevItem = NULL; } \
\
/* Find the next in the list. */ \
classname *linkname##Next ( void ) \
{ \
ASSERT ( ( linkname##pPrevItem == NULL ) || ( linkname##pPrevItem->linkname##pNextItem == this ) ); \
ASSERT ( ( linkname##pNextItem == NULL ) || ( linkname##pNextItem->linkname##pPrevItem == this ) ); \
return linkname##pNextItem; \
} \
\
/* Find the previous in the list. */ \
classname *linkname##Prev ( void ) \
{ \
ASSERT ( ( linkname##pPrevItem == NULL ) || ( linkname##pPrevItem->linkname##pNextItem == this ) ); \
ASSERT ( ( linkname##pNextItem == NULL ) || ( linkname##pNextItem->linkname##pPrevItem == this ) ); \
return linkname##pPrevItem; \
} \
\
/* Remove this item from the list. */ \
/* Returns the next item. */ \
classname *linkname##Del ( void ) \
{ \
classname *pNext = linkname##pNextItem; \
classname *pPrev = linkname##pPrevItem; \
ASSERT ( ( pPrev == NULL ) || ( pPrev->linkname##pNextItem == this ) ); \
ASSERT ( ( pNext == NULL ) || ( pNext->linkname##pPrevItem == this ) ); \
if ( pPrev != NULL ) \
{ \
pPrev->linkname##pNextItem = pNext; \
} \
if ( pNext != NULL ) \
{ \
pNext->linkname##pPrevItem = pPrev; \
} \
linkname##pNextItem = NULL; \
linkname##pPrevItem = NULL; \
return pNext; \
} \
\
/* Remove this item from the list. */ \
/* Assumes that this is the first item in the list for speed (asserted). */ \
/* Returns the next item. */ \
classname *linkname##DelScan ( void ) \
{ \
ASSERT ( linkname##pPrevItem == NULL ); \
classname *pNext = linkname##pNextItem; \
ASSERT ( ( pNext == NULL ) || ( pNext->linkname##pPrevItem == this ) ); \
if ( pNext != NULL ) \
{ \
pNext->linkname##pPrevItem = NULL; \
} \
linkname##pNextItem = NULL; \
linkname##pPrevItem = NULL; \
return pNext; \
} \
\
/* Deletes the item, given a pointer to the first item in the list. */ \
/* Modifies the point as necessary. */ \
/* Returns the next item. */ \
/* Use like pThing->DelFromFirst ( &pFirst ); */ \
classname *linkname##DelFromFirst ( classname **ppFirst ) \
{ \
ASSERT ( ppFirst != NULL ); \
ASSERT ( *ppFirst != NULL ); \
if ( *ppFirst == this ) \
{ \
ASSERT ( linkname##pPrevItem == NULL ); \
/* First in the list. */ \
*ppFirst = linkname##Del(); \
return *ppFirst; \
} \
else \
{ \
/* DLink lists already know their previous item. */ \
return ( linkname##Del() ); \
} \
} \
\
/* Add the item after the given item. */ \
/* Return the new next item. */ \
classname *linkname##AddAfter ( classname *pPrev ) \
{ \
ASSERT ( linkname##pNextItem == NULL ); \
ASSERT ( linkname##pPrevItem == NULL ); \
ASSERT ( pPrev != NULL ); \
linkname##pNextItem = pPrev->linkname##pNextItem; \
linkname##pPrevItem = pPrev; \
if ( linkname##pNextItem != NULL ) \
{ \
linkname##pNextItem->linkname##pPrevItem = this; \
} \
pPrev->linkname##pNextItem = this; \
return ( linkname##pNextItem ); \
} \
\
/* Add the item after the given item. */ \
/* Assumes this is the last item in the list for speed (asserted) */ \
void linkname##AddAfterEnd ( classname *pPrev ) \
{ \
ASSERT ( linkname##pNextItem == NULL ); \
ASSERT ( linkname##pPrevItem == NULL ); \
ASSERT ( pPrev != NULL ); \
ASSERT ( pPrev->linkname##pNextItem == NULL ); \
linkname##pNextItem = NULL; \
linkname##pPrevItem = pPrev; \
pPrev->linkname##pNextItem = this; \
} \
\
/* Add before given item. */ \
/* Returns the new previous item. */ \
classname *linkname##AddBefore ( classname *pNext ) \
{ \
ASSERT ( linkname##pNextItem == NULL ); \
ASSERT ( linkname##pPrevItem == NULL ); \
ASSERT ( pNext != NULL ); \
linkname##pNextItem = pNext; \
linkname##pPrevItem = pNext->linkname##pPrevItem; \
if ( linkname##pPrevItem != NULL ) \
{ \
linkname##pPrevItem->linkname##pNextItem = this; \
} \
pNext->linkname##pPrevItem = this; \
return ( linkname##pPrevItem ); \
} \
\
/* Add the item before the given item. */ \
/* Assumes this is the first item in the list for speed (asserted) */ \
void linkname##AddBeforeStart ( classname *pNext ) \
{ \
ASSERT ( linkname##pNextItem == NULL ); \
ASSERT ( linkname##pPrevItem == NULL ); \
ASSERT ( pNext != NULL ); \
ASSERT ( pNext->linkname##pPrevItem == NULL ); \
linkname##pPrevItem = NULL; \
linkname##pNextItem = pNext; \
pNext->linkname##pPrevItem = this; \
} \
\
/* Find the last item in the list. */ \
classname *linkname##FindLast ( void ) \
{ \
classname *pCurr = this; \
ASSERT ( pCurr != NULL ); \
while ( pCurr->linkname##pNextItem != NULL ) \
{ \
ASSERT ( ( pCurr->linkname##pPrevItem == NULL ) || ( pCurr->linkname##pPrevItem->linkname##pNextItem == pCurr ) ); \
ASSERT ( ( pCurr->linkname##pNextItem == NULL ) || ( pCurr->linkname##pNextItem->linkname##pPrevItem == pCurr ) ); \
pCurr = pCurr->linkname##pNextItem; \
} \
return pCurr; \
} \
\
/* Find the first item in the list. */ \
classname *linkname##FindFirst ( void ) \
{ \
classname *pCurr = this; \
ASSERT ( pCurr != NULL ); \
while ( pCurr->linkname##pPrevItem != NULL ) \
{ \
ASSERT ( ( pCurr->linkname##pPrevItem == NULL ) || ( pCurr->linkname##pPrevItem->linkname##pNextItem == pCurr ) ); \
ASSERT ( ( pCurr->linkname##pNextItem == NULL ) || ( pCurr->linkname##pNextItem->linkname##pPrevItem == pCurr ) ); \
pCurr = pCurr->linkname##pPrevItem; \
} \
return pCurr; \
} \
\
/* Consistency check - checks the current list is sound. */ \
void linkname##ConsistencyCheck ( void ) \
{ \
classname *pCurr = this; \
/* Scan backwards. */ \
ASSERT ( pCurr != NULL ); \
while ( pCurr->linkname##pPrevItem != NULL ) \
{ \
ASSERT ( ( pCurr->linkname##pPrevItem == NULL ) || ( pCurr->linkname##pPrevItem->linkname##pNextItem == pCurr ) ); \
ASSERT ( ( pCurr->linkname##pNextItem == NULL ) || ( pCurr->linkname##pNextItem->linkname##pPrevItem == pCurr ) ); \
pCurr = pCurr->linkname##pPrevItem; \
} \
ASSERT ( ( pCurr->linkname##pPrevItem == NULL ) || ( pCurr->linkname##pPrevItem->linkname##pNextItem == pCurr ) ); \
ASSERT ( ( pCurr->linkname##pNextItem == NULL ) || ( pCurr->linkname##pNextItem->linkname##pPrevItem == pCurr ) ); \
\
/* Scan forwards. */ \
pCurr = this; \
ASSERT ( pCurr != NULL ); \
while ( pCurr->linkname##pNextItem != NULL ) \
{ \
ASSERT ( ( pCurr->linkname##pPrevItem == NULL ) || ( pCurr->linkname##pPrevItem->linkname##pNextItem == pCurr ) ); \
ASSERT ( ( pCurr->linkname##pNextItem == NULL ) || ( pCurr->linkname##pNextItem->linkname##pPrevItem == pCurr ) ); \
pCurr = pCurr->linkname##pNextItem; \
} \
ASSERT ( ( pCurr->linkname##pPrevItem == NULL ) || ( pCurr->linkname##pPrevItem->linkname##pNextItem == pCurr ) ); \
ASSERT ( ( pCurr->linkname##pNextItem == NULL ) || ( pCurr->linkname##pNextItem->linkname##pPrevItem == pCurr ) ); \
} \
\
/* Adds the item to the end of this list */ \
void linkname##AddToEnd ( classname *pItem ) \
{ \
ASSERT ( pItem != NULL ); \
linkname##AddAfterEnd ( pItem->linkname##FindLast() ); \
} \
\
/* Adds the item the the start of this list */ \
void linkname##AddToStart ( classname *pItem ) \
{ \
ASSERT ( pItem != NULL ); \
linkname##AddBeforeStart ( pItem->linkname##FindFirst() ); \
} \
\
/* Check that all the pointer are NULL, ready to be deleted */ \
bool linkname##CheckNull ( void ) \
{ \
return ( ( linkname##pNextItem == NULL ) && ( linkname##pPrevItem == NULL ) ); \
} \
\
/* Calls delete() on all the objects in this list and deletes it */ \
void linkname##DelWholeList ( void ) \
{ \
classname *pCur = linkname##FindFirst(); \
while ( pCur != NULL ) \
{ \
classname *pNext = pCur->linkname##DelScan(); \
delete ( pCur ); \
pCur = pNext; \
} \
} \
static int CountBitsIn ( unsigned int dwInput )
{
int iCount = 0;
unsigned int dwTemp = dwInput;
while ( dwTemp != 0 )
{
dwTemp = ( dwTemp & ( dwTemp - 1 ) );
iCount++;
}
return ( iCount );
}
// Swap things.
template <class S> void Swap ( S &a, S &b )
{
S temp = a;
a = b;
b = temp;
}
// Count number of items in a static array, e.g. strings, etc.
// So for: DWORD dwArray[20], NumItemsIn ( dwArray ) = 20
template <class T> int NumItemsIn ( T &thing )
{
return ( sizeof(thing) / sizeof (*thing) );
}
// Safe version of strncpy - always puts a trailing 0 on the end.
template <class C> C *SafeStrncpy ( C *dest, const C *src, size_t number )
{
strncpy ( dest, src, number );
dest[number-1] = 0;
return ( dest );
}
// A moderately good "close enough" thing.
inline bool CloseEnough ( float f1, float f2, float epsilon = 0.0001f )
{
if ( fabsf ( f1 ) > fabsf ( f2 ) )
{
return ( fabsf ( f1 - f2 ) <= fabsf ( epsilon * f1 ) + epsilon );
}
else
{
return ( fabsf ( f1 - f2 ) <= fabsf ( epsilon * f2 ) + epsilon );
}
}
// "Values" to pass to templates.
// Thanks to Jan for this perversion!
class Yes
{
public:
enum { bVal = TRUE };
};
class No
{
public:
enum { bVal = FALSE };
};
// Slow - checks the heap every time.
#define CHECK_HEAP 0
// A binary heap. Actually stores pointers to type THING, not the THINGs themselves.
template <class THING, class SORT> class BinaryHeap
{
private:
struct Blob
{
THING *pThing;
SORT Sort;
};
Blob *pBlobArray;
int iCurrentSize;
int iAllocatedSize;
int iCurrentPos;
#ifdef DEBUG
// A flag that says using FindNext, RemoveNext and RemoveCurrent are OK to call.
bool bFindNextValid;
#endif
public:
BinaryHeap ( void )
{
pBlobArray = NULL;
iCurrentSize = 0;
iAllocatedSize = 0;
#ifdef DEBUG
bFindNextValid = FALSE;
#endif
iCurrentPos = 0;
}
~BinaryHeap ( void )
{
if ( pBlobArray != NULL )
{
delete[] pBlobArray;
pBlobArray = NULL;
}
iCurrentSize = 0;
iAllocatedSize = 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -