00001 /* 00002 * Copyright 1999-2004 The Apache Software Foundation. 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #if !defined(REUSABLEARENABLOCK_INCLUDE_GUARD_1357924680) 00018 #define REUSABLEARENABLOCK_INCLUDE_GUARD_1357924680 00019 00020 00021 #include <xalanc/PlatformSupport/ArenaBlockBase.hpp> 00022 00023 00024 00025 #include <xalanc/Include/XalanMemMgrAutoPtr.hpp> 00026 00027 00028 00029 XALAN_CPP_NAMESPACE_BEGIN 00030 00031 00032 00033 template <class ObjectType, 00034 #if defined(XALAN_NO_DEFAULT_TEMPLATE_ARGUMENTS) 00035 class SizeType> 00036 #else 00037 class SizeType = unsigned short> 00038 #endif 00039 class ReusableArenaBlock : public ArenaBlockBase<ObjectType, SizeType> 00040 { 00041 00042 public: 00043 00044 typedef ArenaBlockBase<ObjectType, SizeType> BaseClassType; 00045 00046 typedef typename BaseClassType::size_type size_type; 00047 00048 typedef ReusableArenaBlock<ObjectType, SizeType> ThisType; 00049 00050 struct NextBlock 00051 { 00052 enum { VALID_OBJECT_STAMP = 0xffddffdd }; 00053 00054 size_type next; 00055 const int verificationStamp; 00056 00057 NextBlock( size_type _next): 00058 next(_next), 00059 verificationStamp(VALID_OBJECT_STAMP) 00060 { 00061 } 00062 00063 bool 00064 isValidFor( size_type rightBorder ) const 00065 { 00066 return ( ( verificationStamp == int(VALID_OBJECT_STAMP)) && 00067 ( next <= rightBorder ) ) ? true : false ; 00068 } 00069 00070 static NextBlock* 00071 cast(void* thePointer) 00072 { 00073 return reinterpret_cast<NextBlock*>(thePointer); 00074 } 00075 00076 static const NextBlock* 00077 cast(const void* thePointer) 00078 { 00079 return reinterpret_cast<const NextBlock*>(thePointer); 00080 } 00081 }; 00082 00083 /* 00084 * Construct an ArenaBlock of the specified size 00085 * of objects. 00086 * 00087 * @param theBlockSize The size of the block (the 00088 * number of objects it can contain). 00089 */ 00090 ReusableArenaBlock( 00091 MemoryManagerType& theManager, 00092 size_type theBlockSize) : 00093 BaseClassType(theManager, theBlockSize), 00094 m_firstFreeBlock(0), 00095 m_nextFreeBlock(0) 00096 00097 { 00098 XALAN_STATIC_ASSERT(sizeof(ObjectType) >= sizeof(NextBlock)); 00099 00100 for( size_type i = 0; i < this->m_blockSize; ++i ) 00101 { 00102 new (&this->m_objectBlock[i]) NextBlock(size_type(i + 1)); 00103 } 00104 } 00105 00106 ~ReusableArenaBlock() 00107 { 00108 size_type removedObjects = 0; 00109 00110 for (size_type i = 0; 00111 i < this->m_blockSize && 00112 removedObjects < this->m_objectCount; 00113 ++i) 00114 { 00115 NextBlock* const pStruct = 00116 NextBlock::cast(&this->m_objectBlock[i]); 00117 00118 if ( isOccupiedBlock(pStruct) ) 00119 { 00120 this->m_objectBlock[i].~ObjectType(); 00121 00122 ++removedObjects; 00123 } 00124 } 00125 } 00126 00127 static ThisType* 00128 create( 00129 MemoryManagerType& theManager, 00130 size_type theBlockSize) 00131 { 00132 ThisType* theInstance; 00133 00134 return XalanConstruct( 00135 theManager, 00136 theInstance, 00137 theManager, 00138 theBlockSize); 00139 } 00140 00141 /* 00142 * Allocate a block. Once the object is constructed, you must call 00143 * commitAllocation(). 00144 * 00145 * @return a pointer to the new block. 00146 */ 00147 ObjectType* 00148 allocateBlock() 00149 { 00150 if ( this->m_objectCount == this->m_blockSize ) 00151 { 00152 assert ( this->m_firstFreeBlock == (this->m_blockSize + 1) ); 00153 00154 return 0; 00155 } 00156 else 00157 { 00158 assert( this->m_objectCount < this->m_blockSize ); 00159 00160 ObjectType* theResult = 0; 00161 00162 assert ( this->m_firstFreeBlock <= this->m_blockSize ); 00163 assert ( this->m_nextFreeBlock <= this->m_blockSize ); 00164 00165 // check if any part was allocated but not commited 00166 if(this->m_firstFreeBlock != this->m_nextFreeBlock) 00167 { 00168 // return the previously allocated block and wait for a commit 00169 theResult = this->m_objectBlock + this->m_firstFreeBlock; 00170 } 00171 else 00172 { 00173 theResult = this->m_objectBlock + this->m_firstFreeBlock; 00174 00175 assert(size_type(theResult - this->m_objectBlock) < this->m_blockSize); 00176 00177 this->m_nextFreeBlock = NextBlock::cast(theResult)->next; 00178 00179 assert(NextBlock::cast(theResult)->isValidFor(this->m_blockSize)); 00180 assert(this->m_nextFreeBlock <= this->m_blockSize); 00181 00182 ++this->m_objectCount; 00183 } 00184 00185 return theResult; 00186 } 00187 } 00188 00189 /* 00190 * Commit the previous allocation. 00191 * 00192 * @param theBlock the address that was returned by allocateBlock() 00193 */ 00194 void 00195 commitAllocation(ObjectType* /* theBlock */) 00196 { 00197 assert ( this->m_objectCount <= this->m_blockSize ); 00198 00199 this->m_firstFreeBlock = this->m_nextFreeBlock; 00200 } 00201 00202 /* 00203 * Destroy the object, and return the block to the free list. 00204 * The behavior is undefined if the object pointed to is not 00205 * owned by the block. 00206 * 00207 * @param theObject the address of the object. 00208 */ 00209 void 00210 destroyObject(ObjectType* theObject) 00211 { 00212 assert(theObject != 0); 00213 00214 // check if any uncommited block is there, add it to the list 00215 if ( this->m_firstFreeBlock != this->m_nextFreeBlock ) 00216 { 00217 // Return it to the pool of free blocks 00218 void* const p = this->m_objectBlock + this->m_firstFreeBlock; 00219 00220 new (p) NextBlock(this->m_nextFreeBlock); 00221 00222 this->m_nextFreeBlock = this->m_firstFreeBlock; 00223 } 00224 00225 assert(ownsObject(theObject) == true); 00226 assert(shouldDestroyBlock(theObject)); 00227 00228 XalanDestroy(*theObject); 00229 00230 new (theObject) NextBlock(this->m_firstFreeBlock); 00231 00232 m_firstFreeBlock = 00233 this->m_nextFreeBlock = 00234 size_type(theObject - this->m_objectBlock); 00235 00236 assert (this->m_firstFreeBlock <= this->m_blockSize); 00237 00238 --this->m_objectCount; 00239 } 00240 00241 /* 00242 * Determine if this block owns the specified object. Note 00243 * that even if the object address is within our block, this 00244 * call will return false if no object currently occupies the 00245 * block. See also ownsBlock(). 00246 * 00247 * @param theObject the address of the object. 00248 * @return true if we own the object, false if not. 00249 */ 00250 bool 00251 ownsObject(const ObjectType* theObject) const 00252 { 00253 assert ( theObject != 0 ); 00254 00255 return isOccupiedBlock(NextBlock::cast(theObject)); 00256 } 00257 00258 protected: 00259 00260 /* 00261 * Determine if the block should be destroyed. Returns true, 00262 * unless the object is on the free list. The behavior is 00263 * undefined if the object pointed to is not owned by the 00264 * block. 00265 * 00266 * @param theObject the address of the object 00267 * @return true if block should be destroyed, false if not. 00268 */ 00269 bool 00270 shouldDestroyBlock(const ObjectType* theObject) const 00271 { 00272 assert(size_type(theObject - this->m_objectBlock) < this->m_blockSize); 00273 00274 return !isOnFreeList(theObject); 00275 } 00276 00277 bool 00278 isOccupiedBlock(const NextBlock* block) const 00279 { 00280 assert( block !=0 ); 00281 00282 return !(this->ownsBlock(reinterpret_cast<const ObjectType*>(block)) && 00283 block->isValidFor(this->m_blockSize)); 00284 } 00285 00286 private: 00287 00288 // Not implemented... 00289 ReusableArenaBlock(const ReusableArenaBlock<ObjectType, SizeType>&); 00290 00291 ReusableArenaBlock<ObjectType, SizeType>& 00292 operator=(const ReusableArenaBlock<ObjectType, SizeType>&); 00293 00294 bool 00295 operator==(const ReusableArenaBlock<ObjectType, SizeType>&) const; 00296 00297 00298 /* 00299 * Determine if the block is on the free list. The behavior is 00300 * undefined if the object pointed to is not owned by the 00301 * block. 00302 * 00303 * @param theObject the address of the object 00304 * @return true if block is on the free list, false if not. 00305 */ 00306 bool 00307 isOnFreeList(const ObjectType* theObject) const 00308 { 00309 if ( this->m_objectCount == 0 ) 00310 { 00311 return false; 00312 } 00313 else 00314 { 00315 ObjectType* pRunPtr = this->m_objectBlock + this->m_firstFreeBlock; 00316 00317 for (size_type i = 0; 00318 i < this->m_blockSize - this->m_objectCount; 00319 ++i) 00320 { 00321 assert(this->ownsBlock(pRunPtr)); 00322 00323 if (pRunPtr == theObject) 00324 { 00325 return true; 00326 } 00327 else 00328 { 00329 NextBlock* const p = reinterpret_cast<NextBlock*>(pRunPtr); 00330 00331 assert(p->isValidFor(this->m_blockSize)); 00332 00333 pRunPtr = this->m_objectBlock + p->next; 00334 } 00335 } 00336 00337 return false; 00338 } 00339 } 00340 00341 // Data members... 00342 size_type m_firstFreeBlock; 00343 00344 size_type m_nextFreeBlock; 00345 }; 00346 00347 00348 00349 XALAN_CPP_NAMESPACE_END 00350 00351 00352 00353 #endif // !defined(REUSABLEARENABLOCK_INCLUDE_GUARD_1357924680)
Doxygen and GraphViz are used to generate this API documentation from the Xalan-C header files.
Xalan-C++ XSLT Processor Version 1.10 |
|