/*++

Copyright (c) 1998  Microsoft Corporation

Module Name:

    svsutil.hxx

Abstract:

    Miscellaneous useful utilities header

Author:

    Sergey Solyanik (SergeyS)

--*/
#if ! defined (__svsutil_HXX__)
#define __svsutil_HXX__     1

#include <tchar.h>

#if ! defined (UNDER_CE)
#include <wchar.h>
#include <stddef.h>
#endif

#if ! defined (TRUE)
#define TRUE (1==1)
#endif

#if ! defined (FALSE)
#define FALSE (1==2)
#endif

#if defined (_DEBUG) || defined (DEBUG)
#define SVSUTIL_DEBUG_ANY       1
#define SVSUTIL_DEBUG_TREE      1
#define SVSUTIL_DEBUG_QUEUE     1
#define SVSUTIL_DEBUG_STACK     1
#define SVSUTIL_DEBUG_HEAP      1
#define SVSUTIL_DEBUG_ARRAYS    1
#define SVSUTIL_DEBUG_MT        1
#define SVSUTIL_DEBUG_THREADS   1
#endif

#if defined (SVSUTIL_DEBUG_ANY)
#define SVSUTIL_ASSERT(c) ((c)? TRUE : (svsutil_AssertBroken (TEXT(__FILE__), __LINE__), TRUE))
#else
#define SVSUTIL_ASSERT(c)
#endif

#define SVSUTIL_MAX_ALIGNMENT   8

#define SVSUTIL_COLOR_BLACK     0
#define SVSUTIL_COLOR_RED       1

#define SVSUTIL_TREE_INITIAL    20
#define SVSUTIL_QUEUE_INITIAL   20
#define SVSUTIL_STACK_INITIAL   20

#define SVSUTIL_ATIMER_INCR     10

#if defined (SVSUTIL_DEBUG_ARRAYS)
#define SVSUTIL_TIER_COLLECTION_BIT     2
#define SVSUTIL_TIER_ELEMENT_BIT        3
#else
#define SVSUTIL_TIER_COLLECTION_BIT     6
#define SVSUTIL_TIER_ELEMENT_BIT        5
#endif
#define SVSUTIL_TIER_COLLECTION_SIZE    (1 << SVSUTIL_TIER_COLLECTION_BIT)
#define SVSUTIL_TIER_ELEMENT_SIZE       (1 << SVSUTIL_TIER_ELEMENT_BIT)
#define SVSUTIL_TIER_COLLECTION_MASK    ((~((-1) << SVSUTIL_TIER_COLLECTION_BIT)) << SVSUTIL_TIER_ELEMENT_BIT)
#define SVSUTIL_TIER_ELEMENT_MASK       (~((-1) << SVSUTIL_TIER_ELEMENT_BIT))
#define SVSUTIL_TIER_MASK               (SVSUTIL_TIER_COLLECTION_MASK | SVSUTIL_TIER_ELEMENT_MASK)
#define SVSUTIL_TIER_BIT                (SVSUTIL_TIER_COLLECTION_BIT + SVSUTIL_TIER_ELEMENT_BIT)

#define SVSUTIL_ARRLEN(array)           (sizeof(array)/sizeof(array[0]))
#define SVSUTIL_CONSTSTRLEN(string)     (SVSUTIL_ARRLEN((string)) - 1)      // Do not count trailing '\0'

#define SVSUTIL_HANDLE_INVALID  0
//
//  General typedefs
//
struct FixedMemDescr;
struct HashDatabase;
struct SVSTimer;
struct SVSAttrTimer;

#define MAXSKEY         ((SVSCKey)-1)
#define SORTINV(kKey)   (MAXSKEY - kKey)

typedef unsigned long SVSCKey;          // Comparison key - this HAS to be unsigned!
typedef unsigned long SVSHKey;          // Hash key
typedef unsigned long SVSHandle;        // Handle

typedef void *(*FuncAlloc)(int iSize, void *pvPrivateData);
typedef void (*FuncFree)(void *pvPtr, void *pvPrivateData);

typedef int (*FuncDebugOut)(void *pvPtr, TCHAR *lpszFormat, ...);

#if defined (__cplusplus)
extern "C" {
#endif

//
//  Externs
//
extern FuncAlloc    g_funcAlloc;
extern FuncFree     g_funcFree;
extern FuncDebugOut g_funcDebugOut;

extern void     *g_pvAllocData;
extern void     *g_pvFreeData;
extern void     *g_pvDebugData;

//
//  Prototypes and classes
//
void svsutil_Initialize (void);

void *svsutil_Alloc (int iSize, void *pvData);
void svsutil_Free (void *pvPtr, void *pvData);
unsigned int svsutil_TotalAlloc (void);
int svsutil_AssertBroken (TCHAR *lpszFile, int iLine);

void svsutil_SetAlloc (FuncAlloc a_funcAlloc, FuncFree a_funcFree);
void svsutil_SetAllocData (void *a_pvAllocData, void *a_pvFreeData);
void svsutil_SetDebugOut (FuncDebugOut a_funcDebugOut, void *a_pvDebugData);

wchar_t *svsutil_wcsdup (wchar_t *);
char    *svsutil_strdup (char *);

#if defined (UNICODE)
#define svsutil_tcsdup  svsutil_wcsdup
#else
#define svsutil_tcsdup  svsutil_strdup
#endif

struct FixedMemDescr *svsutil_AllocFixedMemDescr (unsigned int a_uiBlockSize, unsigned int a_uiBlockIncr);
void *svsutil_GetFixed (struct FixedMemDescr *a_pfmd);
void svsutil_FreeFixed (void *pvData, struct FixedMemDescr *a_pfmd);
void svsutil_ReleaseFixedEmpty (struct FixedMemDescr *a_pfmd);
void svsutil_ReleaseFixedNonEmpty (struct FixedMemDescr *a_pfmd);
void svsutil_CompactFixed (struct FixedMemDescr *a_pfmd);
int svsutil_IsFixedEmpty (struct FixedMemDescr *a_pfmd);
int svsutil_FixedBlockSize (struct FixedMemDescr *a_pfmd);
#if defined (_WINDOWS_) || defined (_WINDOWS_CE_)
struct FixedMemDescr *svsutil_AllocFixedMemDescrSynch (unsigned int a_uiBlockSize, unsigned int a_uiBlockIncr, CRITICAL_SECTION *a_pcs);
#endif

struct HashDatabase *svsutil_GetStringHash (int iBuckets, int iSens);
TCHAR *svsutil_StringHashAlloc(struct HashDatabase *pdb, TCHAR *lpszString);
TCHAR *svsutil_StringHashCheck (struct HashDatabase *pdb, TCHAR *lpszString);
int svsutil_StringHashFree (struct HashDatabase *pdb, TCHAR *lpszString);
int svsutil_StringHashRef (struct HashDatabase *pdb, TCHAR *lpszString);
void svsutil_DestroyStringHash (struct HashDatabase *pdb);

#if defined (SVSUTIL_DEBUG_HEAP)
#define svsutil_ReleaseFixed svsutil_ReleaseFixedEmpty
#else
#define svsutil_ReleaseFixed svsutil_ReleaseFixedNonEmpty
#endif

void svsutil_GetAbsTime (unsigned int *ps, unsigned int *pms);
struct SVSAttrTimer *svsutil_AllocAttrTimer (void);
int  svsutil_SetAttrTimer   (struct SVSAttrTimer *pTimer, SVSHandle hEvent, unsigned int uiAbsTimeMillis);
int  svsutil_ClearAttrTimer (struct SVSAttrTimer *pTimer, SVSHandle hEvent);
void svsutil_FreeAttrTimer  (struct SVSAttrTimer *pTimer);
void svsutil_WalkAttrTimer (struct SVSAttrTimer *pTimer, void (*pfunc)(unsigned int uiWhen, SVSHandle hEvent, void *pvArg), void *pvArg);

#if defined (__cplusplus)
};
#endif

#if defined (__cplusplus)

#pragma warning(disable:4505)

#if defined (_WINDOWS_) || defined (_WINDOWS_CE_) || defined (UNDER_CE)
class SVSLocalCriticalSection {
    CRITICAL_SECTION *m_pcs;

public:
    SVSLocalCriticalSection (CRITICAL_SECTION *pcs) {
        m_pcs = pcs;
        EnterCriticalSection (pcs);
    }

    ~SVSLocalCriticalSection (void) {
        LeaveCriticalSection (m_pcs);
    }
};

class SVSLocalCriticalSectionX {
    CRITICAL_SECTION *m_pcs;

public:
    SVSLocalCriticalSectionX (CRITICAL_SECTION *pcs) {
        m_pcs = pcs;
        if (m_pcs)
            EnterCriticalSection (m_pcs);
    }

