| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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(REUSABLEARENAALLOCATOR_INCLUDE_GUARD_1357924680) |
| #define REUSABLEARENAALLOCATOR_INCLUDE_GUARD_1357924680 |
| |
| |
| |
| #include <algorithm> |
| |
| |
| |
| #include "ReusableArenaBlock.hpp" |
| #include "ArenaAllocator.hpp" |
| |
| |
| |
| namespace XALAN_CPP_NAMESPACE { |
| |
| |
| |
| template<class ObjectType> |
| class ReusableArenaAllocator : public ArenaAllocator<ObjectType, |
| ReusableArenaBlock<ObjectType> > |
| { |
| public: |
| |
| typedef ReusableArenaBlock<ObjectType> ReusableArenaBlockType; |
| |
| typedef typename ReusableArenaBlockType::size_type size_type; |
| |
| typedef ArenaAllocator<ObjectType, |
| ReusableArenaBlockType> BaseClassType; |
| |
| typedef ReusableArenaAllocator<ObjectType> ThisType; |
| |
| typedef XalanList<ReusableArenaBlockType*> ArenaBlockListType; |
| |
| typedef typename ArenaBlockListType::iterator iterator; |
| typedef typename ArenaBlockListType::const_iterator const_iterator; |
| typedef typename ArenaBlockListType::reverse_iterator reverse_iterator; |
| typedef typename ArenaBlockListType::const_reverse_iterator const_reverse_iterator; |
| |
| |
| /* |
| * Construct an instance that will allocate blocks of the specified size. |
| * |
| * @param theBlockSize The block size. |
| */ |
| ReusableArenaAllocator( |
| MemoryManager& theManager, |
| size_type theBlockSize, |
| bool destroyBlocks = false) : |
| BaseClassType(theManager, theBlockSize), |
| m_destroyBlocks(destroyBlocks) |
| { |
| } |
| |
| virtual |
| ~ReusableArenaAllocator() |
| { |
| } |
| |
| /* |
| * Destroy the object, and free the block for re-use. |
| * |
| * @param theObject the address of the object. |
| * @return true if the object was deleted, false if not. |
| */ |
| bool |
| destroyObject(ObjectType* theObject) |
| { |
| bool bResult = false; |
| |
| assert ( theObject != 0 ); |
| |
| if ( this->m_blocks.empty() ) |
| return bResult; |
| |
| iterator iTerator = this->m_blocks.begin(); |
| |
| iterator iEnd = this->m_blocks.end(); |
| |
| // first , run over unfull blocks ( that consentrated from the head ) |
| while( iTerator != iEnd |
| && (*iTerator)->blockAvailable() ) |
| { |
| if ((*iTerator)->ownsBlock(theObject) == true) |
| { |
| (*iTerator)->destroyObject(theObject); |
| |
| // move the block we have just deleted to the head of the list |
| if (iTerator != this->m_blocks.begin()) |
| { |
| // move the block to the beginning |
| ReusableArenaBlockType* block = *iTerator; |
| |
| assert(block != 0); |
| |
| this->m_blocks.erase(iTerator); |
| |
| this->m_blocks.push_front(block); |
| } |
| |
| if (m_destroyBlocks) |
| { |
| destroyBlock(); |
| } |
| |
| bResult = true; |
| |
| break; |
| } |
| |
| ++iTerator; |
| } |
| |
| reverse_iterator rIterator = this->m_blocks.rbegin(); |
| |
| reverse_iterator rEnd = this->m_blocks.rend(); |
| |
| // if the block hasn't been found from the head , start with full blocks ( from the taile) |
| while ( !bResult && rIterator != rEnd ) |
| { |
| if ((*rIterator)->ownsBlock(theObject)) |
| { |
| (*rIterator)->destroyObject(theObject); |
| |
| if (rIterator != this->m_blocks.rbegin()) |
| { |
| // move the block to the beginning |
| ReusableArenaBlockType* block = *iTerator; |
| |
| assert(block != 0); |
| |
| this->m_blocks.erase(iTerator); |
| |
| this->m_blocks.push_front(block); |
| |
| } |
| |
| if (m_destroyBlocks) |
| { |
| destroyBlock(); |
| } |
| |
| bResult = true; |
| |
| break; |
| } |
| |
| if ( *rIterator == *iTerator) |
| { |
| break; |
| } |
| else |
| { |
| ++rIterator; |
| } |
| } |
| |
| return bResult; |
| } |
| |
| /* |
| * Allocate a block of the appropriate size for an |
| * object. Call commitAllocation() when after |
| * the object is successfully constructed. You _must_ |
| * commit an allocation before performing any other |
| * operation on the allocator. |
| * |
| * |
| * @return A pointer to a block of memory |
| */ |
| virtual ObjectType* |
| allocateBlock() |
| { |
| if( this->m_blocks.empty() |
| || !this->m_blocks.front()->blockAvailable() ) |
| { |
| this->m_blocks.push_front( |
| ReusableArenaBlockType::create( |
| this->getMemoryManager(), |
| this->m_blockSize)); |
| |
| assert( this->m_blocks.front() != 0 ); |
| } |
| |
| assert( this->m_blocks.front() != 0 ); |
| assert( this->m_blocks.front()->blockAvailable() ); |
| |
| return this->m_blocks.front()->allocateBlock(); |
| } |
| |
| /* |
| * Commits the allocation of the previous |
| * allocateBlock() call. |
| * |
| * @param theObject A pointer to a block of memory |
| */ |
| virtual void |
| commitAllocation(ObjectType* theObject) |
| { |
| // Note that this-> is required by template lookup rules. |
| assert( this->m_blocks.empty() == false ); |
| assert( this->m_blocks.front() != 0 ); |
| assert( this->m_blocks.front()->ownsBlock(theObject) == true ); |
| |
| this->m_blocks.front()->commitAllocation(theObject); |
| |
| if( !this->m_blocks.front()->blockAvailable() ) |
| { |
| ReusableArenaBlockType* fullBlock = this->m_blocks.front(); |
| |
| assert ( fullBlock != 0 ); |
| |
| this->m_blocks.pop_front(); |
| |
| this->m_blocks.push_back( fullBlock ); |
| } |
| } |
| |
| |
| virtual bool |
| ownsObject(const ObjectType* theObject) const |
| { |
| if ( this->m_blocks.empty() ) |
| return false; |
| |
| const_iterator iTerator = this->m_blocks.begin(); |
| |
| const_iterator iEnd = this->m_blocks.end(); |
| |
| while( iTerator != iEnd |
| && (*iTerator)->blockAvailable() ) |
| { |
| if ((*iTerator)->ownsBlock(theObject) ) |
| { |
| return true; |
| } |
| |
| ++iTerator; |
| } |
| |
| const_reverse_iterator rIterator = this->m_blocks.rbegin(); |
| |
| const_reverse_iterator rEnd = this->m_blocks.rend(); |
| |
| while( rIterator != rEnd ) |
| { |
| if ((*rIterator)->ownsBlock(theObject) ) |
| { |
| return true; |
| } |
| |
| if ( *iTerator == *rIterator ) |
| { |
| break; |
| } |
| else |
| { |
| ++rIterator; |
| } |
| } |
| |
| return false; |
| } |
| |
| protected: |
| |
| /* |
| * The method destroys an empty block from the head of the list. |
| * For eliminating multiple create/destroy operation, the block |
| * is destroyed only if the second one is not full. |
| */ |
| void |
| destroyBlock() |
| { |
| assert(m_destroyBlocks == true); |
| |
| if ( this->m_blocks.empty() == false) |
| { |
| const_iterator iTerator = this->m_blocks.begin(); |
| |
| if ( (*iTerator)->isEmpty() ) |
| { |
| ++iTerator; |
| |
| if (iTerator == this->m_blocks.end() || |
| (*iTerator)->blockAvailable() ) |
| { |
| this->m_blocks.pop_front(); |
| } |
| } |
| } |
| } |
| |
| // data members |
| const bool m_destroyBlocks; |
| |
| private: |
| |
| // Not defined... |
| ReusableArenaAllocator(const ReusableArenaAllocator<ObjectType>&); |
| |
| ReusableArenaAllocator<ObjectType>& |
| operator=(const ReusableArenaAllocator<ObjectType>&); |
| |
| bool |
| operator==(const ReusableArenaAllocator<ObjectType>&) const; |
| }; |
| |
| |
| |
| } |
| |
| |
| |
| #endif // !defined(REUSABLEARENAALLOCATOR_INCLUDE_GUARD_1357924680) |