diff options
| author | git perforce import user <a@b> | 2016-10-25 12:29:14 -0600 |
|---|---|---|
| committer | Sheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees> | 2016-10-25 18:56:37 -0500 |
| commit | 3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch) | |
| tree | fa6485c169e50d7415a651bf838f5bcd0fd3bfbd /APEX_1.4/common/include/InplaceStorage.h | |
| download | physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip | |
Initial commit:
PhysX 3.4.0 Update @ 21294896
APEX 1.4.0 Update @ 21275617
[CL 21300167]
Diffstat (limited to 'APEX_1.4/common/include/InplaceStorage.h')
| -rw-r--r-- | APEX_1.4/common/include/InplaceStorage.h | 985 |
1 files changed, 985 insertions, 0 deletions
diff --git a/APEX_1.4/common/include/InplaceStorage.h b/APEX_1.4/common/include/InplaceStorage.h new file mode 100644 index 00000000..d2d81912 --- /dev/null +++ b/APEX_1.4/common/include/InplaceStorage.h @@ -0,0 +1,985 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#ifndef __APEX_INPLACE_STORAGE_H__ +#define __APEX_INPLACE_STORAGE_H__ + +#include "ApexUsingNamespace.h" +#include "PsAllocator.h" +#include "InplaceTypes.h" + +namespace nvidia +{ +namespace apex +{ + + +class InplaceStorage; + +class InplaceStorageGroup +{ + friend class InplaceStorage; + + InplaceStorage* _storage; + uint32_t _lastBlockIndex; + + InplaceStorageGroup* _groupListPrev; + InplaceStorageGroup* _groupListNext; + + PX_INLINE void reset(InplaceStorage* storage) + { + PX_UNUSED(storage); + PX_ASSERT(_storage == storage); + _storage = 0; + } + +public: + PX_INLINE InplaceStorageGroup() : _storage(0) {} + PX_INLINE InplaceStorageGroup(InplaceStorage& storage) : _storage(0) + { + init(storage); + } + PX_INLINE ~InplaceStorageGroup() + { + release(); + } + + PX_INLINE void init(InplaceStorage& storage); + PX_INLINE void release(); + + PX_INLINE void begin(); + PX_INLINE void end(); + + PX_INLINE InplaceStorage& getStorage() + { + PX_ASSERT(_storage != 0); + return *_storage; + } +}; + +class InplaceStorage +{ + struct ReflectorArg + { + }; + + class Reflector + { + InplaceStorage* _storage; + uint32_t _blockIndex; + uint8_t* _blockPtr; + + public: + Reflector(InplaceStorage* storage, uint32_t blockIndex, uint8_t* blockPtr) + : _storage(storage), _blockIndex(blockIndex), _blockPtr(blockPtr) + { + } + + template <int _inplace_offset_, typename MT> + PX_INLINE void processType(ReflectorArg, InplaceHandleBase& handle, MT ) + { + size_t offset = size_t(reinterpret_cast<uint8_t*>(&handle) - _blockPtr); + _storage->addHandleRef(_blockIndex, offset, MT::AutoFreeValue); + } + template <int _inplace_offset_, typename T, typename MT> + PX_INLINE void processType(ReflectorArg ra, InplaceHandle<T>& handle, MT mt) + { + processType<_inplace_offset_>(ra, static_cast<InplaceHandleBase&>(handle), mt); + } + template <int _inplace_offset_, typename T, typename MT> + PX_INLINE void processType(ReflectorArg, T& , MT ) + { + ; //do nothing + } + + template <int _inplace_offset_, typename T> + PX_INLINE void processPrimitiveType(ReflectorArg, T& ) + { + ; //do nothing + } + }; + friend class Reflector; + + static const uint32_t NULL_INDEX = InplaceHandleBase::NULL_VALUE; + + struct Block + { + uint32_t _size; + uint32_t _alignment; + uint32_t _offset; + uint32_t _prevIndex; + union + { + uint32_t _nextIndex; + uint32_t _nextFreeBlockIndex; + }; + uint32_t _firstRefIndex; + InplaceStorageGroup* _group; + + void reset() + { + _alignment = 0; + _size = 0; + _offset = uint32_t(-1); + _prevIndex = _nextIndex = NULL_INDEX; + _firstRefIndex = NULL_INDEX; + _group = NULL; + } + }; + + struct HandleRef + { + enum Flags + { + AUTO_FREE = 0x01, + }; + uint32_t flags; + uint32_t ownerBlockIndex; + uint32_t offsetInBlock; + union + { + uint32_t nextIndex; + uint32_t nextFreeRefIndex; + }; + + void reset() + { + flags = 0; + ownerBlockIndex = NULL_INDEX; + offsetInBlock = 0; + } + }; + + void addHandleRef(uint32_t blockIndex, size_t offset, bool autoFree) + { + //find free handleRef + if (_firstFreeRefIndex == NULL_INDEX) + { + _firstFreeRefIndex = _handleRefs.size(); + _handleRefs.resize(_firstFreeRefIndex + 1); + + _handleRefs.back().nextFreeRefIndex = NULL_INDEX; + } + uint32_t thisRefIndex = _firstFreeRefIndex; + HandleRef& handleRef = _handleRefs[thisRefIndex]; + _firstFreeRefIndex = handleRef.nextFreeRefIndex; + + Block& block = _blocks[blockIndex]; + handleRef.nextIndex = block._firstRefIndex; + block._firstRefIndex = thisRefIndex; + + handleRef.ownerBlockIndex = blockIndex; + handleRef.offsetInBlock = (uint32_t) offset; + handleRef.flags = 0; + if (autoFree) + { + handleRef.flags |= HandleRef::AUTO_FREE; + } + } + + template <typename F> + void removeHandleRefs(F func, uint32_t blockIndex, uint32_t minOffset = 0) + { + Block& block = _blocks[blockIndex]; + + uint32_t prevRefIndex = NULL_INDEX; + uint32_t currRefIndex = block._firstRefIndex; + while (currRefIndex != NULL_INDEX) + { + HandleRef& handleRef = _handleRefs[currRefIndex]; + PX_ASSERT(handleRef.ownerBlockIndex == blockIndex); + + uint32_t nextRefIndex = handleRef.nextIndex; + if (handleRef.offsetInBlock >= minOffset) + { + //remove + if (handleRef.flags & HandleRef::AUTO_FREE) + { + uint32_t blockOffset = block._offset; + PX_ASSERT(blockOffset != uint32_t(-1)); + InplaceHandleBase handle = *reinterpret_cast<InplaceHandleBase*>(getBufferPtr() + blockOffset + handleRef.offsetInBlock); + + (this->*func)(block, handle); + } + + if (prevRefIndex != NULL_INDEX) + { + _handleRefs[prevRefIndex].nextIndex = nextRefIndex; + } + else + { + block._firstRefIndex = nextRefIndex; + } + + handleRef.nextFreeRefIndex = _firstFreeRefIndex; + _firstFreeRefIndex = currRefIndex; + + handleRef.reset(); + } + else + { + prevRefIndex = currRefIndex; + } + currRefIndex = nextRefIndex; + } + } + + + PX_INLINE void mapHandle(InplaceHandleBase& handle) const + { + if (handle._value != NULL_INDEX) + { + handle._value = _blocks[handle._value]._offset; + } + } + PX_INLINE uint8_t* getBufferPtr() + { + PX_ASSERT(_bufferPtr != 0); + _isChanged = true; + return _bufferPtr; + } + PX_INLINE const uint8_t* getBufferPtr() const + { + PX_ASSERT(_bufferPtr != 0); + return _bufferPtr; + } + + template <typename T> + PX_INLINE const T* resolveType(InplaceHandleBase handle) const + { + if (handle._value != NULL_INDEX) + { + const Block& block = _blocks[handle._value]; + PX_ASSERT(block._offset != uint32_t(-1)); + return reinterpret_cast<const T*>(getBufferPtr() + block._offset); + } + return 0; + } + template <typename T> + PX_INLINE T* resolveType(InplaceHandleBase handle) + { + if (handle._value != NULL_INDEX) + { + const Block& block = _blocks[handle._value]; + PX_ASSERT(block._offset != uint32_t(-1)); + return reinterpret_cast<T*>(getBufferPtr() + block._offset); + } + return 0; + } + +protected: + //buffer API + virtual uint8_t* storageResizeBuffer(uint32_t newSize) = 0; + + virtual void storageLock() {} + virtual void storageUnlock() {} + +public: + InplaceStorage() + { + _bufferPtr = 0; + _isChanged = false; + + _firstFreeBlockIndex = NULL_INDEX; + _lastAllocatedBlockIndex = NULL_INDEX; + _allocatedSize = 0; + + _groupListHead = 0; + _activeGroup = NULL; + + _firstFreeRefIndex = NULL_INDEX; + } + virtual ~InplaceStorage() + { + release(); + } + + void release() + { + releaseGroups(); + } + + bool isChanged() const + { + return _isChanged; + } + void setUnchanged() + { + _isChanged = false; + } + + template <typename T> + PX_INLINE bool fetch(InplaceHandleBase handle, T& out, uint32_t index = 0) const + { + const T* ptr = resolveType<T>(handle); + if (ptr != 0) + { + out = ptr[index]; + return true; + } + return false; + } + template <typename T> + PX_INLINE bool update(InplaceHandleBase handle, const T& in, uint32_t index = 0) + { + T* ptr = resolveType<T>(handle); + if (ptr != 0) + { + ptr[index] = in; + return true; + } + return false; + } + template <typename T> + PX_INLINE bool updateRange(InplaceHandleBase handle, const T* in, uint32_t count, uint32_t start = 0) + { + T* ptr = resolveType<T>(handle); + if (ptr != 0) + { + ::memcpy(ptr + start, in, sizeof(T) * count); + return true; + } + return false; + } + + + template <typename T> + PX_INLINE bool alloc(InplaceHandleBase& handle, uint32_t count = 1) + { + PX_ASSERT(count > 0); + handle._value = allocBlock(sizeof(T) * count, __alignof(T)); + if (handle._value != NULL_INDEX) + { + reflectElems<T>(handle, count); + return true; + } + return false; + } + + template <typename T> + PX_INLINE bool alloc(InplaceHandle<T>& handle, uint32_t count = 1) + { + return alloc<T>(static_cast<InplaceHandleBase&>(handle), count); + } + + PX_INLINE void free(InplaceHandleBase& handle) + { + if (handle._value != NULL_INDEX) + { + freeBlock(handle._value); + handle._value = NULL_INDEX; + } + } + + template <typename T> + bool realloc(InplaceHandleBase& handle, uint32_t oldCount, uint32_t newCount) + { + if (handle._value != NULL_INDEX) + { + PX_ASSERT(oldCount > 0); + if (oldCount != newCount) + { + if (newCount > 0) + { + if (resizeBlock(handle._value, sizeof(T) * newCount)) + { + if (newCount > oldCount) + { + reflectElems<T>(handle, newCount, oldCount); + } + return true; + } + return false; + } + free(handle); + } + } + else + { + PX_ASSERT(oldCount == 0); + if (newCount > 0) + { + return (alloc<T>(handle, newCount) != 0); + } + } + return true; + } + + + template <typename T> + PX_INLINE InplaceHandle<T> mappedHandle(InplaceHandle<T> handle) const + { + mapHandle(handle); + return handle; + } + + uint32_t mapTo(uint8_t* destPtr) const + { + PX_ASSERT(_lastAllocatedBlockIndex == NULL_INDEX || _blocks[_lastAllocatedBlockIndex]._offset + _blocks[_lastAllocatedBlockIndex]._size == _allocatedSize); + + memcpy(destPtr, getBufferPtr(), _allocatedSize); + + //iterate all blocks + for (uint32_t blockIndex = _lastAllocatedBlockIndex; blockIndex != NULL_INDEX; blockIndex = _blocks[blockIndex]._prevIndex) + { + const Block& block = _blocks[blockIndex]; + //iterate all refs in current block + for (uint32_t refIndex = block._firstRefIndex; refIndex != NULL_INDEX; refIndex = _handleRefs[refIndex].nextIndex) + { + const HandleRef& handleRef = _handleRefs[refIndex]; + PX_ASSERT(handleRef.ownerBlockIndex == blockIndex); + + uint32_t blockOffset = block._offset; + PX_ASSERT(blockOffset != uint32_t(-1)); + InplaceHandleBase& handle = *reinterpret_cast<InplaceHandleBase*>(destPtr + blockOffset + handleRef.offsetInBlock); + + mapHandle(handle); + } + } + return _allocatedSize; + } + + uint32_t getAllocatedSize() const + { + return _allocatedSize; + } + +private: + template <typename T> + T* reflectElems(InplaceHandleBase handle, uint32_t newCount, uint32_t oldCount = 0) + { + const Block& block = _blocks[handle._value]; + + uint8_t* ptr = (getBufferPtr() + block._offset); + T* ptrT0 = reinterpret_cast<T*>(ptr); + T* ptrT = ptrT0 + oldCount; + Reflector r(this, handle._value, ptr); + for (uint32_t index = oldCount; index < newCount; ++index) + { + ::new(ptrT) T; + InplaceTypeHelper::reflectType<0>(r, ReflectorArg(), *ptrT, InplaceTypeMemberDefaultTraits()); + ++ptrT; + } + return ptrT0; + } + + static PX_INLINE uint32_t alignUp(uint32_t size, uint32_t alignment) + { + PX_ASSERT(alignment > 0); + return (size + (alignment - 1)) & ~(alignment - 1); + } + + PX_INLINE int32_t getMoveDelta(uint32_t blockIndex, uint32_t moveOffset) const + { + PX_ASSERT(blockIndex != NULL_INDEX); + const uint32_t currOffset = _blocks[blockIndex]._offset; + + //calculate max alignment for all subsequent blocks + uint32_t alignment = 0; + do + { + const Block& block = _blocks[blockIndex]; + alignment = PxMax(alignment, block._alignment); + + blockIndex = block._nextIndex; + } + while (blockIndex != NULL_INDEX); + + int32_t moveDelta = (int32_t)moveOffset - (int32_t)currOffset; + //align moveDelta + if (moveDelta >= 0) + { + moveDelta += (alignment - 1); + moveDelta &= ~(alignment - 1); + } + else + { + moveDelta = -moveDelta; + moveDelta &= ~(alignment - 1); + moveDelta = -moveDelta; + } + PX_ASSERT(currOffset + moveDelta >= moveOffset); + return moveDelta; + } + + uint32_t getPrevAllocatedSize(uint32_t prevBlockIndex) const + { + uint32_t prevAllocatedSize = 0; + if (prevBlockIndex != NULL_INDEX) + { + const Block& prevBlock = _blocks[prevBlockIndex]; + prevAllocatedSize = prevBlock._offset + prevBlock._size; + } + return prevAllocatedSize; + } + + void moveBlocks(uint32_t moveBlockIndex, int32_t moveDelta) + { + if (moveDelta != 0) + { + const uint32_t currOffset = _blocks[moveBlockIndex]._offset; + const uint32_t moveOffset = currOffset + moveDelta; + + uint32_t moveSize = _allocatedSize - currOffset; + uint8_t* moveFromPtr = getBufferPtr() + currOffset; + uint8_t* moveToPtr = getBufferPtr() + moveOffset; + memmove(moveToPtr, moveFromPtr, moveSize); + + _allocatedSize += moveDelta; + //update moved blocks + do + { + Block& moveBlock = _blocks[moveBlockIndex]; + moveBlock._offset += moveDelta; + PX_ASSERT((moveBlock._offset & (moveBlock._alignment - 1)) == 0); + + moveBlockIndex = moveBlock._nextIndex; + } + while (moveBlockIndex != NULL_INDEX); + } + } + + void removeBlocks(uint32_t prevBlockIndex, uint32_t nextBlockIndex, uint32_t lastBlockIndex) + { + PX_UNUSED(lastBlockIndex); + + uint32_t prevAllocatedSize = getPrevAllocatedSize(prevBlockIndex); + if (prevBlockIndex != NULL_INDEX) + { + _blocks[prevBlockIndex]._nextIndex = nextBlockIndex; + } + if (nextBlockIndex != NULL_INDEX) + { + _blocks[nextBlockIndex]._prevIndex = prevBlockIndex; + + const int32_t moveDelta = getMoveDelta(nextBlockIndex, prevAllocatedSize); + moveBlocks(nextBlockIndex, moveDelta); + } + else + { + //last block + PX_ASSERT(lastBlockIndex == _lastAllocatedBlockIndex); + _lastAllocatedBlockIndex = prevBlockIndex; + + _allocatedSize = prevAllocatedSize; + } + shrinkBuffer(); + } + + PX_INLINE bool growBuffer(uint32_t newAllocatedSize) + { + PX_ASSERT(newAllocatedSize >= _allocatedSize); + + uint8_t* newBufferPtr = storageResizeBuffer(newAllocatedSize); + if (newBufferPtr == 0) + { + PX_ASSERT(0 && "Out of memory!"); + return false; + } + _bufferPtr = newBufferPtr; + return true; + } + + PX_INLINE void shrinkBuffer() + { + uint8_t* newBufferPtr = storageResizeBuffer(_allocatedSize); + PX_ASSERT(newBufferPtr != 0); + _bufferPtr = newBufferPtr; + } + + uint32_t allocBlock(uint32_t size, uint32_t alignment) + { + uint32_t insertBlockIndex; + uint32_t offset; + int32_t moveDelta; + uint32_t newAllocatedSize; + + PX_ASSERT(_activeGroup != NULL); + if (_activeGroup->_lastBlockIndex == NULL_INDEX || _activeGroup->_lastBlockIndex == _lastAllocatedBlockIndex) + { + //push_back new block + insertBlockIndex = NULL_INDEX; + offset = alignUp(_allocatedSize, alignment); + moveDelta = 0; + newAllocatedSize = offset + size; + } + else + { + //insert new block + insertBlockIndex = _blocks[_activeGroup->_lastBlockIndex]._nextIndex; + PX_ASSERT(insertBlockIndex != NULL_INDEX); + + uint32_t prevAllocatedSize = getPrevAllocatedSize(_blocks[insertBlockIndex]._prevIndex); + offset = alignUp(prevAllocatedSize, alignment); + const uint32_t moveOffset = offset + size; + moveDelta = getMoveDelta(insertBlockIndex, moveOffset); + newAllocatedSize = _allocatedSize + moveDelta; + } + + if (growBuffer(newAllocatedSize) == false) + { + return NULL_INDEX; + } + + //find free block + if (_firstFreeBlockIndex == NULL_INDEX) + { + _firstFreeBlockIndex = _blocks.size(); + _blocks.resize(_firstFreeBlockIndex + 1); + + _blocks.back()._nextFreeBlockIndex = NULL_INDEX; + } + uint32_t blockIndex = _firstFreeBlockIndex; + Block& block = _blocks[blockIndex]; + _firstFreeBlockIndex = block._nextFreeBlockIndex; + + //init block + block._size = size; + block._alignment = alignment; + block._offset = offset; + block._firstRefIndex = NULL_INDEX; + block._group = _activeGroup; + + PX_ASSERT((block._offset & (block._alignment - 1)) == 0); + + if (insertBlockIndex == NULL_INDEX) + { + //add new block after the _lastAllocatedBlockIndex + block._prevIndex = _lastAllocatedBlockIndex; + block._nextIndex = NULL_INDEX; + + if (_lastAllocatedBlockIndex != NULL_INDEX) + { + PX_ASSERT(_blocks[_lastAllocatedBlockIndex]._nextIndex == NULL_INDEX); + _blocks[_lastAllocatedBlockIndex]._nextIndex = blockIndex; + } + _lastAllocatedBlockIndex = blockIndex; + } + else + { + PX_ASSERT(_activeGroup->_lastBlockIndex != NULL_INDEX); + //insert new block before the insertBlockIndex + block._prevIndex = _activeGroup->_lastBlockIndex; + _blocks[_activeGroup->_lastBlockIndex]._nextIndex = blockIndex; + + block._nextIndex = insertBlockIndex; + _blocks[insertBlockIndex]._prevIndex = blockIndex; + + moveBlocks(insertBlockIndex, moveDelta); + PX_ASSERT(_allocatedSize == newAllocatedSize); + } + _allocatedSize = newAllocatedSize; + + //update group + _activeGroup->_lastBlockIndex = blockIndex; + + return blockIndex; + } + + + PX_INLINE void onRemoveHandle(const Block& block, InplaceHandleBase handle) + { + PX_UNUSED(block); + if (handle._value != InplaceHandleBase::NULL_VALUE) + { + PX_ASSERT(handle._value < _blocks.size()); + PX_ASSERT(_blocks[handle._value]._group == block._group); + + freeBlock(handle._value); + } + } + PX_INLINE void onRemoveHandleEmpty(const Block& , InplaceHandleBase ) + { + } + + void freeBlock(uint32_t blockIndex) + { + PX_ASSERT(blockIndex != NULL_INDEX); + PX_ASSERT(_activeGroup != NULL); + PX_ASSERT(_blocks[blockIndex]._group == _activeGroup); + + removeHandleRefs(&InplaceStorage::onRemoveHandle, blockIndex); + + Block& block = _blocks[blockIndex]; + + removeBlocks(block._prevIndex, block._nextIndex, blockIndex); + + //update group + if (_activeGroup->_lastBlockIndex == blockIndex) + { + _activeGroup->_lastBlockIndex = + (block._prevIndex != NULL_INDEX) && + (_blocks[block._prevIndex]._group == _activeGroup) ? block._prevIndex : NULL_INDEX; + } + + block.reset(); + //add block to free list + block._nextFreeBlockIndex = _firstFreeBlockIndex; + _firstFreeBlockIndex = blockIndex; + } + + bool resizeBlock(uint32_t blockIndex, uint32_t newSize) + { + if (newSize < _blocks[blockIndex]._size) + { + //remove refs + removeHandleRefs(&InplaceStorage::onRemoveHandle, blockIndex, newSize); + } + + Block& block = _blocks[blockIndex]; + const uint32_t nextBlockIndex = block._nextIndex; + + uint32_t newAllocatedSize = block._offset + newSize; + int32_t moveDelta = 0; + if (nextBlockIndex != NULL_INDEX) + { + moveDelta = getMoveDelta(nextBlockIndex, newAllocatedSize); + newAllocatedSize = _allocatedSize + moveDelta; + } + + const bool bGrow = (newAllocatedSize > _allocatedSize); + if (bGrow) + { + if (growBuffer(newAllocatedSize) == false) + { + return false; + } + } + + block._size = newSize; + + if (nextBlockIndex != NULL_INDEX) + { + moveBlocks(nextBlockIndex, moveDelta); + PX_ASSERT(_allocatedSize == newAllocatedSize); + } + _allocatedSize = newAllocatedSize; + if (!bGrow) + { + shrinkBuffer(); + } + return true; + } + + void groupInit(InplaceStorageGroup* group) + { + storageLock(); + + //init new group + group->_lastBlockIndex = NULL_INDEX; + group->_groupListPrev = 0; + group->_groupListNext = _groupListHead; + if (_groupListHead != NULL) + { + _groupListHead->_groupListPrev = group; + } + _groupListHead = group; + + storageUnlock(); + } + + void groupFree(InplaceStorageGroup* group) + { + storageLock(); + + if (group->_lastBlockIndex != NULL_INDEX) + { + uint32_t prevBlockIndex = group->_lastBlockIndex; + uint32_t nextBlockIndex = _blocks[group->_lastBlockIndex]._nextIndex; + do + { + uint32_t freeBlockIndex = prevBlockIndex; + Block& freeBlock = _blocks[freeBlockIndex]; + prevBlockIndex = freeBlock._prevIndex; + + removeHandleRefs(&InplaceStorage::onRemoveHandleEmpty, freeBlockIndex); + + freeBlock.reset(); + //add block to free list + freeBlock._nextFreeBlockIndex = _firstFreeBlockIndex; + _firstFreeBlockIndex = freeBlockIndex; + } + while (prevBlockIndex != NULL_INDEX && _blocks[prevBlockIndex]._group == group); + + PX_ASSERT(prevBlockIndex == NULL_INDEX || _blocks[prevBlockIndex]._group != group); + PX_ASSERT(nextBlockIndex == NULL_INDEX || _blocks[nextBlockIndex]._group != group); + + removeBlocks(prevBlockIndex, nextBlockIndex, group->_lastBlockIndex); + } + + //remove from GroupList + if (group->_groupListNext != 0) + { + group->_groupListNext->_groupListPrev = group->_groupListPrev; + } + if (group->_groupListPrev != 0) + { + group->_groupListPrev->_groupListNext = group->_groupListNext; + } + else + { + PX_ASSERT(_groupListHead == group); + _groupListHead = group->_groupListNext; + } + + storageUnlock(); + } + + void groupBegin(InplaceStorageGroup* group) + { + storageLock(); + + PX_ASSERT(_activeGroup == NULL); + _activeGroup = group; + } + + void groupEnd(InplaceStorageGroup* group) + { + PX_UNUSED(group); + PX_ASSERT(group == _activeGroup); + _activeGroup = NULL; + + storageUnlock(); + } + + void releaseGroups() + { + storageLock(); + + while (_groupListHead != 0) + { + InplaceStorageGroup* group = _groupListHead; + _groupListHead = _groupListHead->_groupListNext; + + group->reset(this); + } + + storageUnlock(); + } + + uint8_t* _bufferPtr; + bool _isChanged; + + uint32_t _allocatedSize; + + uint32_t _firstFreeBlockIndex; + uint32_t _lastAllocatedBlockIndex; + physx::Array<Block> _blocks; + + uint32_t _firstFreeRefIndex; + physx::Array<HandleRef> _handleRefs; + + InplaceStorageGroup* _groupListHead; + InplaceStorageGroup* _activeGroup; + + friend class InplaceStorageGroup; +}; + +PX_INLINE void InplaceStorageGroup::init(InplaceStorage& storage) +{ + PX_ASSERT(_storage == 0); + _storage = &storage; + getStorage().groupInit(this); +} +PX_INLINE void InplaceStorageGroup::release() +{ + if (_storage != 0) + { + getStorage().groupFree(this); + _storage = 0; + } +} +PX_INLINE void InplaceStorageGroup::begin() +{ + getStorage().groupBegin(this); +} +PX_INLINE void InplaceStorageGroup::end() +{ + getStorage().groupEnd(this); +} + +class InplaceStorageGroupScope +{ +private: + InplaceStorageGroupScope& operator=(const InplaceStorageGroupScope&); + InplaceStorageGroup& _group; + +public: + InplaceStorageGroupScope(InplaceStorageGroup& group) : _group(group) + { + _group.begin(); + } + ~InplaceStorageGroupScope() + { + _group.end(); + } +}; + +#define INPLACE_STORAGE_GROUP_SCOPE(group) InplaceStorageGroupScope scopeAccess_##group ( group ); InplaceStorage& _storage_ = group.getStorage(); + +//// +class ApexCpuInplaceStorage : public InplaceStorage +{ +public: + ApexCpuInplaceStorage(uint32_t allocStep = 4096) + : mAllocStep(allocStep) + { + mSize = 0; + mStoragePtr = 0; + } + ~ApexCpuInplaceStorage() + { + release(); + } + + void release() + { + if (mStoragePtr) + { + PX_FREE(mStoragePtr); + mSize = 0; + mStoragePtr = 0; + } + } + +protected: + //interface for InplaceStorage + uint8_t* storageResizeBuffer(uint32_t newSize) + { + if (newSize > mSize) + { + newSize = ((newSize + mAllocStep - 1) / mAllocStep) * mAllocStep; + PX_ASSERT(newSize > mSize && (newSize % mAllocStep) == 0); + uint8_t* newStoragePtr = (uint8_t*)PX_ALLOC(newSize, PX_DEBUG_EXP("ApexCpuInplaceStorage")); + if (!newStoragePtr) + { + return 0; + } + memcpy(newStoragePtr, mStoragePtr, mSize); + PX_FREE(mStoragePtr); + mSize = newSize; + mStoragePtr = newStoragePtr; + } + return mStoragePtr; + } + +private: + uint32_t mAllocStep; + uint32_t mSize; + uint8_t* mStoragePtr; +}; + + + +} +} // end namespace nvidia::apex + +#endif // __APEX_INPLACE_STORAGE_H__ |