    ~SVSLocalCriticalSectionX (void) {
        if (m_pcs)
            LeaveCriticalSection (m_pcs);
    }
};

class SVSSynch {
protected:
    CRITICAL_SECTION    cs;

#if defined (SVSUTIL_DEBUG_MT)
    int                 iRef;
    DWORD               dwLockingThreadId;
#endif

protected:
    SVSSynch (void) {
        InitializeCriticalSection (&cs);

#if defined (SVSUTIL_DEBUG_MT)
        iRef              = 0;
        dwLockingThreadId = 0;
#endif
    }
    ~SVSSynch (void) {
#if defined (SVSUTIL_DEBUG_MT)
        SVSUTIL_ASSERT ((iRef == 0) && (dwLockingThreadId == 0));
#endif

        DeleteCriticalSection (&cs);
    }

public:
    void Lock (void) {
        EnterCriticalSection (&cs);

#if defined (SVSUTIL_DEBUG_MT)
        DWORD dwCurrentThreadId = GetCurrentThreadId();
        SVSUTIL_ASSERT (((iRef == 0) && (dwLockingThreadId == 0)) || ((iRef > 0) && (dwLockingThreadId == dwCurrentThreadId)));
        dwLockingThreadId = dwCurrentThreadId;
        iRef++;
#endif
    }

    void Unlock (void) {
#if defined (SVSUTIL_DEBUG_MT)
        DWORD dwCurrentThreadId = GetCurrentThreadId ();
        SVSUTIL_ASSERT ((iRef > 0) && (dwLockingThreadId == dwCurrentThreadId));
        if (--iRef == 0)
            dwLockingThreadId = 0;
#endif

        LeaveCriticalSection (&cs);
    }

    int IsLocked (void) {
#if defined (SVSUTIL_DEBUG_MT)
        DWORD dwCurrentThreadId = GetCurrentThreadId();
        return (iRef > 0) && (dwLockingThreadId == dwCurrentThreadId);
#else
        return TRUE;
#endif
    }
};

#endif

class SVSAllocClass {
public:
    void *operator new (size_t iSize) {
        void *pRes = g_funcAlloc(iSize, g_pvAllocData);
        SVSUTIL_ASSERT (pRes);
        return pRes;
    }

    void operator delete(void *ptr) {
        g_funcFree (ptr, g_pvFreeData);
    }
};

class SVSRefObj {
protected:
    int iRef;

public:
    void AddRef (void) {
#if defined (_WINDOWS_) || defined (_WINDOWS_CE_)
        InterlockedIncrement ((long *)&iRef);
#else
        ++iRef;
#endif
    }

    void DelRef (void) {
        SVSUTIL_ASSERT (iRef > 0);
#if defined (_WINDOWS_) || defined (_WINDOWS_CE_)
        InterlockedDecrement ((long *)&iRef);
#else
        --iRef;
#endif
    }

    int GetRefCount (void) {
        return iRef;
    }

    SVSRefObj (void) {
        iRef = 1;
    }
};

class SVSSignallingRefObj : public SVSRefObj {
protected:
    void (*pfSignal)(void *);
    void *pvData;

public:
    void DelRef (void) {
        SVSUTIL_ASSERT (iRef > 0);
#if defined (_WINDOWS_) || defined (_WINDOWS_CE_)
        InterlockedDecrement ((long *)&iRef);
#else
        --iRef;
#endif

        if ((iRef == 0) && pfSignal)
            pfSignal (pvData);
    }

    SVSSignallingRefObj (void) {
        pfSignal = NULL;
        pvData   = NULL;
    }

    void SetSignal (void (*a_pfSignal)(void *), void *a_pvData) {
        SVSUTIL_ASSERT (pfSignal == NULL);
        SVSUTIL_ASSERT (pvData   == NULL);

        pfSignal = a_pfSignal;
        pvData   = a_pvData;
    }
};
//
//  Enumerable class
//
class SVSEnumClass {
public:
    virtual SVSHandle EnumStart     (void)            = 0;
    virtual SVSHandle EnumNext      (SVSHandle hEnum) = 0;
    virtual void      *EnumGetData  (SVSHandle hEnum) = 0;
    virtual SVSCKey   EnumGetKey   (SVSHandle hEnum) = 0;
};

//
//  Queue class
//

class SVSLinkedSegment {
protected:
    class SVSLinkedSegment *plsNext;
    class SVSLinkedSegment *plsPrev;
    void *pvArray[1];

    friend class SVSQueue;
    friend class SVSStack;
};

class SVSQueue : public SVSAllocClass {
protected:
    SVSLinkedSegment    *plsHead;
    SVSLinkedSegment    *plsTail;

    unsigned int    iSegSize;
    unsigned int    iBlockSize;
    unsigned int    iHeadNdx;
    unsigned int    iTailNdx;

#if defined (SVSUTIL_DEBUG_QUEUE)
    void CoherencyCheck (void) {
        SVSUTIL_ASSERT(iSegSize > 0);
        SVSUTIL_ASSERT(iBlockSize > 0);
        SVSUTIL_ASSERT(iHeadNdx < iSegSize);
        SVSUTIL_ASSERT(iTailNdx < iSegSize);
        SVSUTIL_ASSERT (plsHead->plsNext->plsPrev == plsHead);
        SVSUTIL_ASSERT (plsTail->plsNext->plsPrev == plsTail);
        SVSUTIL_ASSERT (plsHead->plsPrev->plsNext == plsHead);
        SVSUTIL_ASSERT (plsTail->plsPrev->plsNext == plsTail);
    }
#endif

public:
    SVSQueue (unsigned int a_iSegSize = SVSUTIL_QUEUE_INITIAL) {
        SVSUTIL_ASSERT (a_iSegSize > 0);

        iSegSize = a_iSegSize;
        iHeadNdx = 0;
        iTailNdx = 0;

        iBlockSize = offsetof (SVSLinkedSegment, pvArray) + a_iSegSize * sizeof(void *);
        plsHead = plsTail = (SVSLinkedSegment *)g_funcAlloc(iBlockSize, g_pvAllocData);

        SVSUTIL_ASSERT (plsHead);

        plsHead->plsPrev = plsHead->plsNext = plsHead;

#if defined (SVSUTIL_DEBUG_QUEUE)
        CoherencyCheck ();
#endif
    }

    ~SVSQueue (void) {
        SVSLinkedSegment *pls = plsHead->plsNext;
        while (pls != plsHead) {
            SVSLinkedSegment *plsNext = pls->plsNext;
            g_funcFree (pls, g_pvFreeData);
            pls = plsNext;
        }

        g_funcFree (plsHead, g_pvFreeData);
    }

    int IsEmpty (void) {
#if defined (SVSUTIL_DEBUG_QUEUE)
        CoherencyCheck ();
#endif
        return (plsHead == plsTail) && (iHeadNdx == iTailNdx);
    }

    int Put (void *pvData) {
#if defined (SVSUTIL_DEBUG_QUEUE)
        CoherencyCheck ();
#endif
        plsHead->pvArray[iHeadNdx++] = pvData;

        if (iHeadNdx < iSegSize)
            return TRUE;

        iHeadNdx = 0;

        if (plsHead->plsNext != plsTail) {
            plsHead = plsHead->plsNext;
            return TRUE;
        }

        SVSLinkedSegment *pls = (SVSLinkedSegment *)g_funcAlloc(iBlockSize, g_pvAllocData);

        if (! pls) {
            SVSUTIL_ASSERT (0);

            iHeadNdx = iSegSize - 1;
            return FALSE;
        }

        pls->plsPrev = plsHead;
        pls->plsNext = plsTail;
        plsHead->plsNext = pls;
        plsTail->plsPrev = pls;

        plsHead = pls;
        return TRUE;
    }

    void *Peek (void) {
        if (IsEmpty()) {
            SVSUTIL_ASSERT(0);
            return NULL;
        }

        return plsTail->pvArray[iTailNdx];
    }

    void *Get (void) {
        if (IsEmpty()) {
            SVSUTIL_ASSERT(0);
            return NULL;
        }

        void *pvData = plsTail->pvArray[iTailNdx++];

        if (iTailNdx < iSegSize)
            return pvData;

        iTailNdx = 0;
        plsTail = plsTail->plsNext;

        return pvData;
    }

