⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 growablemap.h

📁 Data Replication Prototype Using ADO
💻 H
字号:
#ifndef GrowableMap_h_
#define GrowableMap_h_

template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
class CGrowableMap : public CObject
{

enum { START_SIZE = 16 }; 

protected:
	// Association
	struct CAssoc
	{
		CAssoc* pNext;
		UINT nHashValue;  // needed for efficient iteration
		KEY key;
		VALUE value;
	};
public:
	CGrowableMap(int nBlockSize = 10) 
	{ 
		m_pHashTable = NULL;
		m_nHashTableSize = START_SIZE; 
		m_nCount = 0;
		m_pFreeList = NULL;
		m_pBlocks = NULL;
		m_nBlockSize = nBlockSize;
	}


	BOOL Lookup(ARG_KEY key, VALUE& rValue) const
	{
		ASSERT_VALID(this);

		UINT nHash;
		CAssoc* pAssoc = GetAssocAt(key, nHash);
		if (pAssoc == NULL)
			return FALSE;  // not in map

		rValue = pAssoc->value;
		return TRUE;
	}

	VALUE& operator[](ARG_KEY key)
	{
		ASSERT_VALID(this);

		UINT nHash;
		CAssoc* pAssoc;
		if ((pAssoc = GetAssocAt(key, nHash)) == NULL)
		{
			if (m_pHashTable == NULL)
				InitHashTable(m_nHashTableSize);
			else if (m_nCount > signed(m_nHashTableSize * 2))
			{
				CAssoc** pHashTable = new CAssoc* [m_nHashTableSize * 2];
				memset(pHashTable+m_nHashTableSize, 0, sizeof(CAssoc*) * m_nHashTableSize);
				memcpy(pHashTable, m_pHashTable, sizeof(CAssoc*) * m_nHashTableSize);
				delete m_pHashTable;
				m_pHashTable = pHashTable;
				m_nHashTableSize *= 2;

				nHash = HashKey_(key) % 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
	}

	void SetAt(ARG_KEY key, ARG_VALUE newValue)
		{ (*this)[key] = newValue; }

	void RemoveAll() 
	{ 
		ASSERT_VALID(this);

		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)
				{
					pAssoc->CAssoc::~CAssoc();
					//DestructElements<VALUE>(&pAssoc->value, 1);
					//DestructElements<KEY>(&pAssoc->key, 1);
				}
			}
		}

		// free hash table
		delete[] m_pHashTable;
		m_pHashTable = NULL;

		m_nCount = 0;
		m_pFreeList = NULL;
		m_pBlocks->FreeDataChain();
		m_pBlocks = NULL;

		m_nHashTableSize = START_SIZE; 
	}

	int GetCount() const { return m_nCount; }

	BOOL IsEmpty() const { return m_nCount == 0; }

	POSITION GetStartPosition() const
	{ return (m_nCount == 0) ? NULL : BEFORE_START_POSITION; }

	void GetNextAssoc(POSITION& rNextPosition, KEY& rKey, VALUE& rValue) const
	{
		ASSERT_VALID(this);
		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
		ASSERT(AfxIsValidAddress(pAssocRet, sizeof(CAssoc)));
		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;
	}

	void InitHashTable(UINT nHashSize, BOOL bAllocNow = TRUE)
	//
	// Used to force allocation of a hash table or to override the default
	//   hash table size of (which is fairly small)
	{
		ASSERT_VALID(this);
		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;
	}

// Implementation
protected:
	CAssoc** m_pHashTable;
	UINT m_nHashTableSize;
	int m_nCount;
	CAssoc* m_pFreeList;
	struct CPlex* m_pBlocks;
	int m_nBlockSize;

	static UINT HashKey_(ARG_KEY key) 
	{
		return (HashKey/*<ARG_KEY>*/(key) * 2654435761UL) >> 11;
	}

	CAssoc* GetAssocAt(ARG_KEY key, UINT& nHash) const
	// find association (or return NULL)
	{
		UINT nHashKey = HashKey_(key);
		nHash = nHashKey % m_nHashTableSize;

		if (m_pHashTable == NULL)
			return NULL;

		// see if it exists
		for (CAssoc* pAssoc = m_pHashTable[nHash]; pAssoc != NULL; pAssoc = pAssoc->pNext)
		{
			if (CompareElements(&pAssoc->key, &key))
				return pAssoc;
		}

		UINT nHashTableSize = m_nHashTableSize;
		UINT nOldHash = nHash;
		while(nHashTableSize > START_SIZE)
		{
			nHashTableSize /= 2;
			if(nOldHash >= nHashTableSize)
			{
				nOldHash = nHashKey % nHashTableSize;
				CAssoc* pAssoc;
				for(CAssoc** ppAssoc = m_pHashTable + nOldHash
				; (pAssoc = *ppAssoc) != NULL
				; ppAssoc = &(pAssoc->pNext))
				{
					if (CompareElements(&pAssoc->key, &key))
					{
						pAssoc->nHashValue = nHash;
						*ppAssoc = pAssoc->pNext;
						pAssoc->pNext = m_pHashTable[nHash];
						m_pHashTable[nHash] = pAssoc;
						return pAssoc;
					}
				}
			}
		}
		ASSERT(START_SIZE == nHashTableSize);

		return NULL;
	}

	CAssoc* NewAssoc()
	{
		if (m_pFreeList == NULL)
		{
			// add another block
			CPlex* newBlock = CPlex::Create(m_pBlocks, m_nBlockSize, sizeof(CAssoc));
			// chain them into free list
			CAssoc* pAssoc = (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

		CAssoc* pAssoc = m_pFreeList;
		m_pFreeList = m_pFreeList->pNext;
		m_nCount++;
		ASSERT(m_nCount > 0);  // make sure we don't overflow
		::new(pAssoc) CAssoc();
		//ConstructElements<KEY>(&pAssoc->key, 1);
		//ConstructElements<VALUE>(&pAssoc->value, 1);   // special construct values
		return pAssoc;
	}

//	void FreeAssoc(CAssoc* pAssoc)
//	{
//		DestructElements<VALUE>(&pAssoc->value, 1);
//		DestructElements<KEY>(&pAssoc->key, 1);
//		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();
//	}

public:
	~CGrowableMap()
	{
		RemoveAll();
		ASSERT(m_nCount == 0);
	}
};


#endif //GrowableMap_h_

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -