hash_pool_vs.h 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. ////////////////////////////////////////////////////////////////////////////////////////
  2. // RAVEN STANDARD TEMPLATE LIBRARY
  3. // (c) 2002 Activision
  4. //
  5. //
  6. // Hash Pool
  7. // ---------
  8. // The hash pool stores raw data of variable size. It uses a hash table to check for
  9. // redundant data, and upon finding any, will return the existing handle. Otherwise
  10. // it copies the data to memory and returns a new handle.
  11. //
  12. //
  13. // NOTES:
  14. //
  15. //
  16. //
  17. ////////////////////////////////////////////////////////////////////////////////////////
  18. #if !defined(RATL_HASH_POOL_VS_INC)
  19. #define RATL_HASH_POOL_VS_INC
  20. ////////////////////////////////////////////////////////////////////////////////////////
  21. // Includes
  22. ////////////////////////////////////////////////////////////////////////////////////////
  23. #if !defined(RATL_COMMON_INC)
  24. #include "ratl_common.h"
  25. #endif
  26. namespace ratl
  27. {
  28. ////////////////////////////////////////////////////////////////////////////////////////
  29. // The Hash Pool
  30. ////////////////////////////////////////////////////////////////////////////////////////
  31. template <int SIZE, int SIZE_HANDLES>
  32. class hash_pool
  33. {
  34. int mHandles[SIZE_HANDLES]; // each handle holds the start index of it's data
  35. int mDataAlloc; // where the next chunck of data will go
  36. char mData[SIZE];
  37. #ifdef _DEBUG
  38. int mFinds; // counts how many total finds have run
  39. int mCurrentCollisions; // counts how many collisions on the last find
  40. int mTotalCollisions; // counts the total number of collisions
  41. int mTotalAllocs;
  42. #endif
  43. ////////////////////////////////////////////////////////////////////////////////////
  44. // This function searches for a handle which already stores the data (assuming the
  45. // handle is a hash within range SIZE_HANDLES).
  46. //
  47. // If it failes, it returns false, and the handle passed in points to the next
  48. // free slot.
  49. ////////////////////////////////////////////////////////////////////////////////////
  50. bool find_existing(int& handle, const void* data, int datasize)
  51. {
  52. #ifdef _DEBUG
  53. mFinds++;
  54. mCurrentCollisions = 0;
  55. #endif
  56. while (mHandles[handle]) // So long as a handle exists there
  57. {
  58. if (mem::eql((void*)(&mData[mHandles[handle]]), data, datasize))
  59. {
  60. return true; // found
  61. }
  62. handle=(handle+1)&(SIZE_HANDLES-1); // incriment the handle
  63. #ifdef _DEBUG
  64. mCurrentCollisions ++;
  65. mTotalCollisions ++;
  66. //assert(mCurrentCollisions < 16); // If We Had 16+ Collisions, Hash May Be Inefficient.
  67. // Evaluate SIZE and SIZEHANDLES
  68. #endif
  69. }
  70. return false; // failed to find
  71. }
  72. ////////////////////////////////////////////////////////////////////////////////////
  73. // A simple hash function for the range of [0, SIZE_HANDLES]
  74. ////////////////////////////////////////////////////////////////////////////////////
  75. int hash(const void* data, int datasize)
  76. {
  77. int h=0;
  78. for (int i=0; i<datasize; i++)
  79. {
  80. h += ((const char*)(data))[i] * (i + 119); // 119. Prime Number?
  81. }
  82. h &= SIZE_HANDLES - 1; // zero out bits beyoned SIZE_HANDLES
  83. return h;
  84. }
  85. public:
  86. hash_pool()
  87. {
  88. clear();
  89. }
  90. ////////////////////////////////////////////////////////////////////////////////////
  91. // The Number Of Bytes Allocated
  92. ////////////////////////////////////////////////////////////////////////////////////
  93. int size() const
  94. {
  95. return mDataAlloc;
  96. }
  97. ////////////////////////////////////////////////////////////////////////////////////
  98. // Check To See If This Memory Pool Is Empty
  99. ////////////////////////////////////////////////////////////////////////////////////
  100. bool empty() const
  101. {
  102. return (mDataAlloc==1);
  103. }
  104. ////////////////////////////////////////////////////////////////////////////////////
  105. // Check To See If This Memory Pool Has Enough Space Left For (minimum) Bytes
  106. ////////////////////////////////////////////////////////////////////////////////////
  107. bool full(int minimum) const
  108. {
  109. return ((SIZE - mDataAlloc)<minimum);
  110. }
  111. ////////////////////////////////////////////////////////////////////////////////////
  112. // Clear - Removes all allocation information - Note! DOES NOT CLEAR MEMORY
  113. ////////////////////////////////////////////////////////////////////////////////////
  114. void clear()
  115. {
  116. mData[0] = 0;
  117. mDataAlloc = 1;
  118. for (int i=0; i<SIZE_HANDLES; i++)
  119. {
  120. mHandles[i] = 0;
  121. }
  122. #ifdef _DEBUG
  123. mFinds = 0;
  124. mCurrentCollisions = 0;
  125. mTotalCollisions = 0;
  126. mTotalAllocs = 0;
  127. #endif
  128. }
  129. ////////////////////////////////////////////////////////////////////////////////////
  130. // This is the primary functionality of the hash pool. It will search for existing
  131. // data of the same size, and failing to find any, it will append the data to the
  132. // memory.
  133. //
  134. // In both cases, it gives you a handle to look up the data later.
  135. ////////////////////////////////////////////////////////////////////////////////////
  136. int get_handle(const void* data, int datasize)
  137. {
  138. int handle = hash(data, datasize); // Initialize Our Handle By Hash Fcn
  139. if (!find_existing(handle, data, datasize))
  140. {
  141. assert(mDataAlloc+datasize < SIZE); // Is There Enough Memory?
  142. #ifdef _DEBUG
  143. mTotalAllocs++;
  144. #endif
  145. mem::cpy((void*)(&mData[mDataAlloc]), data, datasize);// Copy Data To Memory
  146. mHandles[handle] = mDataAlloc; // Mark Memory In Hash Tbl
  147. mDataAlloc += datasize; // Adjust Next Alloc Location
  148. }
  149. return handle; // Return The Hash Tbl handleess
  150. }
  151. ////////////////////////////////////////////////////////////////////////////////////
  152. // Constant Access Operator
  153. ////////////////////////////////////////////////////////////////////////////////////
  154. const void* operator[](int handle) const
  155. {
  156. assert(handle>=0 && handle<SIZE_HANDLES);
  157. return &(mData[mHandles[handle]]);
  158. }
  159. #ifdef _DEBUG
  160. float average_collisions() {return ((float)mTotalCollisions / (float)mFinds);}
  161. int total_allocs() {return mTotalAllocs;}
  162. int total_finds() {return mFinds;}
  163. int total_collisions() {return mTotalCollisions;}
  164. #endif
  165. };
  166. }
  167. #endif