    void Compact (void) {
#if defined (SVSUTIL_DEBUG_QUEUE)
        CoherencyCheck ();
#endif
        SVSLinkedSegment *pls = plsHead->plsNext;

        while (pls != plsTail) {
            SVSLinkedSegment *plsNext = pls->plsNext;

            g_funcFree (pls, g_pvFreeData);

            pls = plsNext;
        }

        plsHead->plsNext = plsTail;
        plsTail->plsPrev = plsHead;

#if defined (SVSUTIL_DEBUG_QUEUE)
        CoherencyCheck ();
#endif
    }
};


class SVSStack : public SVSAllocClass {
protected:
    SVSLinkedSegment    *plsBase;
    SVSLinkedSegment    *plsHead;

    unsigned int    iSegSize;
    unsigned int    iBlockSize;
    unsigned int    iHeadNdx;

#if defined (SVSUTIL_DEBUG_STACK)
    void CoherencyCheck (void) {
        SVSUTIL_ASSERT (iSegSize > 0);
        SVSUTIL_ASSERT (iBlockSize > 0);
        SVSUTIL_ASSERT (iHeadNdx < iSegSize);
        SVSUTIL_ASSERT (plsBase->plsPrev == NULL);
        SVSUTIL_ASSERT ((plsHead == plsBase) || (plsHead->plsPrev->plsNext == plsHead));
        SVSUTIL_ASSERT ((! plsHead->plsNext) || (plsHead->plsNext->plsPrev == plsHead));
        SVSUTIL_ASSERT ((! plsBase->plsNext) || (plsBase->plsNext->plsPrev == plsBase));
    }
#endif

public:
    SVSStack (unsigned int a_iSegSize = SVSUTIL_STACK_INITIAL) {
        SVSUTIL_ASSERT (a_iSegSize > 0);

        iSegSize = a_iSegSize;
        iHeadNdx = 0;

        iBlockSize = offsetof (SVSLinkedSegment, pvArray) + a_iSegSize * sizeof(void *);
        plsHead = plsBase = (SVSLinkedSegment *)g_funcAlloc(iBlockSize, g_pvAllocData);

        SVSUTIL_ASSERT (plsHead);

        plsHead->plsPrev = plsHead->plsNext = NULL;

#if defined (SVSUTIL_DEBUG_STACK)
        CoherencyCheck ();
#endif
    }

    ~SVSStack (void) {
        SVSLinkedSegment *pls = plsBase;
        while (pls) {
            SVSLinkedSegment *plsNext = pls->plsNext;
            g_funcFree (pls, g_pvFreeData);
            pls = plsNext;
        }
    }

    int IsEmpty (void) {
#if defined (SVSUTIL_DEBUG_STACK)
        CoherencyCheck ();
#endif
        return (plsHead == plsBase) && (iHeadNdx == 0);
    }

    int Push (void *pvData) {
#if defined (SVSUTIL_DEBUG_STACK)
        CoherencyCheck ();
#endif
        plsHead->pvArray[iHeadNdx++] = pvData;

        if (iHeadNdx < iSegSize)
            return TRUE;

        iHeadNdx = 0;

        if (plsHead->plsNext != NULL) {
            plsHead = plsHead->plsNext;
            return TRUE;
        }

        SVSLinkedSegment *pls = (SVSLinkedSegment *)g_funcAlloc(iBlockSize, g_pvAllocData);

        if (! pls) {
            SVSUTIL_ASSERT (0);

            iHeadNdx = iSegSize - 1;
            return FALSE;
        }

        pls->plsPrev = plsHead;
        pls->plsNext = NULL;
        plsHead->plsNext = pls;

        plsHead = pls;
        return TRUE;
    }

    void *Peek (void) {
        if (IsEmpty()) {
            SVSUTIL_ASSERT(0);
            return NULL;
        }

        int               iHeadNdx2 = (int)iHeadNdx - 1;
        SVSLinkedSegment *plsHead2  = plsHead;

        if (iHeadNdx2 < 0) {
            iHeadNdx2 = iSegSize - 1;
            plsHead2  = plsHead->plsPrev;
        }

        return plsHead2->pvArray[iHeadNdx2];
    }

    void *Pop (void) {
        if (IsEmpty()) {
            SVSUTIL_ASSERT(0);
            return NULL;
        }

        if (((int)--iHeadNdx) < 0) {
            iHeadNdx = iSegSize - 1;
            plsHead = plsHead->plsPrev;
        }

        return plsHead->pvArray[iHeadNdx];
    }

    void Compact (void) {
#if defined (SVSUTIL_DEBUG_STACK)
        CoherencyCheck ();
#endif
        SVSLinkedSegment *pls = plsHead->plsNext;

        while (pls) {
            SVSLinkedSegment *plsNext = pls->plsNext;

            g_funcFree (pls, g_pvFreeData);

            pls = plsNext;
        }

        plsHead->plsNext = NULL;

#if defined (SVSUTIL_DEBUG_STACK)
        CoherencyCheck ();
#endif
    }
};

//
//  Expandable Arrays
//
template <class T> class SVSMTABlock  : public SVSAllocClass {
public:
    T               **m_p_ptCollection;
    int             m_iNdxFirst;
    int             m_iNdxLast;
    SVSMTABlock *m_pNextBlock;

    SVSMTABlock (SVSMTABlock *a_pCurrentHead, int iStartNdx) {
        SVSUTIL_ASSERT ((iStartNdx & SVSUTIL_TIER_MASK) == 0);
        SVSUTIL_ASSERT (iStartNdx >= 0);

        m_pNextBlock = a_pCurrentHead;
        m_iNdxFirst  = iStartNdx;
        m_iNdxLast   = iStartNdx | SVSUTIL_TIER_MASK;

        m_p_ptCollection = NULL;
    }

    ~SVSMTABlock (void) {
        if (! m_p_ptCollection)
            return;

        for (int i = 0 ; i < SVSUTIL_TIER_COLLECTION_SIZE ; ++i) {
            if (! m_p_ptCollection[i])
                break;

            g_funcFree (m_p_ptCollection[i], g_pvFreeData);
        }

        g_funcFree (m_p_ptCollection, g_pvFreeData);
    }

    int AllocateBlock (void) {
        SVSUTIL_ASSERT (m_p_ptCollection == NULL);

        int iSz = sizeof(T *) * SVSUTIL_TIER_COLLECTION_SIZE;
        m_p_ptCollection = (T **)g_funcAlloc (iSz, g_pvAllocData);

        if (! m_p_ptCollection) {
            SVSUTIL_ASSERT (0);
            return FALSE;
        }

        memset (m_p_ptCollection, 0, iSz);
        return TRUE;
    }

    int AllocateCluster (int i) {
        SVSUTIL_ASSERT (m_p_ptCollection[i] == NULL);

        m_p_ptCollection[i] = (T *)g_funcAlloc(sizeof(T) * SVSUTIL_TIER_ELEMENT_SIZE, g_pvAllocData);

        return m_p_ptCollection[i] != NULL;
    }
};

template <class T> class SVSExpArray : public SVSAllocClass {
protected:
    int                 m_iBigBlocks;
    int                 m_iPhysInLast;
    SVSMTABlock<T>      *m_pFirstBlock;

public:
    SVSExpArray(void) {
        m_pFirstBlock = NULL;
        m_iBigBlocks  = 0;
        m_iPhysInLast = 0;
    }


    int SRealloc (int a_iElemNum);
    int CRealloc (int a_iElemNum);

    ~SVSExpArray(void) {
        while (m_pFirstBlock) {
            SVSMTABlock<T> *pNextBlock = m_pFirstBlock->m_pNextBlock;
            delete m_pFirstBlock;
            m_pFirstBlock = pNextBlock;
        }
    }

    T& operator[](int iIndex) {
        static T dummy;

        int iBaseNdx = iIndex & (~SVSUTIL_TIER_MASK);
        SVSMTABlock<T> *pmta = m_pFirstBlock;
        while (pmta) {
            if (pmta->m_iNdxFirst == iBaseNdx)
                return pmta->m_p_ptCollection[(iIndex & SVSUTIL_TIER_COLLECTION_MASK) >> SVSUTIL_TIER_ELEMENT_BIT][iIndex & SVSUTIL_TIER_ELEMENT_MASK];

            pmta = pmta->m_pNextBlock;
        }

        return dummy;
    }
};

