123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- ////////////////////////////////////////////////////////////////////////////////////////
- // RAVEN STANDARD TEMPLATE LIBRARY
- // (c) 2002 Activision
- //
- //
- // Hash Pool
- // ---------
- // The hash pool stores raw data of variable size. It uses a hash table to check for
- // redundant data, and upon finding any, will return the existing handle. Otherwise
- // it copies the data to memory and returns a new handle.
- //
- //
- // NOTES:
- //
- //
- //
- ////////////////////////////////////////////////////////////////////////////////////////
- #if !defined(RATL_HASH_POOL_VS_INC)
- #define RATL_HASH_POOL_VS_INC
- ////////////////////////////////////////////////////////////////////////////////////////
- // Includes
- ////////////////////////////////////////////////////////////////////////////////////////
- #if !defined(RATL_COMMON_INC)
- #include "ratl_common.h"
- #endif
- namespace ratl
- {
- ////////////////////////////////////////////////////////////////////////////////////////
- // The Hash Pool
- ////////////////////////////////////////////////////////////////////////////////////////
- template <int SIZE, int SIZE_HANDLES>
- class hash_pool
- {
- int mHandles[SIZE_HANDLES]; // each handle holds the start index of it's data
- int mDataAlloc; // where the next chunck of data will go
- char mData[SIZE];
- #ifdef _DEBUG
- int mFinds; // counts how many total finds have run
- int mCurrentCollisions; // counts how many collisions on the last find
- int mTotalCollisions; // counts the total number of collisions
- int mTotalAllocs;
- #endif
- ////////////////////////////////////////////////////////////////////////////////////
- // This function searches for a handle which already stores the data (assuming the
- // handle is a hash within range SIZE_HANDLES).
- //
- // If it failes, it returns false, and the handle passed in points to the next
- // free slot.
- ////////////////////////////////////////////////////////////////////////////////////
- bool find_existing(int& handle, const void* data, int datasize)
- {
- #ifdef _DEBUG
- mFinds++;
- mCurrentCollisions = 0;
- #endif
- while (mHandles[handle]) // So long as a handle exists there
- {
- if (mem::eql((void*)(&mData[mHandles[handle]]), data, datasize))
- {
- return true; // found
- }
- handle=(handle+1)&(SIZE_HANDLES-1); // incriment the handle
- #ifdef _DEBUG
- mCurrentCollisions ++;
- mTotalCollisions ++;
- //assert(mCurrentCollisions < 16); // If We Had 16+ Collisions, Hash May Be Inefficient.
- // Evaluate SIZE and SIZEHANDLES
- #endif
- }
- return false; // failed to find
- }
- ////////////////////////////////////////////////////////////////////////////////////
- // A simple hash function for the range of [0, SIZE_HANDLES]
- ////////////////////////////////////////////////////////////////////////////////////
- int hash(const void* data, int datasize)
- {
- int h=0;
- for (int i=0; i<datasize; i++)
- {
- h += ((const char*)(data))[i] * (i + 119); // 119. Prime Number?
- }
- h &= SIZE_HANDLES - 1; // zero out bits beyoned SIZE_HANDLES
- return h;
- }
- public:
- hash_pool()
- {
- clear();
- }
- ////////////////////////////////////////////////////////////////////////////////////
- // The Number Of Bytes Allocated
- ////////////////////////////////////////////////////////////////////////////////////
- int size() const
- {
- return mDataAlloc;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- // Check To See If This Memory Pool Is Empty
- ////////////////////////////////////////////////////////////////////////////////////
- bool empty() const
- {
- return (mDataAlloc==1);
- }
- ////////////////////////////////////////////////////////////////////////////////////
- // Check To See If This Memory Pool Has Enough Space Left For (minimum) Bytes
- ////////////////////////////////////////////////////////////////////////////////////
- bool full(int minimum) const
- {
- return ((SIZE - mDataAlloc)<minimum);
- }
- ////////////////////////////////////////////////////////////////////////////////////
- // Clear - Removes all allocation information - Note! DOES NOT CLEAR MEMORY
- ////////////////////////////////////////////////////////////////////////////////////
- void clear()
- {
- mData[0] = 0;
- mDataAlloc = 1;
- for (int i=0; i<SIZE_HANDLES; i++)
- {
- mHandles[i] = 0;
- }
- #ifdef _DEBUG
- mFinds = 0;
- mCurrentCollisions = 0;
- mTotalCollisions = 0;
- mTotalAllocs = 0;
- #endif
- }
- ////////////////////////////////////////////////////////////////////////////////////
- // This is the primary functionality of the hash pool. It will search for existing
- // data of the same size, and failing to find any, it will append the data to the
- // memory.
- //
- // In both cases, it gives you a handle to look up the data later.
- ////////////////////////////////////////////////////////////////////////////////////
- int get_handle(const void* data, int datasize)
- {
- int handle = hash(data, datasize); // Initialize Our Handle By Hash Fcn
- if (!find_existing(handle, data, datasize))
- {
- assert(mDataAlloc+datasize < SIZE); // Is There Enough Memory?
- #ifdef _DEBUG
- mTotalAllocs++;
- #endif
- mem::cpy((void*)(&mData[mDataAlloc]), data, datasize);// Copy Data To Memory
- mHandles[handle] = mDataAlloc; // Mark Memory In Hash Tbl
- mDataAlloc += datasize; // Adjust Next Alloc Location
- }
- return handle; // Return The Hash Tbl handleess
- }
- ////////////////////////////////////////////////////////////////////////////////////
- // Constant Access Operator
- ////////////////////////////////////////////////////////////////////////////////////
- const void* operator[](int handle) const
- {
- assert(handle>=0 && handle<SIZE_HANDLES);
- return &(mData[mHandles[handle]]);
- }
- #ifdef _DEBUG
- float average_collisions() {return ((float)mTotalCollisions / (float)mFinds);}
- int total_allocs() {return mTotalAllocs;}
- int total_finds() {return mFinds;}
- int total_collisions() {return mTotalCollisions;}
- #endif
- };
- }
- #endif
|