mirror of
https://github.com/DrBeef/JKXR.git
synced 2024-11-23 12:32:26 +00:00
302 lines
10 KiB
C
302 lines
10 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
|
||
|
//
|
||
|
//
|
||
|
// Handle Pool
|
||
|
// -----------
|
||
|
// The memory pool class is a simple routine for constant time allocation and deallocation
|
||
|
// from a fixed size pool of objects. The class uses a simple array to hold the actual
|
||
|
// data, a queue for the free list, and a bit field to mark which spots in the array
|
||
|
// are allocated.
|
||
|
//
|
||
|
// In addition to the standard memory pool features, this Handle Pool provides a fast
|
||
|
// iterator, asserts on attempting to access unused data, and a unique ID "handle" for
|
||
|
// the external system to use.
|
||
|
//
|
||
|
//
|
||
|
//
|
||
|
// NOTES:
|
||
|
//
|
||
|
//
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||
|
#if !defined(RATL_HANDLE_POOL_VS_INC)
|
||
|
#define RATL_HANDLE_POOL_VS_INC
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||
|
// Includes
|
||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||
|
#if !defined(RATL_COMMON_INC)
|
||
|
#include "ratl_common.h"
|
||
|
#endif
|
||
|
#if !defined(RATL_POOL_VS_INC)
|
||
|
#include "pool_vs.h"
|
||
|
#endif
|
||
|
|
||
|
namespace ratl
|
||
|
{
|
||
|
|
||
|
|
||
|
template <class T>
|
||
|
class handle_pool_base : public pool_root<T>
|
||
|
{
|
||
|
public:
|
||
|
typedef T TStorageTraits;
|
||
|
typedef typename T::TValue TTValue;
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
// Capacity Enum
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
static const int CAPACITY = T::CAPACITY;
|
||
|
|
||
|
private:
|
||
|
int mHandles[CAPACITY];
|
||
|
int mMASK_HANDLE_TO_INDEX;
|
||
|
int mMASK_NUM_BITS;
|
||
|
|
||
|
void IncHandle(int index)
|
||
|
{
|
||
|
mHandles[index] += (1<<mMASK_NUM_BITS);
|
||
|
if (mHandles[index]<0)
|
||
|
{
|
||
|
// we rolled over
|
||
|
mHandles[index] = index; // Reset The ID Counter
|
||
|
mHandles[index] |= (1<<mMASK_NUM_BITS);
|
||
|
}
|
||
|
}
|
||
|
public:
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
// Constructor
|
||
|
//
|
||
|
// We need a routine to calculate the MASK used to convert a handle to an index and
|
||
|
// the number of bits needed to shift by.
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
handle_pool_base()
|
||
|
{
|
||
|
mMASK_HANDLE_TO_INDEX = 0;
|
||
|
mMASK_NUM_BITS = 0;
|
||
|
|
||
|
int value=CAPACITY-1;
|
||
|
while(value)
|
||
|
{
|
||
|
value>>= 1;
|
||
|
|
||
|
mMASK_HANDLE_TO_INDEX <<= 1;
|
||
|
mMASK_HANDLE_TO_INDEX |= 1;
|
||
|
mMASK_NUM_BITS++;
|
||
|
}
|
||
|
for (int i=0; i<CAPACITY; i++)
|
||
|
{
|
||
|
#ifdef _DEBUG
|
||
|
mHandles[i] = i; // Reset The ID Counter
|
||
|
mHandles[i] |= ((++HandleSaltValue)<<mMASK_NUM_BITS);
|
||
|
#else
|
||
|
mHandles[i] = i; // Reset The ID Counter
|
||
|
mHandles[i] |= (1<<mMASK_NUM_BITS);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
// Clear - Removes all allocation information
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
void clear()
|
||
|
{
|
||
|
pool_root<T>::clear();
|
||
|
// note that we do not refill the handles cause we want old handles to still be stale
|
||
|
for (int i=0; i<CAPACITY; i++)
|
||
|
{
|
||
|
IncHandle(i);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
// Constant Accessor
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
const TTValue& operator[](int handle) const
|
||
|
{
|
||
|
assert(is_used(handle)); //typically this is a stale handle (already been freed)
|
||
|
return pool_root<T>::value_at_index(handle&mMASK_HANDLE_TO_INDEX);
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
// Accessor
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
TTValue& operator[](int i)
|
||
|
{
|
||
|
assert(is_used(i)); //typically this is a stale handle (already been freed)
|
||
|
return pool_root<T>::value_at_index(i&mMASK_HANDLE_TO_INDEX);
|
||
|
}
|
||
|
|
||
|
bool is_used(int i) const
|
||
|
{
|
||
|
if (mHandles[i&mMASK_HANDLE_TO_INDEX]==i)
|
||
|
{
|
||
|
return pool_root<T>::is_used_index(i&mMASK_HANDLE_TO_INDEX);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
// Swap two items based on handle
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
void swap(int i,int j)
|
||
|
{
|
||
|
assert(is_used(i)); //typically this is a stale handle (already been freed)
|
||
|
assert(is_used(j)); //typically this is a stale handle (already been freed)
|
||
|
swap_index(handle_to_index(i),handle_to_index(j));
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
// The Allocator returns a handle
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
int alloc()
|
||
|
{
|
||
|
int index=pool_root<T>::alloc_index();
|
||
|
return mHandles[index];
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
// The Allocator, with value, returns a handle
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
int alloc(const TTValue &v)
|
||
|
{
|
||
|
int index=pool_root<T>::alloc_index(v);
|
||
|
return mHandles[index];
|
||
|
}
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
// The Deallocator, by index, not something generally needed
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
void free_index(int index)
|
||
|
{
|
||
|
pool_root<T>::free_index(index);
|
||
|
IncHandle(index);
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
// The Deallocator, by handle
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
void free(int handle)
|
||
|
{
|
||
|
assert(is_used(handle));
|
||
|
free_index(handle&mMASK_HANDLE_TO_INDEX);
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
// The Deallocator, by pointer
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
void free(TTValue *me)
|
||
|
{
|
||
|
free_index(pointer_to_index(me));
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
// Convert a handle to a raw index, not generally something you should use
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
int handle_to_index(int handle) const
|
||
|
{
|
||
|
assert(is_used(handle));
|
||
|
return (handle&mMASK_HANDLE_TO_INDEX);
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
// FInd the handle for a given index, this cannot check for stale handles, so it is ill advised
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
int index_to_handle(int index) const
|
||
|
{
|
||
|
assert(index>=0 && index<CAPACITY && pool_root<T>::is_used_index(index)); //disallowing this on stale handles
|
||
|
return (mHandles[index]);
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
// converts a T pointer to a handle, generally not something you need, cannot check for stale handles
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
int pointer_to_handle(const TTValue *me) const
|
||
|
{
|
||
|
return index_to_handle(pool_root<T>::pointer_to_index(me));
|
||
|
}
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
// converts a T pointer to a handle, generally not something you need, cannot check for stale handles
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
int pointer_to_handle(const TRatlNew *me) const
|
||
|
{
|
||
|
return index_to_handle(pool_root<T>::pointer_to_index(me));
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
// Get An Iterator To The Object At handle
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
typename pool_root<T>::iterator at(int handle)
|
||
|
{
|
||
|
assert(is_used(handle));
|
||
|
return pool_root<T>::at_index(handle&mMASK_HANDLE_TO_INDEX);
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
// Get An Iterator To The Object At handle
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
typename pool_root<T>::const_iterator at(int handle) const
|
||
|
{
|
||
|
assert(is_used(handle));
|
||
|
return pool_root<T>::at_index(handle&mMASK_HANDLE_TO_INDEX);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template<class T, int ARG_CAPACITY>
|
||
|
class handle_pool_vs : public handle_pool_base<storage::value_semantics<T,ARG_CAPACITY> >
|
||
|
{
|
||
|
public:
|
||
|
typedef typename storage::value_semantics<T,ARG_CAPACITY> TStorageTraits;
|
||
|
typedef typename TStorageTraits::TValue TTValue;
|
||
|
static const int CAPACITY = ARG_CAPACITY;
|
||
|
handle_pool_vs() {}
|
||
|
};
|
||
|
|
||
|
template<class T, int ARG_CAPACITY>
|
||
|
class handle_pool_os : public handle_pool_base<storage::object_semantics<T,ARG_CAPACITY> >
|
||
|
{
|
||
|
public:
|
||
|
typedef typename storage::object_semantics<T,ARG_CAPACITY> TStorageTraits;
|
||
|
typedef typename TStorageTraits::TValue TTValue;
|
||
|
static const int CAPACITY = ARG_CAPACITY;
|
||
|
handle_pool_os() {}
|
||
|
};
|
||
|
|
||
|
template<class T, int ARG_CAPACITY, int ARG_MAX_CLASS_SIZE>
|
||
|
class handle_pool_is : public handle_pool_base<storage::virtual_semantics<T,ARG_CAPACITY,ARG_MAX_CLASS_SIZE> >
|
||
|
{
|
||
|
public:
|
||
|
typedef typename storage::virtual_semantics<T,ARG_CAPACITY,ARG_MAX_CLASS_SIZE> TStorageTraits;
|
||
|
typedef typename TStorageTraits::TValue TTValue;
|
||
|
static const int CAPACITY = ARG_CAPACITY;
|
||
|
static const int MAX_CLASS_SIZE = ARG_MAX_CLASS_SIZE;
|
||
|
handle_pool_is() {}
|
||
|
};
|
||
|
|
||
|
}
|
||
|
#endif
|