blob: de5e91d0fcb10e2240067adc2714240e9ba8c3b5 [file] [log] [blame]
/*
* Copyright 1999-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if !defined(REUSABLEARENABLOCK_INCLUDE_GUARD_1357924680)
#define REUSABLEARENABLOCK_INCLUDE_GUARD_1357924680
#include <xalanc/PlatformSupport/ArenaBlockBase.hpp>
XALAN_CPP_NAMESPACE_BEGIN
template<bool> struct CompileTimeError;
template<> struct CompileTimeError<true>{};
#define XALAN_STATIC_CHECK(expr) CompileTimeError<bool(expr)>()
template <class ObjectType,
#if defined(XALAN_NO_DEFAULT_TEMPLATE_ARGUMENTS)
class size_Type>
#else
class size_Type = unsigned short >
#endif
class ReusableArenaBlock : public ArenaBlockBase<ObjectType, size_Type>
{
public:
typedef ArenaBlockBase<ObjectType, size_Type> BaseClassType;
typedef typename BaseClassType::size_type size_type;
struct NextBlock
{
enum { VALID_OBJECT_STAMP = 0xffddffdd };
size_type next;
const int verificationStamp;
NextBlock( size_type _next):
next(_next),
verificationStamp(VALID_OBJECT_STAMP)
{
}
bool
isValidFor( size_type rightBorder ) const
{
return ( ( verificationStamp == int(VALID_OBJECT_STAMP)) &&
( next <= rightBorder ) ) ? true : false ;
}
};
/*
* Construct an ArenaBlock of the specified size
* of objects.
*
* @param theBlockSize The size of the block (the number of objects it can contain).
*/
ReusableArenaBlock(size_type theBlockSize) :
BaseClassType(theBlockSize),
m_firstFreeBlock(0),
m_nextFreeBlock(0)
{
XALAN_STATIC_CHECK(sizeof(ObjectType) >= sizeof(NextBlock));
for( size_type i = 0; i < this->m_blockSize; ++i )
{
new ( reinterpret_cast<NextBlock*>(&(this->m_objectBlock[i])) ) NextBlock( (size_type)(i + 1) );
}
}
~ReusableArenaBlock()
{
size_type removedObjects = 0;
NextBlock* pStruct = 0;
for ( size_type i = 0 ; i < this->m_blockSize && (removedObjects < this->m_objectCount) ; ++i )
{
pStruct = reinterpret_cast<NextBlock*>(&(this->m_objectBlock[i]));
if ( isOccupiedBlock(pStruct) )
{
this->m_objectBlock[i].~ObjectType();
++removedObjects;
}
}
}
/*
* Allocate a block. Once the object is constructed, you must call
* commitAllocation().
*
* @return a pointer to the new block.
*/
ObjectType*
allocateBlock()
{
if ( this->m_objectCount == this->m_blockSize )
{
assert ( this->m_firstFreeBlock == (this->m_blockSize + 1) );
return 0;
}
else
{
assert( this->m_objectCount < this->m_blockSize );
ObjectType* theResult = 0;
assert ( this->m_firstFreeBlock <= this->m_blockSize );
assert ( this->m_nextFreeBlock <= this->m_blockSize );
// check if any part was allocated but not commited
if( this->m_firstFreeBlock != this->m_nextFreeBlock)
{
// return then againg the previouse allocated block and wait for commitment
theResult = this->m_objectBlock + this->m_firstFreeBlock;
}
else
{
theResult = this->m_objectBlock + this->m_firstFreeBlock;
assert(size_type( theResult - this->m_objectBlock ) < this->m_blockSize);
this->m_nextFreeBlock = (reinterpret_cast<NextBlock*>(theResult))->next;
assert ( ( reinterpret_cast<NextBlock*>(theResult ))->isValidFor( this->m_blockSize ) );
assert ( this->m_nextFreeBlock <= this->m_blockSize );
++this->m_objectCount;
}
return theResult;
}
}
/*
* Commit the previous allocation.
*
* @param theBlock the address that was returned by allocateBlock()
*/
void
commitAllocation(ObjectType* /* theBlock */)
{
this->m_firstFreeBlock = this->m_nextFreeBlock;
assert ( this->m_objectCount <= this->m_blockSize );
}
/*
* Destroy the object, and return the block to the free list.
* The behavior is undefined if the object pointed to is not
* owned by the block.
*
* @param theObject the address of the object.
*/
void
destroyObject(ObjectType* theObject)
{
// check if any uncommited block is there, add it to the list
if ( this->m_firstFreeBlock != this->m_nextFreeBlock )
{
// return it to pull of the free blocks
void* const p = this->m_objectBlock + this->m_firstFreeBlock;
new (p) NextBlock(this->m_nextFreeBlock);
this->m_nextFreeBlock = this->m_firstFreeBlock;
}
assert(ownsObject(theObject) == true);
assert(shouldDestroyBlock(theObject));
theObject->~ObjectType();
new (theObject) NextBlock(this->m_firstFreeBlock);
m_firstFreeBlock = this->m_nextFreeBlock = size_type(theObject - this->m_objectBlock);
assert (this->m_firstFreeBlock <= this->m_blockSize);
--this->m_objectCount;
}
/*
* Determine if this block owns the specified object. Note
* that even if the object address is within our block, this
* call will return false if no object currently occupies the
* block. See also ownsBlock().
*
* @param theObject the address of the object.
* @return true if we own the object, false if not.
*/
bool
ownsObject(const ObjectType* theObject) const
{
assert ( theObject != 0 );
return isOccupiedBlock( reinterpret_cast<const NextBlock*>(theObject) );
}
protected:
/*
* Determine if the block should be destroyed. Returns true,
* unless the object is on the free list. The behavior is
* undefined if the object pointed to is not owned by the
* block.
*
* @param theObject the address of the object
* @return true if block should be destroyed, false if not.
*/
bool
shouldDestroyBlock(const ObjectType* theObject) const
{
assert( size_type(theObject - this->m_objectBlock) < this->m_blockSize);
return !isOnFreeList(theObject);
}
bool
isOccupiedBlock(const NextBlock* block)const
{
assert( block !=0 );
return !( this->ownsBlock(reinterpret_cast<const ObjectType*>(block)) && block->isValidFor(this->m_blockSize) );
}
private:
// Not implemented...
ReusableArenaBlock(const ReusableArenaBlock<ObjectType>&);
ReusableArenaBlock<ObjectType>&
operator=(const ReusableArenaBlock<ObjectType>&);
bool
operator==(const ReusableArenaBlock<ObjectType>&) const;
/*
* Determine if the block is on the free list. The behavior is
* undefined if the object pointed to is not owned by the
* block.
*
* @param theObject the address of the object
* @return true if block is on the free list, false if not.
*/
bool
isOnFreeList(const ObjectType* theObject) const
{
if ( this->m_objectCount == 0 )
{
return false;
}
else
{
ObjectType* pRunPtr = this->m_objectBlock + this->m_firstFreeBlock;
for ( size_type i = 0; i < (this->m_blockSize - this->m_objectCount); ++i)
{
assert ( ownsBlock( pRunPtr ) );
if (pRunPtr == theObject)
{
return true;
}
else
{
NextBlock* const p = reinterpret_cast<NextBlock*>(pRunPtr);
assert( p->isValidFor( this->m_blockSize ) );
pRunPtr = this->m_objectBlock + p->next;
}
}
return false;
}
}
// Data members...
size_type m_firstFreeBlock;
size_type m_nextFreeBlock;
};
XALAN_CPP_NAMESPACE_END
#endif // !defined(REUSABLEARENABLOCK_INCLUDE_GUARD_1357924680)