add initial_reserve_id(), bring up to Panda coding standards

This commit is contained in:
David Rose 2007-03-15 23:46:08 +00:00
parent 1fdb425b88
commit 7022d6ab9e
2 changed files with 182 additions and 81 deletions

View File

@ -26,8 +26,8 @@
NotifyCategoryDecl(uniqueIdAllocator, EXPCL_PANDA, EXPTP_PANDA); NotifyCategoryDecl(uniqueIdAllocator, EXPCL_PANDA, EXPTP_PANDA);
NotifyCategoryDef(uniqueIdAllocator, ""); NotifyCategoryDef(uniqueIdAllocator, "");
const U32 UniqueIdAllocator::IndexEnd=(U32)-1; const PN_uint32 UniqueIdAllocator::IndexEnd = (PN_uint32)-1;
const U32 UniqueIdAllocator::IndexAllocated=(U32)-2; const PN_uint32 UniqueIdAllocator::IndexAllocated = (PN_uint32)-2;
#ifndef NDEBUG //[ #ifndef NDEBUG //[
// Non-release build: // Non-release build:
@ -51,31 +51,36 @@ const U32 UniqueIdAllocator::IndexAllocated=(U32)-2;
#define audio_error(msg) \ #define audio_error(msg) \
audio_cat->error() << msg << endl audio_cat->error() << msg << endl
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: // Function: UniqueIdAllocator::Constructor
// Access: // Access: Published
// Description: Create a free id pool in the range [min:max]. // Description: Create a free id pool in the range [min:max].
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
UniqueIdAllocator:: UniqueIdAllocator::
UniqueIdAllocator(U32 min, U32 max) UniqueIdAllocator(PN_uint32 min, PN_uint32 max)
: _min(min), _max(max) { : _min(min), _max(max) {
uniqueIdAllocator_debug("UniqueIdAllocator("<<min<<", "<<max<<")"); uniqueIdAllocator_debug("UniqueIdAllocator("<<min<<", "<<max<<")");
_size=_max-_min+1; // +1 because min and max are inclusive.
nassertv(_size); // size must be > 0. nassertv(_max > _min);
_table=new U32[_size]; _size = _max-_min+1; // +1 because min and max are inclusive.
nassertv(_size != 0); // size must be > 0.
_table=new PN_uint32[_size];
nassertv(_table); // This should be redundant if new throws an exception. nassertv(_table); // This should be redundant if new throws an exception.
for (U32 i=0; i<_size; ++i) {
_table[i]=i+1; for (PN_uint32 i = 0; i < _size; ++i) {
_table[i] = i + 1;
} }
_table[_size-1]=IndexEnd; _table[_size - 1] = IndexEnd;
_next_free=0; _next_free = 0;
_last_free=_size-1; _last_free = _size - 1;
_free=_size; _free=_size;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: // Function: UniqueIdAllocator::Destructor
// Access: // Access: Published
// Description: // Description:
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
UniqueIdAllocator:: UniqueIdAllocator::
@ -86,57 +91,113 @@ UniqueIdAllocator::
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: // Function: UniqueIdAllocator::allocate
// Access: // Access: Published
// Description: Receive an id between _min and _max (that were passed // Description: Returns an id between _min and _max (that were passed
// to the constructor). // to the constructor).
// IndexEnd is returned if no ids are available. // IndexEnd is returned if no ids are available.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
U32 UniqueIdAllocator:: PN_uint32 UniqueIdAllocator::
allocate() { allocate() {
if (_next_free==IndexEnd) { if (_next_free == IndexEnd) {
// ...all ids allocated. // ...all ids allocated.
uniqueIdAllocator_warning("allocate Error: no more free ids."); uniqueIdAllocator_warning("allocate Error: no more free ids.");
return IndexEnd; return IndexEnd;
} }
U32 id=_min+_next_free; PN_uint32 index = _next_free;
_next_free=_table[_next_free]; _next_free = _table[_next_free];
#ifndef NDEBUG //[ #ifndef NDEBUG //[
_table[id-_min]=IndexAllocated; nassertr(_table[index] != IndexAllocated, IndexEnd);
_table[index] = IndexAllocated;
#endif //] #endif //]
--_free; --_free;
uniqueIdAllocator_debug("allocate() returning "<<id);
PN_uint32 id = index + _min;
uniqueIdAllocator_debug("allocate() returning " << id);
return id; return id;
} }
////////////////////////////////////////////////////////////////////
// Function: UniqueIdAllocator::initial_reserve_id
// Access: Published
// Description: This may be called to mark a particular id as having
// already been allocated (for instance, by a prior
// pass). The specified id is removed from the
// available pool.
//
// Because of the limitations of this algorithm, this
// may only be called before the first call to
// allocate(); and all the calls to initial_reserve_id()
// must be made in descending order by id.
////////////////////////////////////////////////////////////////////
void UniqueIdAllocator::
initial_reserve_id(PN_uint32 id) {
nassertv(_next_free == 0); // Must call before any call to allocate().
nassertv(id >= _min && id <= _max); // Attempt to reserve out-of-range id.
PN_uint32 index = id - _min; // Convert to _table index.
nassertv(_table[index] != IndexAllocated);
// Because we insist that this call be made before any calls to
// allocate(), and in descending order, it follows that the _table
// is still set up such that _table[i] = i+1, at least for all slots
// <= index. Thus, the free link to slot [index] is guaranteed to
// be the slot right before it.
if (index == 0) {
_next_free = _table[index];
} else {
nassertv(_table[index - 1] == index);
_table[index - 1] = _table[index];
if (index == _last_free) {
_last_free = index - 1;
}
}
#ifndef NDEBUG //[
_table[index] = IndexAllocated;
#endif //]
--_free;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: free // Function: UniqueIdAllocator::free
// Access: // Access: Published
// Description: Free an allocated index (index must be between _min // Description: Free an allocated index (index must be between _min
// and _max that were passed to the constructor). // and _max that were passed to the constructor).
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void UniqueIdAllocator:: void UniqueIdAllocator::
free(U32 index) { free(PN_uint32 id) {
uniqueIdAllocator_debug("free("<<index<<")"); uniqueIdAllocator_debug("free("<<id<<")");
nassertv(index>=_min); // Attempt to free out-of-range id.
nassertv(index<=_max); // Attempt to free out-of-range id. nassertv(id >= _min && id <= _max); // Attempt to free out-of-range id.
index=index-_min; // Convert to _table index. PN_uint32 index = id - _min; // Convert to _table index.
nassertv(_table[index]==IndexAllocated); // Attempt to free non-allocated id. nassertv(_table[index] == IndexAllocated); // Attempt to free non-allocated id.
_table[index]=IndexEnd; // Mark this element as the end of the list. if (_next_free != IndexEnd) {
_table[_last_free]=index; nassertv(_table[_last_free] == IndexEnd);
if (_next_free==IndexEnd) { _table[_last_free] = index;
// ...the free list was empty.
_next_free=index;
} }
_last_free=index; _table[index] = IndexEnd; // Mark this element as the end of the list.
_last_free = index;
if (_next_free == IndexEnd) {
// ...the free list was empty.
_next_free = index;
}
++_free; ++_free;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: fraction_used // Function: UniqueIdAllocator::fraction_used
// Access: // Access: Published
// Description: return the decimal fraction of the pool that is used. // Description: return the decimal fraction of the pool that is used.
// The range is 0 to 1.0 (e.g. 75% would be 0.75). // The range is 0 to 1.0 (e.g. 75% would be 0.75).
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -145,27 +206,45 @@ fraction_used() const {
return float(_size-_free)/_size; return float(_size-_free)/_size;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: output // Function: UniqueIdAllocator::output
// Access: // Access: Published
// Description: ...intended for debugging only. // Description: ...intended for debugging only.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void UniqueIdAllocator:: void UniqueIdAllocator::
output(ostream& os, bool verbose) const { output(ostream &out) const {
os <<"[_min: "<<_min<<"; _max: "<<_max out << "UniqueIdAllocator(" << _min << ", " << _max << "), "
<<";\n_next_free: "<<long(_next_free) << _free << " id's remaining of " << _size;
<<"; _last_free: "<<long(_last_free) }
<<"; _size: "<<_size
<<"; _free: "<<_free ////////////////////////////////////////////////////////////////////
<<"; used: "<<_size-_free // Function: UniqueIdAllocator::write
<<"; fraction_used: "<<fraction_used(); // Access: Published
if (verbose) { // Description: ...intended for debugging only.
os <<";\n "; ////////////////////////////////////////////////////////////////////
for (U32 i=0; i<_size; ++i) { void UniqueIdAllocator::
os<<long(_table[i])<<", "; write(ostream &out) const {
} out << "_min: " << _min << "; _max: " << _max
} << ";\n_next_free: " << PN_int32(_next_free)
os<<"]"<<endl; << "; _last_free: " << PN_int32(_last_free)
<< "; _size: " << _size
<< "; _free: " << _free
<< "; used: " << _size - _free
<< "; fraction_used: " << fraction_used()
<< ";\n";
out << "Table:";
for (PN_uint32 i = 0; i < _size; ++i) {
out << " " << PN_int32(_table[i]);
}
out << "\n";
out << "Free chain:";
PN_uint32 index = _next_free;
while (index != IndexEnd) {
out << " " << index + _min;
index = _table[index];
}
out << "\n";
} }

View File

@ -21,9 +21,7 @@
#define _UNIQUEIDALLOCATOR_H #define _UNIQUEIDALLOCATOR_H
#include "pandabase.h" #include "pandabase.h"
#include "numeric_types.h"
typedef unsigned long U32;
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Class : UniqueIdAllocator // Class : UniqueIdAllocator
@ -49,30 +47,54 @@ typedef unsigned long U32;
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
class EXPCL_PANDA UniqueIdAllocator { class EXPCL_PANDA UniqueIdAllocator {
PUBLISHED: PUBLISHED:
UniqueIdAllocator(U32 min=0, U32 max=20); UniqueIdAllocator(PN_uint32 min=0, PN_uint32 max=20);
~UniqueIdAllocator(); ~UniqueIdAllocator();
U32 allocate();
void free(U32 index);
float fraction_used() const;
void output(ostream& os, bool verbose=false) const;
public: PN_uint32 allocate();
// VC6 does not support declaring const values within the class void initial_reserve_id(PN_uint32 id);
// definition; we must therefore define the value for this in the
// .cxx file. This does potentially change the way the code is void free(PN_uint32 index);
// generated (since the compiler does not necessarily know the value float fraction_used() const;
// of this constant).
static const U32 IndexEnd; void output(ostream &out) const;
void write(ostream &out) const;
public:
static const PN_uint32 IndexEnd;
static const PN_uint32 IndexAllocated;
protected: protected:
static const U32 IndexAllocated; // _table stores an array of _size words, corresponding to each
U32* _table; // allocatable id.
U32 _min;
U32 _max; // For each free id, the table entry at the corresponding index
U32 _next_free; // contains the index number of the next free id, thus defining a
U32 _last_free; // chain of free id's. The last element of the chain contains
U32 _size; // IndexEnd.
U32 _free;
// For an allocated id, the table entry at the corresponding index
// is undefined (but in debug mode, it contains IndexAllocated).
PN_uint32 *_table;
// The minimum and maximum as passed to the constructor.
PN_uint32 _min;
PN_uint32 _max;
// This is the head of the free chain: as elements are allocated,
// they are taken from _table[_next_free]. If the free chain is
// empty, _next_free == IndexEnd.
PN_uint32 _next_free;
// This is the tail of the free chain: as elements are freed, they
// are stored in _table[_last_free]. Normally, _table[_last_free]
// is the end of the free chain, unless the free chain is empty.
PN_uint32 _last_free;
// The total number of elements in _table.
PN_uint32 _size;
// The number of free elements in _table.
PN_uint32 _free;
}; };
#endif //] #endif //]