template <class T> int SVSExpArray<T>::SRealloc (int a_iElemNum) {
    SVSUTIL_ASSERT (a_iElemNum >= 0);

    int iNeedBlocks = (a_iElemNum >> SVSUTIL_TIER_BIT) + 1;

    if (iNeedBlocks < m_iBigBlocks)
        return TRUE;

    int iClusters  = ((a_iElemNum & SVSUTIL_TIER_MASK) >> SVSUTIL_TIER_ELEMENT_BIT) + 1;

    if ((iNeedBlocks == m_iBigBlocks) && (iClusters <= m_iPhysInLast))
        return TRUE;

    if (iNeedBlocks > m_iBigBlocks) {
        if (m_pFirstBlock) {
            while (m_iPhysInLast < SVSUTIL_TIER_COLLECTION_SIZE) {
                if (! m_pFirstBlock->AllocateCluster(m_iPhysInLast)) {
                    SVSUTIL_ASSERT(0);
                    return FALSE;
                }

                ++m_iPhysInLast;
            }
        }

        while (m_iBigBlocks < iNeedBlocks) {
            SVSMTABlock<T> *pNewFirst = new SVSMTABlock<T>(m_pFirstBlock, m_iBigBlocks << SVSUTIL_TIER_BIT);
            if ((! pNewFirst) || (!pNewFirst->AllocateBlock())) {
                SVSUTIL_ASSERT (0);
                return FALSE;
            }

            ++m_iBigBlocks;
            m_pFirstBlock = pNewFirst;

            m_iPhysInLast = 0;

            int iLimit = (m_iBigBlocks < iNeedBlocks) ? SVSUTIL_TIER_COLLECTION_SIZE : iClusters;

            while (m_iPhysInLast < iLimit) {
                if (! m_pFirstBlock->AllocateCluster(m_iPhysInLast)) {
                    SVSUTIL_ASSERT(0);
                    return FALSE;
                }
                ++m_iPhysInLast;
            }
        }

        return TRUE;
    }

    while (m_iPhysInLast < iClusters) {
        if (! m_pFirstBlock->AllocateCluster(m_iPhysInLast)) {
            SVSUTIL_ASSERT(0);
            return FALSE;
        }

        ++m_iPhysInLast;
    }

    return TRUE;
}

template <class T> int SVSExpArray<T>::CRealloc (int a_iElemNum) {
    SVSUTIL_ASSERT (a_iElemNum >= 0);

    int iNeedBlocks = (a_iElemNum >> SVSUTIL_TIER_BIT) + 1;

    if (iNeedBlocks > m_iBigBlocks)
        return SRealloc (a_iElemNum);

    int iClusters  = ((a_iElemNum & SVSUTIL_TIER_MASK) >> SVSUTIL_TIER_ELEMENT_BIT) + 1;

    if ((iNeedBlocks == m_iBigBlocks) && (iClusters > m_iPhysInLast))
        return SRealloc (a_iElemNum);

    while ((iNeedBlocks > m_iBigBlocks) && (m_iBigBlocks > 0)) {
        SVSMTABlock<T> *pmta = m_pFirstBlock->m_pNextBlock;
        delete m_pFirstBlock;
        m_pFirstBlock = pmta;

        --m_iBigBlocks;
        m_iPhysInLast = SVSUTIL_TIER_COLLECTION_SIZE;
    }

    while (m_iPhysInLast > iClusters) {
        SVSUTIL_ASSERT ((m_iPhysInLast == SVSUTIL_TIER_COLLECTION_SIZE) || (! m_pFirstBlock->m_p_ptCollection[m_iPhysInLast]));
        --m_iPhysInLast;
        SVSUTIL_ASSERT (m_pFirstBlock->m_p_ptCollection[m_iPhysInLast]);
        g_funcFree (m_pFirstBlock->m_p_ptCollection[m_iPhysInLast], g_pvFreeData);
        m_pFirstBlock->m_p_ptCollection[m_iPhysInLast] = NULL;
    }

    return TRUE;
}

//
//  Long bitfields
//
class SVSBitField  : public SVSAllocClass {
protected:
    int             m_iLength;
    int             m_iWLength;
    unsigned int    *m_puiData;
    unsigned int    m_uiLastWMask;

public:
    SVSBitField (int a_iLength) {
        SVSUTIL_ASSERT(a_iLength > 0);

        m_iLength     = a_iLength;
        m_iWLength    = (m_iLength / (8 * sizeof(int))) + 1;
        m_uiLastWMask = ~((-1) << (m_iLength - (m_iWLength - 1) * 8 * sizeof(int)));
        m_puiData     = (unsigned int *)g_funcAlloc (m_iWLength * sizeof(int), g_pvAllocData);
    }

    ~SVSBitField (void) {
        g_funcFree (m_puiData, g_pvFreeData);
    }

    SVSBitField &operator=(int iBit) {
        if ((iBit & 1) == 0)
            memset (m_puiData, 0, m_iWLength * sizeof(int));
        else
            memset (m_puiData, 0xff, m_iWLength * sizeof(int));

        return *this;
    }

    SVSBitField &operator=(SVSBitField &bf) {
        SVSUTIL_ASSERT (bf.m_iLength == m_iLength);

        memcpy (m_puiData, bf.m_puiData, m_iWLength * sizeof(int));

        return *this;
    }

    SVSBitField &operator|=(SVSBitField &bf) {
        SVSUTIL_ASSERT (bf.m_iLength == m_iLength);

        for (int i = 0 ; i < m_iWLength ; ++i)
            m_puiData[i] |= bf.m_puiData[i];

        return *this;
    }

    SVSBitField &operator&=(SVSBitField &bf) {
        SVSUTIL_ASSERT (bf.m_iLength == m_iLength);

        for (int i = 0 ; i < m_iWLength ; ++i)
            m_puiData[i] &= bf.m_puiData[i];

        return *this;
    }

    void Set (int iBitNum) {
        SVSUTIL_ASSERT (iBitNum < m_iLength);

        int iWord = iBitNum / (sizeof(int) * 8);
        unsigned int uiMask  = 1 << (iBitNum - iWord * sizeof(int) * 8);

        m_puiData[iWord] |= uiMask;
    }

    void Clear (int iBitNum) {
        SVSUTIL_ASSERT (iBitNum < m_iLength);

        int iWord = iBitNum / (sizeof(int) * 8);
        unsigned int uiMask  = 1 << (iBitNum - iWord * sizeof(int) * 8);

        m_puiData[iWord] &= ~uiMask;
    }

    void Inv (int iBitNum) {
        SVSUTIL_ASSERT (iBitNum < m_iLength);

        int iWord = iBitNum / (sizeof(int) * 8);
        unsigned int uiMask  = 1 << (iBitNum - iWord * sizeof(int) * 8);

        m_puiData[iWord] ^= uiMask;
    }

    int Get(int iBitNum) {
        SVSUTIL_ASSERT (iBitNum < m_iLength);

        int iWord = iBitNum / (sizeof(int) * 8);

        return (m_puiData[iWord] >> (iBitNum - iWord * sizeof(int) * 8)) & 1;
    }

    int operator==(int iBit) {
        unsigned int iCmp = ((iBit & 1) == 0) ? 0 : (unsigned int)-1;
        for (int i = 0 ; i < m_iWLength - 1 ; ++i) {
            if (m_puiData[i] != iCmp)
                return FALSE;
        }

        return ((m_puiData[i] ^ iCmp) & m_uiLastWMask) == 0;
    }

    int operator!=(int iBit) {
        return ! (*this == iBit);
    }

    int operator==(SVSBitField &bf) {
        if (bf.m_iLength != m_iLength)
            return FALSE;

        for (int i = 0 ; i < m_iWLength - 1 ; ++i) {
            if (m_puiData[i] != bf.m_puiData[i])
                return FALSE;
        }

        return ((m_puiData[i] ^ bf.m_puiData[i]) & m_uiLastWMask) == 0;
    }

    int operator!=(SVSBitField &bf) {
        return ! (*this == bf);
    }
};

//
//  Heaps
//
struct SVSHeapEntry {
    SVSCKey     cKey;
    void        *pvData;
};

class SVSHeap  : public SVSAllocClass, public SVSEnumClass {
protected:
    int                         heap_size;
    SVSExpArray<SVSHeapEntry>   *pArray;

    static int Parent(int i) { return (i - 1) / 2; }
    static int Left  (int i) { return 2 * i + 1;   }
    static int Right (int i) { return 2 * (i + 1); }

    void Heapify (int i) {
        int l = Left(i);
        int r = Right(i);
        int largest = ((l < heap_size) && ((*pArray)[l].cKey > (*pArray)[i].cKey)) ? l : i;
        if ((r < heap_size) && ((*pArray)[r].cKey > (*pArray)[largest].cKey))
            largest = r;

        if (largest != i) {
            SVSHeapEntry he = (*pArray)[i];
            (*pArray)[i] = (*pArray)[largest];
            (*pArray)[largest] = he;

            Heapify (largest);
        }
    }

public:
    SVSHeap (void) {
        heap_size = 0;
        pArray = new SVSExpArray<SVSHeapEntry>;
    }

