mirror of
https://github.com/DrBeef/JKXR.git
synced 2024-12-02 09:02:09 +00:00
222 lines
6.8 KiB
C
222 lines
6.8 KiB
C
|
/*
|
||
|
===========================================================================
|
||
|
Copyright (C) 2000 - 2013, Raven Software, Inc.
|
||
|
Copyright (C) 2001 - 2013, Activision, Inc.
|
||
|
Copyright (C) 2013 - 2015, OpenJK contributors
|
||
|
|
||
|
This file is part of the OpenJK source code.
|
||
|
|
||
|
OpenJK is free software; you can redistribute it and/or modify it
|
||
|
under the terms of the GNU General Public License version 2 as
|
||
|
published by the Free Software Foundation.
|
||
|
|
||
|
This program is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
GNU General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License
|
||
|
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||
|
===========================================================================
|
||
|
*/
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||
|
// 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
|