Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

539 lines
13 KiB

/*++
Copyright (c) 1985 - 1999, Microsoft Corporation
Module Name:
cstring.h
Abstract:
This file defines the CString Class.
and CMapStringToOb<VALUE, ARG_VALUE> template class.
Author:
Revision History:
Notes:
--*/
#ifndef _CSTRING_H_
#define _CSTRING_H_
#include "template.h"
/////////////////////////////////////////////////////////////////////////////
// Globals
extern TCHAR afxChNil;
extern LPCTSTR _afxPchNil;
#define afxEmptyString ((CString&)*(CString*)&_afxPchNil)
/////////////////////////////////////////////////////////////////////////////
// CStringData
struct CStringData
{
long nRefs; // reference count
int nDataLength; // length of data (including terminator)
int nAllocLength; // length of allocation
// TCHAR data[nAllocLength]
TCHAR* data() // TCHAR* to managed data
{
return (TCHAR*)(this+1);
}
};
/////////////////////////////////////////////////////////////////////////////
// CString
class CString
{
public:
// Constructors
// constructs empty CString
CString();
// copy constructor
CString(const CString& stringSrc);
// from an ANSI string (converts to TCHAR)
CString(LPCSTR lpsz);
// subset of characters from an ANSI string (converts to TCHAR)
CString(LPCSTR lpch, int nLength);
// return pointer to const string
operator LPCTSTR() const;
// overloaded assignment
// ref-counted copy from another CString
const CString& operator=(const CString& stringSrc);
// set string content to single character
const CString& operator=(TCHAR ch);
// copy string content from ANSI string (converts to TCHAR)
const CString& operator=(LPCSTR lpsz);
// Attributes & Operations
// string comparison
// straight character comparison
int Compare(LPCTSTR lpsz) const;
// compare ignoring case
int CompareNoCase(LPCTSTR lpsz) const;
// simple sub-string extraction
// return nCount characters starting at zero-based nFirst
CString Mid(int nFirst, int nCount) const;
// return all characters starting at zero-based nFirst
CString Mid(int nFirst) const;
// searching
// find character starting at left, -1 if not found
int Find(TCHAR ch) const;
// find character starting at zero-based index and going right
int Find(TCHAR ch, int nStart) const;
// Implementation
public:
~CString();
private:
LPTSTR m_pchData; // pointer to ref counted string data
// implementation helpers
CStringData* GetData() const;
void Init();
void AllocCopy(CString& dest, int nCopyLen, int nCopyIndex, int nExtraLen) const;
void AllocBuffer(int nLen);
void AssignCopy(int nSrcLen, LPCTSTR lpszSrcData);
void AllocBeforeWrite(int nLen);
void Release();
static void PASCAL Release(CStringData* pData);
static int PASCAL SafeStrlen(LPCTSTR lpsz);
static void FreeData(CStringData* pData);
};
inline
CStringData*
CString::GetData(
) const
{
ASSERT(m_pchData != NULL);
return ((CStringData*)m_pchData)-1;
}
inline
void
CString::Init(
)
{
m_pchData = afxEmptyString.m_pchData;
}
// Compare helpers
bool operator==(const CString& s1, const CString& s2);
bool operator==(const CString& s1, LPCTSTR s2);
bool operator==(LPCTSTR s1, const CString& s2);
/////////////////////////////////////////////////////////////////////////////
// Special implementation for CStrings
// it is faster to bit-wise copy a CString than to call an offical
// constructor - since an empty CString can be bit-wise copied
static
void
ConstructElement(
CString* pNewData
)
{
memcpy(pNewData, &afxEmptyString, sizeof(CString));
}
static
void
DestructElement(
CString* pOldData
)
{
pOldData->~CString();
}
/////////////////////////////////////////////////////////////////////////////
// CMapStringToOb<VALUE, ARG_VALUE>
template<class VALUE, class ARG_VALUE>
class CMapStringToOb
{
public:
CMapStringToOb(int nBlockSize = 10);
~CMapStringToOb();
INT_PTR GetCount() const;
BOOL Lookup(LPCTSTR key, VALUE& rValue) const;
VALUE& operator[](LPCTSTR key);
void SetAt(LPCTSTR key, ARG_VALUE newValue);
BOOL RemoveKey(LPCTSTR key);
void RemoveAll();
POSITION GetStartPosition() const;
void GetNextAssoc(POSITION& rNextPosition, CString& rKey, VALUE& rValue) const;
void InitHashTable(UINT hashSize, BOOL bAllocNow = TRUE);
protected:
// Overridables: special non-virtual (see map implementation for details)
// Routine used to user-provided hash keys
UINT HashKey(LPCTSTR key) const;
private:
// Association
struct CAssoc {
CAssoc* pNext;
UINT nHashValue; // needed for efficient iteration
CString key;
VALUE value;
};
private:
CAssoc* NewAssoc();
void FreeAssoc(CAssoc*);
CAssoc* GetAssocAt(LPCTSTR, UINT&) const;
private:
CAssoc** m_pHashTable;
UINT m_nHashTableSize;
INT_PTR m_nCount;
CAssoc* m_pFreeList;
struct CPlex* m_pBlocks;
int m_nBlockSize;
};
template<class VALUE, class ARG_VALUE>
INT_PTR
CMapStringToOb<VALUE, ARG_VALUE>::GetCount(
) const
{
return m_nCount;
}
template<class VALUE, class ARG_VALUE>
void
CMapStringToOb<VALUE, ARG_VALUE>::SetAt(
LPCTSTR key,
ARG_VALUE newValue
)
{
(*this)[key] = newValue;
}
template<class VALUE, class ARG_VALUE>
CMapStringToOb<VALUE, ARG_VALUE>::CMapStringToOb(
int nBlockSize
)
{
ASSERT(nBlockSize > 0);
m_pHashTable = NULL;
m_nHashTableSize = 17; // default size
m_nCount = 0;
m_pFreeList = NULL;
m_pBlocks = NULL;
m_nBlockSize = nBlockSize;
}
template<class VALUE, class ARG_VALUE>
UINT
CMapStringToOb<VALUE, ARG_VALUE>::HashKey(
LPCTSTR key
) const
{
UINT nHash = 0;
while (*key)
nHash = (nHash<<5) + nHash + *key++;
return nHash;
}
template<class VALUE, class ARG_VALUE>
void
CMapStringToOb<VALUE, ARG_VALUE>::InitHashTable(
UINT nHashSize,
BOOL bAllocNow
)
{
ASSERT(m_nCount == 0);
ASSERT(nHashSize > 0);
if (m_pHashTable != NULL) {
// free hash table
delete[] m_pHashTable;
m_pHashTable = NULL;
}
if (bAllocNow) {
m_pHashTable = new CAssoc* [nHashSize];
memset(m_pHashTable, 0, sizeof(CAssoc*) * nHashSize);
}
m_nHashTableSize = nHashSize;
}
template<class VALUE, class ARG_VALUE>
void
CMapStringToOb<VALUE, ARG_VALUE>::RemoveAll(
)
{
if (m_pHashTable != NULL) {
// destroy elements (values and keys)
for (UINT nHash = 0; nHash < m_nHashTableSize; nHash++) {
CAssoc* pAssoc;
for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL; pAssoc = pAssoc->pNext) {
DestructElements<VALUE>(&pAssoc->value, 1);
DestructElement(&pAssoc->key); // free up string data
}
}
}
// free hash table
delete[] m_pHashTable;
m_pHashTable = NULL;
m_nCount = 0;
m_pFreeList = NULL;
m_pBlocks->FreeDataChain();
m_pBlocks = NULL;
}
template<class VALUE, class ARG_VALUE>
CMapStringToOb<VALUE, ARG_VALUE>::~CMapStringToOb(
)
{
RemoveAll();
ASSERT(m_nCount == 0);
}
template<class VALUE, class ARG_VALUE>
typename CMapStringToOb<VALUE, ARG_VALUE>::CAssoc*
CMapStringToOb<VALUE, ARG_VALUE>::NewAssoc(
)
{
if (m_pFreeList == NULL) {
// add another block
CPlex* newBlock = CPlex::Create(m_pBlocks, m_nBlockSize, sizeof(CMapStringToOb::CAssoc));
// chain them into free list;
CMapStringToOb::CAssoc* pAssoc = (CMapStringToOb::CAssoc*) newBlock->data();
// free in reverse order to make it easier to debug
pAssoc += m_nBlockSize - 1;
for (int i = m_nBlockSize-1; i >= 0; i--, pAssoc--) {
pAssoc->pNext = m_pFreeList;
m_pFreeList = pAssoc;
}
}
ASSERT(m_pFreeList != NULL); // we must have something
CMapStringToOb::CAssoc* pAssoc = m_pFreeList;
m_pFreeList = m_pFreeList->pNext;
m_nCount++;
ASSERT(m_nCount > 0); // make sure we don't overflow
memcpy(&pAssoc->key, &afxEmptyString, sizeof(CString));
ConstructElements<VALUE>(&pAssoc->value, 1); // special construct values
return pAssoc;
}
template<class VALUE, class ARG_VALUE>
void
CMapStringToOb<VALUE, ARG_VALUE>::FreeAssoc(
CAssoc* pAssoc
)
{
DestructElements<VALUE>(&pAssoc->value, 1);
DestructElement(&pAssoc->key); // free up string data
pAssoc->pNext = m_pFreeList;
m_pFreeList = pAssoc;
m_nCount--;
ASSERT(m_nCount >= 0); // make sure we don't underflow
// if no more elements, cleanup completely
if (m_nCount == 0)
RemoveAll();
}
template<class VALUE, class ARG_VALUE>
typename CMapStringToOb<VALUE, ARG_VALUE>::CAssoc*
CMapStringToOb<VALUE, ARG_VALUE>::GetAssocAt(
LPCTSTR key,
UINT& nHash
) const
{
nHash = HashKey(key) % m_nHashTableSize;
if (m_pHashTable == NULL)
return NULL;
// see if it exists
CAssoc* pAssoc;
for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL; pAssoc = pAssoc->pNext) {
if (pAssoc->key == key)
return pAssoc;
}
return NULL;
}
template<class VALUE, class ARG_VALUE>
BOOL
CMapStringToOb<VALUE, ARG_VALUE>::Lookup(
LPCTSTR key,
VALUE& rValue
) const
{
UINT nHash;
CAssoc* pAssoc = GetAssocAt(key, nHash);
if (pAssoc == NULL)
return FALSE; // not in map
rValue = pAssoc->value;
return TRUE;
}
template<class VALUE, class ARG_VALUE>
VALUE&
CMapStringToOb<VALUE, ARG_VALUE>::operator[](
LPCTSTR key
)
{
UINT nHash;
CAssoc* pAssoc;
if ((pAssoc = GetAssocAt(key, nHash)) == NULL) {
if (m_pHashTable == NULL)
InitHashTable(m_nHashTableSize);
// it doesn't exist, add a new Association
pAssoc = NewAssoc();
pAssoc->nHashValue = nHash;
pAssoc->key = key;
// 'pAssoc->value' is a constructed object, nothing more
// put into hash table
pAssoc->pNext = m_pHashTable[nHash];
m_pHashTable[nHash] = pAssoc;
}
return pAssoc->value; // return new reference
}
template<class VALUE, class ARG_VALUE>
BOOL
CMapStringToOb<VALUE, ARG_VALUE>::RemoveKey(
LPCTSTR key
)
{
if (m_pHashTable == NULL)
return FALSE; // nothing in the table
CAssoc** ppAssocPrev;
ppAssocPrev = &m_pHashTable[HashKey(key) % m_nHashTableSize];
CAssoc* pAssoc;
for (pAssoc = *ppAssocPrev; pAssoc != NULL; pAssoc = pAssoc->pNext) {
if (pAssoc->key == key)) {
// remove it
*ppAssocPrev = pAssoc->pNext; // remove from list
FreeAssoc(pAssoc);
return TRUE;
}
ppAssocPrev = &pAssoc->pNext;
}
return FALSE; // not found
}
template<class VALUE, class ARG_VALUE>
POSITION
CMapStringToOb<VALUE, ARG_VALUE>::GetStartPosition(
) const
{
return (m_nCount == 0) ? NULL : BEFORE_START_POSITION;
}
template<class VALUE, class ARG_VALUE>
void
CMapStringToOb<VALUE, ARG_VALUE>::GetNextAssoc(
POSITION& rNextPosition,
CString& rKey,
VALUE& rValue
) const
{
ASSERT(m_pHashTable != NULL); // never call on empty map
CAssoc* pAssocRet = (CAssoc*)rNextPosition;
ASSERT(pAssocRet != NULL);
if (pAssocRet == (CAssoc*) BEFORE_START_POSITION) {
// find the first association
for (UINT nBucket = 0; nBucket < m_nHashTableSize; nBucket++)
if ((pAssocRet = m_pHashTable[nBucket]) != NULL)
break;
ASSERT(pAssocRet != NULL); // must find something
}
// find next association
CAssoc* pAssocNext;
if ((pAssocNext = pAssocRet->pNext) == NULL) {
// go to next bucket
for (UINT nBucket = pAssocRet->nHashValue + 1; nBucket < m_nHashTableSize; nBucket++)
if ((pAssocNext = m_pHashTable[nBucket]) != NULL)
break;
}
rNextPosition = (POSITION) pAssocNext;
// fill in return data
rKey = pAssocRet->key;
rValue = pAssocRet->value;
}
#endif // _CSTRING_H_