    ~SVSHeap (void) {
        delete pArray;
    }

    int Insert(SVSCKey cKey, void *pvData) {
        if (! (*pArray).SRealloc(heap_size + 1))
            return FALSE;

        int i = heap_size++;

        while ((i > 0) && ((*pArray)[Parent(i)].cKey < cKey)) {
            (*pArray)[i] = (*pArray)[Parent(i)];
            i = Parent(i);
        }

        (*pArray)[i].cKey   = cKey;
        (*pArray)[i].pvData = pvData;

        return TRUE;
    }

    void *Remove(SVSHandle hIndex)
    {
        if (heap_size < 1 || (int) hIndex > heap_size) {
            SVSUTIL_ASSERT(0);
            return NULL;
        }
        hIndex = hIndex - 1;

        void *pvResult = (*pArray)[hIndex].pvData;
        --heap_size;

        (*pArray)[hIndex] = (*pArray)[heap_size];

        Heapify(hIndex);
        return pvResult;
    }

    int IsEmpty (void) {
        return heap_size < 1;
    }

    void *Peek (SVSCKey *pcKey) {
        if (heap_size < 1) {
            SVSUTIL_ASSERT(0);
            return NULL;
        }

        if (pcKey)
            *pcKey = (*pArray)[0].cKey;

        return (*pArray)[0].pvData;
    }

    void *ExtractMax (SVSCKey *pcKey) {
        if (heap_size < 1) {
            SVSUTIL_ASSERT(0);
            return NULL;
        }

        void *pvResult = (*pArray)[0].pvData;

        if (pcKey)
            *pcKey = (*pArray)[0].cKey;

        --heap_size;

        (*pArray)[0] = (*pArray)[heap_size];

        Heapify (0);

        return pvResult;
    }


    void Compact (void) {
        (*pArray).CRealloc (heap_size);
    }

    virtual SVSHandle EnumStart (void) {
        return heap_size < 1 ? SVSUTIL_HANDLE_INVALID : 1;
    }

    virtual SVSHandle EnumNext  (SVSHandle hEnum) {
        return (int)hEnum < heap_size ? hEnum + 1 : SVSUTIL_HANDLE_INVALID;
    }

    virtual void *EnumGetData  (SVSHandle hEnum) {
        SVSUTIL_ASSERT ((hEnum > 0) && ((int)hEnum <= heap_size));
        return (*pArray)[hEnum - 1].pvData;
    }

    virtual SVSCKey EnumGetKey  (SVSHandle hEnum) {
        SVSUTIL_ASSERT ((hEnum > 0) && ((int)hEnum <= heap_size));
        return (*pArray)[hEnum - 1].cKey;
    }
};

//
// Heap template
//
template <class T> struct SVSTHeapEntry {
    T cKey;
    void *pvData;
};


template <class T> class SVSTHeap {
protected:
    int                         heap_size;
    typedef SVSTHeapEntry<T> X;
    SVSExpArray<X>  *pArray;

    static int Parent(int i) { return (i - 1) / 2; }
    static int Left  (int i) { return 2 * i + 1;   }
    static int Right (int i) { return 2 * (i + 1); }

    void Heapify (int i) {
        int l = Left(i);
        int r = Right(i);
        int largest = ((l < heap_size) && ((*pArray)[l].cKey > (*pArray)[i].cKey)) ? l : i;
        if ((r < heap_size) && ((*pArray)[r].cKey > (*pArray)[largest].cKey))
            largest = r;

        if (largest != i) {
            SVSTHeapEntry<T> he = (*pArray)[i];
            (*pArray)[i] = (*pArray)[largest];
            (*pArray)[largest] = he;

            Heapify (largest);
        }
    }

public:
    SVSTHeap (void) {
        heap_size = 0;
        pArray = new SVSExpArray < SVSTHeapEntry<T> >;
    }

    ~SVSTHeap (void) {
        delete pArray;
    }

    int Insert(T cKey, void *pvData) {
        if (! (*pArray).SRealloc(heap_size + 1))
            return FALSE;

        int i = heap_size++;

        while ((i > 0) && ((*pArray)[Parent(i)].cKey < cKey)) {
            (*pArray)[i] = (*pArray)[Parent(i)];
            i = Parent(i);
        }

        (*pArray)[i].cKey   = cKey;
        (*pArray)[i].pvData = pvData;

        return TRUE;
    }

    void *Remove(SVSHandle hIndex)
    {
        if (heap_size < 1 || (int) hIndex > heap_size) {
            SVSUTIL_ASSERT(0);
            return NULL;
        }
        hIndex = hIndex - 1;

        void *pvResult = (*pArray)[hIndex].pvData;
        --heap_size;

        (*pArray)[hIndex] = (*pArray)[heap_size];

        Heapify(hIndex);
        return pvResult;
    }


    int IsEmpty (void) {
        return heap_size < 1;
    }

    void *Peek (T *pcKey) {
        if (heap_size < 1) {
            SVSUTIL_ASSERT(0);
            return NULL;
        }

        if (pcKey)
            *pcKey = (*pArray)[0].cKey;

        return (*pArray)[0].pvData;
    }

    void *ExtractMax (T *pcKey) {
        if (heap_size < 1) {
            SVSUTIL_ASSERT(0);
            return NULL;
        }

        void *pvResult = (*pArray)[0].pvData;

        if (pcKey)
            *pcKey = (*pArray)[0].cKey;

        --heap_size;

        (*pArray)[0] = (*pArray)[heap_size];

        Heapify (0);

        return pvResult;
    }


    void Compact (void) {
        (*pArray).CRealloc (heap_size);
    }

    virtual SVSHandle EnumStart (void) {
        return heap_size < 1 ? SVSUTIL_HANDLE_INVALID : 1;
    }

    virtual SVSHandle EnumNext  (SVSHandle hEnum) {
        return (int)hEnum < heap_size ? hEnum + 1 : SVSUTIL_HANDLE_INVALID;
    }

    virtual void *EnumGetData  (SVSHandle hEnum) {
        SVSUTIL_ASSERT ((hEnum > 0) && ((int)hEnum <= heap_size));
        return (*pArray)[hEnum - 1].pvData;
    }

    virtual T EnumGetKey  (SVSHandle hEnum) {
        SVSUTIL_ASSERT ((hEnum > 0) && ((int)hEnum <= heap_size));
        return (*pArray)[hEnum - 1].cKey;
    }
};


//
//      Handle system
//
#define SVSUTIL_HANDLE_NUMBITS  16

#define SVSUTIL_HANDLE_TAGBITS  (sizeof(SVSHandle) * 8 - SVSUTIL_HANDLE_NUMBITS)
#define SVSUTIL_HANDLE_MAXNUM   ((1 << SVSUTIL_HANDLE_NUMBITS) - 1)
#define SVSUTIL_HANDLE_MAXTAG   ((1 << SVSUTIL_HANDLE_TAGBITS) - 1)
#define SVSUTIL_HANDLE_TOTAG(h) ((h) >> SVSUTIL_HANDLE_NUMBITS)
#define SVSUTIL_HANDLE_TONUM(h) ((h) & SVSUTIL_HANDLE_MAXNUM)

class SVSPrivateHandle : public SVSAllocClass {
protected:
    union {
        void        *pvData;
        int         iNextFree;
    };

    struct {
        int          iTag   : 24;
        unsigned int fFree  : 1;
    };

    friend class SVSHandleSystem;
    friend class SVSSimpleHandleSystem;
};

class SVSHandleSystem : public SVSAllocClass {
protected:
    SVSExpArray<SVSPrivateHandle> *pArray;
    int                           iFreeNdx;
    int                           iArraySize;

public:
    SVSHandle   AllocHandle (void *a_pvData) {
        SVSUTIL_ASSERT (a_pvData != NULL);
        SVSUTIL_ASSERT (iFreeNdx < iArraySize);
        SVSUTIL_ASSERT (iArraySize >= 0);

        if (iFreeNdx == -1) {
            if (iArraySize >= SVSUTIL_HANDLE_MAXNUM)
                return FALSE;

            if (! (*pArray).SRealloc (iArraySize + 1))
                return SVSUTIL_HANDLE_INVALID;

            iFreeNdx = iArraySize;
            (*pArray)[iArraySize].iNextFree = -1;
            (*pArray)[iArraySize].iTag      = 1;
            (*pArray)[iArraySize].fFree     = TRUE;
            ++iArraySize;
        }

        SVSUTIL_ASSERT ((iFreeNdx >= 0) && (iFreeNdx < iArraySize));

        SVSPrivateHandle *psHandle = &(*pArray)[iFreeNdx];
        int               iNdx = iFreeNdx;

        SVSUTIL_ASSERT (psHandle->fFree);

        iFreeNdx = psHandle->iNextFree;

        psHandle->pvData = a_pvData;
        psHandle->fFree  = FALSE;
        psHandle->iTag  += 1;

        if (psHandle->iTag >= SVSUTIL_HANDLE_MAXTAG)
            psHandle->iTag = 1;

        return (psHandle->iTag << SVSUTIL_HANDLE_NUMBITS) | iNdx;
    }

