home *** CD-ROM | disk | FTP | other *** search
- #ifndef __DEBUGGERUTIL_H__
- #define __DEBUGGERUTIL_H__
-
- #include "stdlib.h"
-
- static inline void * __cdecl operator new(size_t n) { return LocalAlloc(LMEM_FIXED, n); }
- static inline void * __cdecl operator new[](size_t n) { return LocalAlloc(LMEM_FIXED, n); };
- static inline void __cdecl operator delete(void *p) { LocalFree(p); }
- static inline void __cdecl operator delete[](void *p) { LocalFree(p); }
-
- /* ------------------------------------------------------------------------- *
- * Utility methods used by the debugger sample.
- * ------------------------------------------------------------------------- */
-
- #define CQUICKBYTES_BASE_SIZE 512
- #define CQUICKBYTES_INCREMENTAL_SIZE 128
-
- //*****************************************************************************
- //
- // **** CQuickBytes
- // This helper class is useful for cases where 90% of the time you allocate 512
- // or less bytes for a data structure. This class contains a 512 byte buffer.
- // Alloc() will return a pointer to this buffer if your allocation is small
- // enough, otherwise it asks the heap for a larger buffer which is freed for
- // you. No mutex locking is required for the small allocation case, making the
- // code run faster, less heap fragmentation, etc... Each instance will allocate
- // 520 bytes, so use accordinly.
- //
- //*****************************************************************************
- class CQuickBytes
- {
- public:
- CQuickBytes() :
- pbBuff(0),
- iSize(0),
- cbTotal(CQUICKBYTES_BASE_SIZE)
- { }
-
- ~CQuickBytes()
- {
- if (pbBuff)
- free(pbBuff);
- }
-
- void *Alloc(int iItems)
- {
- iSize = iItems;
- if (iItems <= CQUICKBYTES_BASE_SIZE)
- return (&rgData[0]);
- else
- {
- pbBuff = malloc(iItems);
- return (pbBuff);
- }
- }
-
- HRESULT ReSize(int iItems)
- {
- void *pbBuffNew;
- if (iItems <= cbTotal)
- {
- iSize = iItems;
- return NOERROR;
- }
-
- pbBuffNew = malloc(iItems + CQUICKBYTES_INCREMENTAL_SIZE);
- if (!pbBuffNew)
- return E_OUTOFMEMORY;
- if (pbBuff)
- {
- memcpy(pbBuffNew, pbBuff, cbTotal);
- free(pbBuff);
- }
- else
- {
- _ASSERTE(cbTotal == CQUICKBYTES_BASE_SIZE);
- memcpy(pbBuffNew, rgData, cbTotal);
- }
- cbTotal = iItems + CQUICKBYTES_INCREMENTAL_SIZE;
- iSize = iItems;
- pbBuff = pbBuffNew;
- return NOERROR;
-
- }
- operator PVOID()
- { return ((pbBuff) ? pbBuff : &rgData[0]); }
-
- void *Ptr()
- { return ((pbBuff) ? pbBuff : &rgData[0]); }
-
- int Size()
- { return (iSize); }
-
- void *pbBuff;
- int iSize; // number of bytes used
- int cbTotal; // total bytes allocated in the buffer
- BYTE rgData[512];
- };
-
- //*****************************************************************************
- // The information that the hash table implementation stores at the beginning
- // of every record that can be but in the hash table.
- //*****************************************************************************
- struct HASHENTRY
- {
- USHORT iPrev; // Previous bucket in the chain.
- USHORT iNext; // Next bucket in the chain.
- };
-
- struct FREEHASHENTRY : HASHENTRY
- {
- USHORT iFree;
- };
-
- //*****************************************************************************
- // Used by the FindFirst/FindNextEntry functions. These api's allow you to
- // do a sequential scan of all entries.
- //*****************************************************************************
- struct HASHFIND
- {
- USHORT iBucket; // The next bucket to look in.
- USHORT iNext;
- };
-
-
- //*****************************************************************************
- // This is a class that implements a chain and bucket hash table. The table
- // is actually supplied as an array of structures by the user of this class
- // and this maintains the chains in a HASHENTRY structure that must be at the
- // beginning of every structure placed in the hash table. Immediately
- // following the HASHENTRY must be the key used to hash the structure.
- //*****************************************************************************
- class CHashTable
- {
- protected:
- BYTE *m_pcEntries; // Pointer to the array of structs.
- USHORT m_iEntrySize; // Size of the structs.
- USHORT m_iBuckets; // # of chains we are hashing into.
- USHORT *m_piBuckets; // Ptr to the array of bucket chains.
-
- HASHENTRY *EntryPtr(USHORT iEntry)
- { return ((HASHENTRY *) (m_pcEntries + (iEntry * m_iEntrySize))); }
-
- USHORT ItemIndex(HASHENTRY *p)
- {
- //
- // The following Index calculation is not safe on 64-bit platforms,
- // so we'll assert a range check in debug, which will catch SOME
- // offensive usages. It also seems, to my eye, not to be safe on
- // 32-bit platforms, but the 32-bit compilers don't seem to complain
- // about it. Perhaps our warning levels are set too low?
- //
- // [[@TODO: brianbec]]
- //
-
- # pragma warning(disable:4244)
-
- _ASSERTE( (( ( ((BYTE*)p) - m_pcEntries ) / m_iEntrySize ) & (~0xFFFF)) == 0 ) ;
-
- return (((BYTE *) p - m_pcEntries) / m_iEntrySize);
-
- # pragma warning(default:4244)
- }
-
-
- public:
- CHashTable(
- USHORT iBuckets) : // # of chains we are hashing into.
- m_iBuckets(iBuckets),
- m_piBuckets(NULL),
- m_pcEntries(NULL)
- {
- _ASSERTE(iBuckets < 0xffff);
- }
- ~CHashTable()
- {
- if (m_piBuckets != NULL)
- {
- delete [] m_piBuckets;
- m_piBuckets = NULL;
- }
- }
-
- //*****************************************************************************
- // This is the second part of construction where we do all of the work that
- // can fail. We also take the array of structs here because the calling class
- // presumably needs to allocate it in its NewInit.
- //*****************************************************************************
- HRESULT NewInit( // Return status.
- BYTE *pcEntries, // Array of structs we are managing.
- USHORT iEntrySize); // Size of the entries.
-
- //*****************************************************************************
- // Return a boolean indicating whether or not this hash table has been inited.
- //*****************************************************************************
- int IsInited()
- { return (m_piBuckets != NULL); }
-
- //*****************************************************************************
- // This can be called to change the pointer to the table that the hash table
- // is managing. You might call this if (for example) you realloc the size
- // of the table and its pointer is different.
- //*****************************************************************************
- void SetTable(
- BYTE *pcEntries) // Array of structs we are managing.
- {
- m_pcEntries = pcEntries;
- }
-
- //*****************************************************************************
- // Clear the hash table as if there were nothing in it.
- //*****************************************************************************
- void Clear()
- {
- _ASSERTE(m_piBuckets != NULL);
- memset(m_piBuckets, 0xff, m_iBuckets * sizeof(USHORT));
- }
-
- //*****************************************************************************
- // Add the struct at the specified index in m_pcEntries to the hash chains.
- //*****************************************************************************
- BYTE *Add( // New entry.
- USHORT iHash, // Hash value of entry to add.
- USHORT iIndex); // Index of struct in m_pcEntries.
-
- //*****************************************************************************
- // Delete the struct at the specified index in m_pcEntries from the hash chains.
- //*****************************************************************************
- void Delete(
- USHORT iHash, // Hash value of entry to delete.
- USHORT iIndex); // Index of struct in m_pcEntries.
-
- void Delete(
- USHORT iHash, // Hash value of entry to delete.
- HASHENTRY *psEntry); // The struct to delete.
-
- //*****************************************************************************
- // The item at the specified index has been moved, update the previous and
- // next item.
- //*****************************************************************************
- void Move(
- USHORT iHash, // Hash value for the item.
- USHORT iNew); // New location.
-
- //*****************************************************************************
- // Search the hash table for an entry with the specified key value.
- //*****************************************************************************
- BYTE *Find( // Index of struct in m_pcEntries.
- USHORT iHash, // Hash value of the item.
- BYTE *pcKey); // The key to match.
-
- //*****************************************************************************
- // Search the hash table for the next entry with the specified key value.
- //*****************************************************************************
- USHORT FindNext( // Index of struct in m_pcEntries.
- BYTE *pcKey, // The key to match.
- USHORT iIndex); // Index of previous match.
-
- //*****************************************************************************
- // Returns the first entry in the first hash bucket and inits the search
- // struct. Use the FindNextEntry function to continue walking the list. The
- // return order is not gauranteed.
- //*****************************************************************************
- BYTE *FindFirstEntry( // First entry found, or 0.
- HASHFIND *psSrch) // Search object.
- {
- if (m_piBuckets == 0)
- return (0);
- psSrch->iBucket = 1;
- psSrch->iNext = m_piBuckets[0];
- return (FindNextEntry(psSrch));
- }
-
- //*****************************************************************************
- // Returns the next entry in the list.
- //*****************************************************************************
- BYTE *FindNextEntry( // The next entry, or0 for end of list.
- HASHFIND *psSrch); // Search object.
-
- protected:
- virtual inline BOOL Cmp(const BYTE *pc1, const HASHENTRY *pc2) = 0;
- };
-
-
- //*****************************************************************************
- // Allocater classes for the CHashTableAndData class. One is for VirtualAlloc
- // and the other for malloc.
- //*****************************************************************************
- class CVMemData
- {
- public:
- static BYTE *Alloc(int iSize, int iMaxSize)
- {
- BYTE *pPtr;
-
- _ASSERTE((iSize & 4095) == 0);
- _ASSERTE((iMaxSize & 4095) == 0);
- if ((pPtr = (BYTE *) VirtualAlloc(NULL, iMaxSize,
- MEM_RESERVE, PAGE_NOACCESS)) == NULL ||
- VirtualAlloc(pPtr, iSize, MEM_COMMIT, PAGE_READWRITE) == NULL)
- {
- VirtualFree(pPtr, 0, MEM_RELEASE);
- return (NULL);
- }
- return (pPtr);
- }
- static void Free(BYTE *pPtr, int iSize)
- {
- _ASSERTE((iSize & 4095) == 0);
- VirtualFree(pPtr, iSize, MEM_DECOMMIT);
- VirtualFree(pPtr, 0, MEM_RELEASE);
- }
- static BYTE *Grow(BYTE *pPtr, int iCurSize)
- {
- _ASSERTE((iCurSize & 4095) == 0);
- return ((BYTE *) VirtualAlloc(pPtr + iCurSize, GrowSize(), MEM_COMMIT, PAGE_READWRITE));
- }
- static int RoundSize(int iSize)
- {
- return ((iSize + 4095) & ~4095);
- }
- static int GrowSize()
- {
- return (4096);
- }
- };
-
- class CNewData
- {
- public:
- static BYTE *Alloc(int iSize, int iMaxSize)
- {
- return ((BYTE *) malloc(iSize));
- }
- static void Free(BYTE *pPtr, int iSize)
- {
- free(pPtr);
- }
- static BYTE *Grow(BYTE *&pPtr, int iCurSize)
- {
- void *p = realloc(pPtr, iCurSize + GrowSize());
- if (p == 0) return (0);
- return (pPtr = (BYTE *) p);
- }
- static int RoundSize(int iSize)
- {
- return (iSize);
- }
- static int GrowSize()
- {
- return (256);
- }
- };
-
-
- //*****************************************************************************
- // This simple code handles a contiguous piece of memory. Growth is done via
- // realloc, so pointers can move. This class just cleans up the amount of code
- // required in every function that uses this type of data structure.
- //*****************************************************************************
- class CMemChunk
- {
- public:
- CMemChunk() : m_pbData(0), m_cbSize(0), m_cbNext(0) { }
- ~CMemChunk()
- {
- Clear();
- }
-
- BYTE *GetChunk(int cbSize)
- {
- BYTE *p;
- if (m_cbSize - m_cbNext < cbSize)
- {
- int cbNew = max(cbSize, 512);
- p = (BYTE *) realloc(m_pbData, m_cbSize + cbNew);
- if (!p) return (0);
- m_pbData = p;
- m_cbSize += cbNew;
- }
- p = m_pbData + m_cbNext;
- m_cbNext += cbSize;
- return (p);
- }
-
- // Can only delete the last unused chunk. no free list.
- void DelChunk(BYTE *p, int cbSize)
- {
- _ASSERTE(p >= m_pbData && p < m_pbData + m_cbNext);
- if (p + cbSize == m_pbData + m_cbNext)
- m_cbNext -= cbSize;
- }
-
- int Size()
- { return (m_cbSize); }
-
- int Offset()
- { return (m_cbNext); }
-
- BYTE *Ptr(int cbOffset = 0)
- {
- _ASSERTE(m_pbData && m_cbSize);
- _ASSERTE(cbOffset < m_cbSize);
- return (m_pbData + cbOffset);
- }
-
- void Clear()
- {
- if (m_pbData)
- free(m_pbData);
- m_pbData = 0;
- m_cbSize = m_cbNext = 0;
- }
-
- private:
- BYTE *m_pbData; // Data pointer.
- int m_cbSize; // Size of current data.
- int m_cbNext; // Next place to write.
- };
-
-
- //*****************************************************************************
- // This implements a hash table and the allocation and management of the
- // records that are being hashed.
- //*****************************************************************************
- template <class M>
- class CHashTableAndData : protected CHashTable
- {
- USHORT m_iFree;
- USHORT m_iEntries;
-
- public:
- CHashTableAndData(
- USHORT iBuckets) : // # of chains we are hashing into.
- CHashTable(iBuckets)
- {
- m_iFree = m_iEntries = 0;
- }
- ~CHashTableAndData()
- {
- if (m_pcEntries != NULL)
- M::Free(m_pcEntries, M::RoundSize(m_iEntries * m_iEntrySize));
- }
-
- //*****************************************************************************
- // This is the second part of construction where we do all of the work that
- // can fail. We also take the array of structs here because the calling class
- // presumably needs to allocate it in its NewInit.
- //*****************************************************************************
- HRESULT NewInit( // Return status.
- USHORT iEntries, // # of entries.
- USHORT iEntrySize, // Size of the entries.
- int iMaxSize); // Max size of data.
-
- //*****************************************************************************
- // Clear the hash table as if there were nothing in it.
- //*****************************************************************************
- void Clear()
- {
- m_iFree = 0;
-
- if (m_iEntries > 0)
- {
- InitFreeChain(0, m_iEntries);
- CHashTable::Clear();
- }
- }
-
- //*****************************************************************************
- //*****************************************************************************
- BYTE *Add(
- USHORT iHash) // Hash value of entry to add.
- {
- FREEHASHENTRY *psEntry;
-
- // Make the table bigger if necessary.
- if (m_iFree == 0xffff && !Grow())
- return (NULL);
-
- // Add the first entry from the free list to the hash chain.
- psEntry = (FREEHASHENTRY *) CHashTable::Add(iHash, m_iFree);
- m_iFree = psEntry->iFree;
- return ((BYTE *) psEntry);
- }
-
- //*****************************************************************************
- // Delete the struct at the specified index in m_pcEntries from the hash chains.
- //*****************************************************************************
- void Delete(
- USHORT iHash, // Hash value of entry to delete.
- USHORT iIndex) // Index of struct in m_pcEntries.
- {
- CHashTable::Delete(iHash, iIndex);
- ((FREEHASHENTRY *) EntryPtr(iIndex))->iFree = m_iFree;
- m_iFree = iIndex;
- }
-
- void Delete(
- USHORT iHash, // Hash value of entry to delete.
- HASHENTRY *psEntry) // The struct to delete.
- {
- CHashTable::Delete(iHash, psEntry);
- ((FREEHASHENTRY *) psEntry)->iFree = m_iFree;
- m_iFree = ItemIndex(psEntry);
- }
-
- private:
- void InitFreeChain(USHORT iStart,USHORT iEnd);
- int Grow();
- };
-
-
- //*****************************************************************************
- // This is the second part of construction where we do all of the work that
- // can fail. We also take the array of structs here because the calling class
- // presumably needs to allocate it in its NewInit.
- //*****************************************************************************
- template<class M>
- HRESULT CHashTableAndData<M>::NewInit(// Return status.
- USHORT iEntries, // # of entries.
- USHORT iEntrySize, // Size of the entries.
- int iMaxSize) // Max size of data.
- {
- BYTE *pcEntries;
- HRESULT hr;
-
- // Allocate the memory for the entries.
- if ((pcEntries = M::Alloc(M::RoundSize(iEntries * iEntrySize),
- M::RoundSize(iMaxSize))) == 0)
- return (E_OUTOFMEMORY);
- m_iEntries = iEntries;
-
- // Init the base table.
- if (FAILED(hr = CHashTable::NewInit(pcEntries, iEntrySize)))
- M::Free(pcEntries, M::RoundSize(iEntries * iEntrySize));
- else
- {
- // Init the free chain.
- m_iFree = 0;
- InitFreeChain(0, iEntries);
- }
- return (hr);
- }
-
- //*****************************************************************************
- // Initialize a range of records such that they are linked together to be put
- // on the free chain.
- //*****************************************************************************
- template<class M>
- void CHashTableAndData<M>::InitFreeChain(
- USHORT iStart, // Index to start initializing.
- USHORT iEnd) // Index to stop initializing
- {
- BYTE *pcPtr;
- _ASSERTE(iEnd > iStart);
-
- pcPtr = m_pcEntries + iStart * m_iEntrySize;
- for (++iStart; iStart < iEnd; ++iStart)
- {
- ((FREEHASHENTRY *) pcPtr)->iFree = iStart;
- pcPtr += m_iEntrySize;
- }
- ((FREEHASHENTRY *) pcPtr)->iFree = 0xffff;
- }
-
- //*****************************************************************************
- // Attempt to increase the amount of space available for the record heap.
- //*****************************************************************************
- template<class M>
- int CHashTableAndData<M>::Grow() // 1 if successful, 0 if not.
- {
- int iCurSize; // Current size in bytes.
- int iEntries; // New # of entries.
-
- _ASSERTE(m_pcEntries != NULL);
- _ASSERTE(m_iFree == 0xffff);
-
- // Compute the current size and new # of entries.
- iCurSize = M::RoundSize(m_iEntries * m_iEntrySize);
- iEntries = (iCurSize + M::GrowSize()) / m_iEntrySize;
-
- // Make sure we stay below 0xffff.
- if (iEntries >= 0xffff) return (0);
-
- // Try to expand the array.
- if (M::Grow(m_pcEntries, iCurSize) == 0)
- return (0);
-
- // Init the newly allocated space.
- InitFreeChain(m_iEntries, iEntries);
- m_iFree = m_iEntries;
- m_iEntries = iEntries;
- return (1);
- }
-
- #define MAKE_ANSIPTR_FROMWIDE(ptrname, widestr) \
- long __l##ptrname = (wcslen(widestr) + 1) * 2 * sizeof(char); \
- CQuickBytes __CQuickBytes##ptrname; \
- __CQuickBytes##ptrname.Alloc(__l##ptrname); \
- WideCharToMultiByte(CP_ACP, 0, widestr, -1, (LPSTR)__CQuickBytes##ptrname.Ptr(), __l##ptrname, NULL, NULL); \
- LPSTR ptrname = (LPSTR)__CQuickBytes##ptrname.Ptr()
-
- #define MAKE_UTF8PTR_FROMWIDE(ptrname, widestr) \
- long __l##ptrname = (long)((wcslen(widestr) + 1) * 2 * sizeof(char)); \
- LPSTR ptrname = (LPSTR)alloca(__l##ptrname); \
- WideCharToMultiByte(CP_ACP, 0, widestr, -1, ptrname, __l##ptrname, NULL, NULL);
-
- // NOTE: CP_ACP is not correct, but Win95 does not support CP_UTF8. For this
- // particular application, CP_ACP is "close enough".
- #define MAKE_WIDEPTR_FROMUTF8(ptrname, utf8str) \
- long __l##ptrname; \
- LPWSTR ptrname; \
- __l##ptrname = MultiByteToWideChar(CP_ACP, 0, utf8str, -1, 0, 0); \
- ptrname = (LPWSTR) alloca(__l##ptrname*sizeof(WCHAR)); \
- MultiByteToWideChar(CP_ACP, 0, utf8str, -1, ptrname, __l##ptrname);
-
-
- #define TESTANDRETURN(test, hrVal) \
- _ASSERTE(test); \
- if (! (test)) \
- return hrVal;
-
- #define TESTANDRETURNPOINTER(pointer) \
- TESTANDRETURN(pointer!=NULL, E_POINTER)
-
- #define TESTANDRETURNMEMORY(pointer) \
- TESTANDRETURN(pointer!=NULL, E_OUTOFMEMORY)
-
- #define TESTANDRETURNHR(hr) \
- TESTANDRETURN(SUCCEEDED(hr), hr)
-
- #define TESTANDRETURNARG(argtest) \
- TESTANDRETURN(argtest, E_INVALIDARG)
-
- #endif // __DEBUGGERUTIL_H__
-