    void        *CloseHandle (SVSHandle h) {
        SVSUTIL_ASSERT (iFreeNdx < iArraySize);

        int iTag = SVSUTIL_HANDLE_TOTAG(h);
        int iNum = SVSUTIL_HANDLE_TONUM(h);

        if ((iNum >= iArraySize) || (iTag != (*pArray)[iNum].iTag))
            return NULL;

        SVSUTIL_ASSERT (iArraySize > 0);

        SVSPrivateHandle *psHandle = &(*pArray)[iNum];
        void *pvData = psHandle->pvData;

        SVSUTIL_ASSERT (! psHandle->fFree);

        psHandle->iNextFree = iFreeNdx;
        psHandle->fFree     = TRUE;
        iFreeNdx = iNum;

        if (++psHandle->iTag >= SVSUTIL_HANDLE_MAXTAG)
            psHandle->iTag = 1;

        return pvData;
    }

    void        *TranslateHandle (SVSHandle h) {
        SVSUTIL_ASSERT (iFreeNdx < iArraySize);

        int iTag = SVSUTIL_HANDLE_TOTAG(h);
        int iNum = SVSUTIL_HANDLE_TONUM(h);

        if ((iNum >= iArraySize) || (iTag != (*pArray)[iNum].iTag))
            return NULL;

        SVSUTIL_ASSERT (iArraySize > 0);
        SVSUTIL_ASSERT (! (*pArray)[iNum].fFree);

        return (*pArray)[iNum].pvData;
    }

    void        *ReAssociate (SVSHandle h, void *pvData2) {
        SVSUTIL_ASSERT (iFreeNdx < iArraySize);
        SVSUTIL_ASSERT (pvData2 != NULL);

        int iTag = SVSUTIL_HANDLE_TOTAG(h);
        int iNum = SVSUTIL_HANDLE_TONUM(h);

        if ((iNum >= iArraySize) || (iTag != (*pArray)[iNum].iTag))
            return NULL;

        SVSUTIL_ASSERT (iArraySize > 0);
        SVSUTIL_ASSERT (! (*pArray)[iNum].fFree);

        void *pvResult = (*pArray)[iNum].pvData;

        (*pArray)[iNum].pvData = pvData2;

        return pvResult;
    }

    int FilterHandles (int (*pFuncFilter)(SVSHandle, void *), void *pvArg) {
        unsigned int iProcessed = 0;
        for (int i = 0 ; i < iArraySize ; ++i) {
            if (! (*pArray)[i].fFree)
                iProcessed += pFuncFilter (((*pArray)[i].iTag << SVSUTIL_HANDLE_NUMBITS) | i,
                                    pvArg);
        }

        return iProcessed;
    }

    SVSHandleSystem (void) {
        pArray      = new SVSExpArray<SVSPrivateHandle>;
        iFreeNdx    = -1;
        iArraySize  = 0;
    }

    ~SVSHandleSystem (void) {
        delete pArray;
    }
};

class SVSSimpleHandleSystem : public SVSAllocClass {
protected:
    SVSPrivateHandle              *pArray;
    int                           iFreeNdx;
    int                           iArraySize;
    int                           iMaxArraySize;

public:
    SVSHandle   AllocHandle (void *a_pvData) {
        SVSUTIL_ASSERT (a_pvData != NULL);
        SVSUTIL_ASSERT (iFreeNdx < iArraySize);
        SVSUTIL_ASSERT (iArraySize >= 0);

        if (iFreeNdx == -1) {
            if (iArraySize >= iMaxArraySize)
                return FALSE;

            iFreeNdx = iArraySize;
            pArray[iArraySize].iNextFree = -1;
            pArray[iArraySize].iTag      = 1;
            pArray[iArraySize].fFree     = TRUE;
            ++iArraySize;
        }

        SVSUTIL_ASSERT ((iFreeNdx >= 0) && (iFreeNdx < iArraySize));

        SVSPrivateHandle *psHandle = &pArray[iFreeNdx];
        int               iNdx = iFreeNdx;

        SVSUTIL_ASSERT (psHandle->fFree);

        iFreeNdx = psHandle->iNextFree;

        psHandle->pvData = a_pvData;
        psHandle->fFree  = FALSE;
        psHandle->iTag  += 1;

        if (psHandle->iTag >= SVSUTIL_HANDLE_MAXTAG)
            psHandle->iTag = 1;

        return (psHandle->iTag << SVSUTIL_HANDLE_NUMBITS) | iNdx;
    }

    void        *CloseHandle (SVSHandle h) {
        SVSUTIL_ASSERT (iFreeNdx < iArraySize);

        int iTag = SVSUTIL_HANDLE_TOTAG(h);
        int iNum = SVSUTIL_HANDLE_TONUM(h);

        if ((iNum >= iArraySize) || (iTag != pArray[iNum].iTag))
            return NULL;

        SVSUTIL_ASSERT (iArraySize > 0);

        SVSPrivateHandle *psHandle = &pArray[iNum];
        void *pvData = psHandle->pvData;

        SVSUTIL_ASSERT (! psHandle->fFree);

        psHandle->iNextFree = iFreeNdx;
        psHandle->fFree     = TRUE;
        iFreeNdx = iNum;

        if (++psHandle->iTag >= SVSUTIL_HANDLE_MAXTAG)
            psHandle->iTag = 1;

        return pvData;
    }

    void        *TranslateHandle (SVSHandle h) {
        SVSUTIL_ASSERT (iFreeNdx < iArraySize);

        int iTag = SVSUTIL_HANDLE_TOTAG(h);
        int iNum = SVSUTIL_HANDLE_TONUM(h);

        if ((iNum >= iArraySize) || (iTag != pArray[iNum].iTag))
            return NULL;

        SVSUTIL_ASSERT (iArraySize > 0);
        SVSUTIL_ASSERT (! pArray[iNum].fFree);

        return pArray[iNum].pvData;
    }

    void        *ReAssociate (SVSHandle h, void *pvData2) {
        SVSUTIL_ASSERT (iFreeNdx < iArraySize);
        SVSUTIL_ASSERT (pvData2 != NULL);

        int iTag = SVSUTIL_HANDLE_TOTAG(h);
        int iNum = SVSUTIL_HANDLE_TONUM(h);

        if ((iNum >= iArraySize) || (iTag != pArray[iNum].iTag))
            return NULL;

        SVSUTIL_ASSERT (iArraySize > 0);
        SVSUTIL_ASSERT (! pArray[iNum].fFree);

        void *pvResult = pArray[iNum].pvData;

        pArray[iNum].pvData = pvData2;

        return pvResult;
    }

    int FilterHandles (int (*pFuncFilter)(SVSHandle, void *), void *pvArg) {
        unsigned int iProcessed = 0;
        for (int i = 0 ; i < iArraySize ; ++i) {
            if (! pArray[i].fFree)
                iProcessed += pFuncFilter ((pArray[i].iTag << SVSUTIL_HANDLE_NUMBITS) | i,
                                    pvArg);
        }

        return iProcessed;
    }

    SVSSimpleHandleSystem (int a_iMaxArraySize) {
        pArray          = (SVSPrivateHandle *)g_funcAlloc (sizeof(SVSPrivateHandle) * a_iMaxArraySize, g_pvAllocData);
        iFreeNdx        = -1;
        iArraySize      = 0;
        iMaxArraySize   = a_iMaxArraySize;
    }

    ~SVSSimpleHandleSystem (void) {
        g_funcFree (pArray, g_pvFreeData);
    }
};

#define SVSUTIL_PGUID_ELEMENTS(p) \
    p->Data1,                 p->Data2,    p->Data3,\
    p->Data4[0], p->Data4[1], p->Data4[2], p->Data4[3],\
    p->Data4[4], p->Data4[5], p->Data4[6], p->Data4[7]

#define SVSUTIL_RGUID_ELEMENTS(p) \
    p.Data1,                p.Data2,    p.Data3,\
    p.Data4[0], p.Data4[1], p.Data4[2], p.Data4[3],\
    p.Data4[4], p.Data4[5], p.Data4[6], p.Data4[7]

#define SVSUTIL_GUID_FORMAT     L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"
#define SVSUTIL_GUID_STR_LENGTH (8 + 1 + 4 + 1 + 4 + 1 + 4 + 1 + 12)

//
//  C-like interface
//
extern "C" {
    SVSQueue *svsutil_GetQueue (unsigned int uiChunkSize);
    int svsutil_IsQueueEmpty (SVSQueue *pQueue);
    int svsutil_PutInQueue (SVSQueue *pQueue, void *pvDatum);
    void *svsutil_GetFromQueue (SVSQueue *pQueue);
    void *svsutil_PeekQueue (SVSQueue *pQueue);
    void svsutil_CompactQueue (SVSQueue *pQueue);
    void svsutil_DestroyQueue (SVSQueue *pQueue);

    SVSStack *svsutil_GetStack (unsigned int uiChunkSize);
    int svsutil_IsStackEmpty (SVSStack *pStack);
    int svsutil_PushStack (SVSStack *pStack, void *pvDatum);
    void *svsutil_PopStack (SVSStack *pStack);
    void *svsutil_PeekStack (SVSStack *pStack);
    void svsutil_CompactStack (SVSStack *pStack);
    void svsutil_DestroyStack (SVSStack *pStack);

    SVSStack *svsutil_GetHeap (void);
    int svsutil_IsHeapEmpty (SVSHeap *pHeap);
    int svsutil_InsertInHeap (SVSHeap *pHeap, SVSCKey *pcKey, void *pvDatum);
    void *svsutil_ExtractMaxFromHeap (SVSHeap *pHeap, SVSCKey *pcKey);
    void *svsutil_PeekHeap (SVSHeap *pHeap, SVSCKey *pcKet);
    void svsutil_CompactHeap (SVSHeap *pHeap);
    void svsutil_DestroyHeap (SVSHeap *pHeap);
}


//
// Thread pool
//

// For converting between filetime and tick measurements
#define SVS_FILETIME_TO_MILLISECONDS ((__int64)10000L)

#if defined (UNDER_CE) && !defined (InterlockedCompareExchange)
#define InterlockedCompareExchange(ptr, newval, oldval) \
    ((PVOID)InterlockedTestExchange((LPLONG)ptr, (LONG)oldval, (LONG)newval))
#endif

typedef unsigned long SVSCookie;

#define SVS_DEBUG_THREAD_WORKER         0
#define SVS_DEBUG_THREAD_SCHEDULE_EVENT 0
#define SVS_DEBUG_THREAD_QUEUE          0

#define SVS_THREAD_POOL_DEFAULT_MAX_THREADS        20

class SVSThreadBlock
{
friend class SVSThreadPool;
protected:
    LPTHREAD_START_ROUTINE m_pfnThread;
    LPVOID m_lpParameter;
    SVSCookie m_ulCookie;

    unsigned long Run() {
        SVSUTIL_ASSERT (m_pfnThread && m_ulCookie);
        return (m_pfnThread)(m_lpParameter);
    }
};


inline __int64 SVSGetCurrentFT(void)
{
    SYSTEMTIME st;
    __int64    ft;

    GetSystemTime(&st);
    SystemTimeToFileTime(&st,(LPFILETIME) &ft);
    return ft;
}


// User application uses this in GetStatistics
typedef struct
{
    LONG fRunning;
    unsigned long           cThreadsRunning;
    unsigned long           cThreadsIdle;
    unsigned long           ulAverageDelayTime;
    long                    cJobsExecuted;
} SVS_THREAD_POOL_STATS;

//
// Used internally by SVSThreadPool for statistics
//

#define SVS_THREAD_STATS_RESIZE 5
class CSVSThreadPoolInternalStats
{
    double                  m_dAvgArray[2];
    __int64                 m_ftPrev;
    int                     m_iSlot;
    int                     m_iIndex;
    long                    m_cJobsExecuted;

public:
    CSVSThreadPoolInternalStats() {
        memset(this,0,sizeof(*this));
    }

    // Called with Lock held by caller.
    void UpdateStatistics(void) {
        __int64 ftNow = SVSGetCurrentFT();
        __int64 ftDelta;

        m_cJobsExecuted++;

        ftDelta = m_ftPrev ? ftNow - m_ftPrev : 0;
        m_ftPrev = ftNow;
        m_dAvgArray[m_iSlot] += ftDelta;

        m_iIndex++;
        if (m_iIndex == SVS_THREAD_STATS_RESIZE)
        {
            m_dAvgArray[m_iSlot] /= SVS_THREAD_STATS_RESIZE;
            m_iSlot  = (m_iSlot + 1) % 2;
            m_dAvgArray[m_iSlot] = 0;
            m_iIndex = 0;
        }
    }

    // Called with Lock held by caller.
    double CalculateAverageDelay(void) {
        double dRet;
        if (m_cJobsExecuted == 0)
        {
            dRet =  0;
        }
        else if (m_cJobsExecuted < SVS_THREAD_STATS_RESIZE)
        {
            dRet =  m_dAvgArray[0] / m_cJobsExecuted;
        }
        else
        {
            dRet =  (m_dAvgArray[!m_iSlot]*SVS_THREAD_STATS_RESIZE +
                     m_dAvgArray[m_iSlot]) / (m_iIndex + SVS_THREAD_STATS_RESIZE);
        }

        return (double) (dRet / SVS_FILETIME_TO_MILLISECONDS);
    }

    int NumberOfJobsExecuted(void) {
        return m_cJobsExecuted;
    }
};

class SVSThreadPool : public SVSSynch, public SVSAllocClass, public SVSTHeap<__int64>
{
protected:
    FixedMemDescr           *m_pNodeMem;            // physical memory of SVSThreadBlock structures, both ones in use and not.
    HANDLE                  m_hWorkerEvent;         // signals running worker threads we're ready
    HANDLE                  m_hTimerEvent;          // signals running worker threads we're ready

    long                    m_fRunning;             // Are we accepting new thread requests?
    unsigned long           m_cMaxThreadsAllowed;   // Maximum # of threads to allow
    unsigned long           m_cThreadsRunning;      // # of threads executing user code
    unsigned long           m_cThreadsIdle;         // # of threads not executing user code but available.
    SVSCookie               m_ulCookie;             // Value of next cookie to assign
    long                    m_fTimerLock;           // Used to sync which worker is the timer

#if defined (SVSUTIL_DEBUG_THREADS)
    CSVSThreadPoolInternalStats     m_Stats;        // Perf statistics.
#endif


    BOOL GetTimer(void) {
        return !InterlockedCompareExchange(&m_fTimerLock,1,0);
    }

    void ReleaseTimer(void) {
        m_fTimerLock = 0;
    }

    // BUGBUG -- what happens if someone changes system time??
    // Called with Lock held by caller.
    SVSThreadBlock * GetNextJobFromQueue()
    {
        SVSUTIL_ASSERT(IsLocked());
        __int64 ftNow;
        __int64 ftNextEvent;
        SVSThreadBlock *ret;

        if (IsEmpty() || !m_fRunning)
            return NULL;

        ret = (SVSThreadBlock *) Peek(&ftNextEvent);

        ftNow = SVSGetCurrentFT();

        if (ftNow >= ~ftNextEvent)
        {
            ExtractMax(NULL);
        }
        else
        {
            ret = NULL;
        }
        return ret;
    }

    // Called with Lock held by caller.
    SVSCookie PutOnWorkerQueue(LPTHREAD_START_ROUTINE pfn, LPVOID lpParameter,__int64 ftExecuteTime)
    {
        SVSUTIL_ASSERT(IsLocked());
        SVSThreadBlock *pThreadBlock = (SVSThreadBlock *)svsutil_GetFixed (m_pNodeMem);

        pThreadBlock->m_pfnThread   = pfn;
        pThreadBlock->m_lpParameter = lpParameter;
        pThreadBlock->m_ulCookie     = ++m_ulCookie;

        if (! Insert(~ftExecuteTime,pThreadBlock))
            return 0;

        if (m_cThreadsRunning == 0 && m_cThreadsIdle == 0)
        {
            HANDLE hThread = CreateThread(0,0,SVSThreadPoolWorkerThread,this,0,0);
            SVSUTIL_ASSERT (hThread);

            if (hThread)
            {
                CloseHandle(hThread);
                m_cThreadsIdle++;
            }
        }
        SetEvent(m_hTimerEvent);
        return pThreadBlock->m_ulCookie;
    }

    // Called with Lock held by caller.
    unsigned long GetDelayUntilNextEvent()
    {
        SVSUTIL_ASSERT(IsLocked());
        __int64 ftNow;
        __int64 ftNextEvent;

        if (IsEmpty())
            return INFINITE;

        Peek(&ftNextEvent);
        ftNextEvent = ~ftNextEvent;
        ftNow = SVSGetCurrentFT();

        // if event has passed, set to 0 timeout.
        if (ftNow >= ftNextEvent)
            return 0;

        return (unsigned long) ((ftNextEvent - ftNow) / SVS_FILETIME_TO_MILLISECONDS);
    }

    void Worker()
    {
        SVSThreadBlock *pThreadBlock = NULL;
        BOOL            fTimer;
        unsigned long   ulTimeOut;
        HANDLE          hEvent;

        while (m_fRunning)
        {
            fTimer = GetTimer();

            if (fTimer)
            {
                hEvent = m_hTimerEvent;
                Lock();
                ulTimeOut = GetDelayUntilNextEvent();
                Unlock();
            }
            else
            {
                ulTimeOut = 5*60000;
                hEvent = m_hWorkerEvent;
            }

            if (WAIT_TIMEOUT == WaitForSingleObject(hEvent,ulTimeOut))
            {
                // If we're not the timer thread then we're done executing...
                if (!fTimer)
                {
                    break;
                }
            }
            else if (!fTimer)
            {
                // We get the worker thread event if a timer has been freed
                // or if we're shutting down, in either case we want
                // to go to top of while loop.
                continue;
            }

            SVSUTIL_ASSERT(fTimer);
            ReleaseTimer();

            Lock();
            pThreadBlock = GetNextJobFromQueue();
            if (!pThreadBlock)
            {
                Unlock();
                continue;
            }

            m_cThreadsIdle--;
            m_cThreadsRunning++;

            if (m_cThreadsIdle)
            {
                SetEvent(m_hWorkerEvent);
            }
            else if (m_cThreadsRunning < m_cMaxThreadsAllowed)
            {
                HANDLE hThread = CreateThread(0,0,SVSThreadPoolWorkerThread,this,0,0);
                SVSUTIL_ASSERT (hThread);
                if (hThread)
                {
                    CloseHandle(hThread);
                    m_cThreadsIdle++;
                }
            }
#if defined (SVSUTIL_DEBUG_THREADS)
            m_Stats.UpdateStatistics();
#endif

            Unlock();
            pThreadBlock->Run();

            Lock();
            svsutil_FreeFixed(pThreadBlock,m_pNodeMem);
            m_cThreadsIdle++;
            m_cThreadsRunning--;
            Unlock();

        }
        Lock();  m_cThreadsIdle--; Unlock();
    }


    static unsigned long WINAPI SVSThreadPoolWorkerThread(LPVOID lpv)
    {
        SVSThreadPool *pThreadPool = (SVSThreadPool *) lpv;

        pThreadPool->Worker();
        return 0;
    }

public:
    SVSThreadPool (unsigned long ulMaxThreads=SVS_THREAD_POOL_DEFAULT_MAX_THREADS)
    {
        m_cMaxThreadsAllowed = ulMaxThreads;
        m_hTimerEvent = m_hWorkerEvent = 0;
        m_cThreadsIdle = m_cThreadsRunning = m_ulCookie = 0;
        m_fTimerLock = FALSE;

        m_pNodeMem = svsutil_AllocFixedMemDescr (sizeof(SVSThreadBlock), 20);
        pArray = new SVSExpArray<X>;  //    typedef SVSTHeapEntry<__int64> X;
        m_hWorkerEvent = CreateEvent (0, FALSE, FALSE, 0);
        m_hTimerEvent  = CreateEvent (0, FALSE, FALSE, 0);


        SVSUTIL_ASSERT ( m_pNodeMem && pArray && m_hWorkerEvent && m_hTimerEvent);

        if (m_pNodeMem && pArray && m_hWorkerEvent && m_hTimerEvent)
        {
            m_fRunning = TRUE;
        }
    }

    ~SVSThreadPool()
    {
        Shutdown();
        SVSUTIL_ASSERT (m_cThreadsRunning == 0 && m_cThreadsIdle == 0);

        if (m_pNodeMem)
            svsutil_ReleaseFixedNonEmpty(m_pNodeMem);

        if (m_hWorkerEvent)
            CloseHandle (m_hWorkerEvent);

        if (m_hTimerEvent)
            CloseHandle (m_hTimerEvent);
    }

    // Shutdown all timers and running threads.  Once shutdown has started,
    // no threads or timers may ever fire again
    unsigned long Shutdown()
    {
        m_fRunning = FALSE;

        while (m_cThreadsRunning || m_cThreadsIdle)
        {
            SetEvent(m_hTimerEvent);
            SetEvent(m_hWorkerEvent);
            Sleep(1000);
        }
        return TRUE;
    }

    SVSCookie ScheduleEvent(LPTHREAD_START_ROUTINE pfn, LPVOID lpParameter, unsigned long ulDelayTime=0)
    {
        SVSCookie ret = 0;
        __int64   ftExecuteTime;

        if (!m_fRunning)
        {
            return 0;
        }

        ftExecuteTime = SVSGetCurrentFT();
        ftExecuteTime += ulDelayTime * SVS_FILETIME_TO_MILLISECONDS;

        Lock();
        ret = PutOnWorkerQueue(pfn,lpParameter,ftExecuteTime);
        Unlock();
        return ret;
    }

    SVSCookie StartTimer(LPTHREAD_START_ROUTINE pfn, LPVOID lpParameter,unsigned long ulDelayTime)
    {
        return ScheduleEvent(pfn,lpParameter,ulDelayTime);
    }

    BOOL UnScheduleEvent(SVSCookie ulCookie)
    {
        BOOL ret = FALSE;
        SVSHandle hEnum;
        SVSThreadBlock *pThreadBlock;

        Lock();
        hEnum = EnumStart();
        do
        {
            pThreadBlock = (SVSThreadBlock *)EnumGetData(hEnum);
            if (pThreadBlock->m_ulCookie == ulCookie)
            {
                ret = Remove(hEnum) ? TRUE : FALSE;
                break;
            }
        } while (SVSUTIL_HANDLE_INVALID != (hEnum = EnumNext(hEnum)));

        Unlock();
        return ret;
    }

    BOOL StopTimer(SVSCookie ulCookie)
    {
        return UnScheduleEvent(ulCookie);
    }

#if defined (SVSUTIL_DEBUG_THREADS)
public:
    void GetStatistics(SVS_THREAD_POOL_STATS *pThreadStats)
    {
        if (!pThreadStats)
            return;

        Lock();
        pThreadStats->fRunning = m_fRunning;
        pThreadStats->cThreadsRunning = m_cThreadsRunning;
        pThreadStats->cThreadsIdle = m_cThreadsIdle;
        pThreadStats->ulAverageDelayTime = (unsigned long) m_Stats.CalculateAverageDelay();
        pThreadStats->cJobsExecuted = m_Stats.NumberOfJobsExecuted();
        Unlock();
    }
#endif  // SVSUTIL_DEBUG_THREADS
};


#else   /* __cplusplus */

struct SVSQueue;
struct SVSStack;
struct SVSHeap;

struct SVSQueue *svsutil_GetQueue (unsigned int uiChunkSize);
int svsutil_IsQueueEmpty (struct SVSQueue *pQueue);
int svsutil_PutInQueue (struct SVSQueue *pQueue, void *pvDatum);
void *svsutil_GetFromQueue (struct SVSQueue *pQueue);
void *svsutil_PeekQueue (struct SVSQueue *pQueue);
void svsutil_CompactQueue (struct SVSQueue *pQueue);
void svsutil_DestroyQueue (struct SVSQueue *pQueue);

struct SVSStack *svsutil_GetStack (unsigned int uiChunkSize);
int svsutil_IsStackEmpty (struct SVSStack *pStack);
int svsutil_PushStack (struct SVSStack *pStack, void *pvDatum);
void *svsutil_PopStack (struct SVSStack *pStack);
void *svsutil_PeekStack (struct SVSStack *pStack);
void svsutil_CompactStack (struct SVSStack *pStack);
void svsutil_DestroyStack (struct SVSStack *pStack);

struct SVSStack *svsutil_GetHeap (void);
int svsutil_IsHeapEmpty (struct SVSHeap *pHeap);
int svsutil_InsertInHeap (struct SVSHeap *pHeap, SVSCKey *pcKey, void *pvDatum);
void *svsutil_ExtractMaxFromHeap (struct SVSHeap *pHeap, SVSCKey *pcKey);
void *svsutil_PeekHeap (struct SVSHeap *pHeap, SVSCKey *pcKet);
void svsutil_CompactHeap (struct SVSHeap *pHeap);
void svsutil_DestroyHeap (struct SVSHeap *pHeap);

#endif

#endif /* __svsutil_HXX__ */