QPoolAllocator::QPoolAllocator(const pointer_uint_q uSize, const pointer_uint_q uBlockSize, const QAlignment &alignment) : m_uBlockSize(uBlockSize), m_uPoolSize(uSize), m_uAllocatedBytes(0), m_uAlignment(alignment), m_bNeedDestroyMemoryChunk(true) { QE_ASSERT_ERROR( 0 != uSize, "Size cannot be zero" ); QE_ASSERT_ERROR( 0 != uBlockSize, "Block size cannot be zero" ); m_pAllocatedMemory = operator new(m_uPoolSize, alignment); QE_ASSERT_ERROR( null_q != m_pAllocatedMemory, "Pointer to allocated memory is null" ); m_pFirst = m_pAllocatedMemory; m_uBlocksCount = m_uPoolSize / uBlockSize; this->AllocateFreeBlocksList(); }
void QPoolAllocator::AllocateFreeBlocksList() { m_ppFreeBlocks = (void**) operator new(m_uBlocksCount * sizeof(void**)); QE_ASSERT_ERROR( null_q != m_ppFreeBlocks, "Pointer to allocated memory for internals is null" ); m_ppNextFreeBlock = m_ppFreeBlocks; m_uSize = m_uPoolSize + m_uBlocksCount * sizeof(void**); this->ClearFreeBlocksList(); }
void SQPoint::Translate(const float_q &fTranslationX, const float_q &fTranslationY, const float_q &fTranslationZ, QVector4* arPoints, const unsigned int &uElements) { // Checks that the point array is not null QE_ASSERT_ERROR( arPoints != null_q, "Input array must not be null" ); for(unsigned int i = 0; i < uElements; ++i) { SQPoint::Translate(fTranslationX, fTranslationY, fTranslationZ, arPoints[i]); } }
void SQPoint::Transform(const QTransformationMatrix3x3 &transformation, QVector2* arPoints, const unsigned int &uElements) { // Checks that the point array is not null QE_ASSERT_ERROR( arPoints != null_q, "Input array must not be null" ); for(unsigned int i = 0; i < uElements; ++i) { arPoints[i] = arPoints[i].Transform(transformation); } }
QLinearAllocator::QLinearAllocator(const pointer_uint_q uSize, const QAlignment &alignment) : m_uSize(uSize), m_bUsesExternalBuffer(false), m_uAlignment(alignment) { QE_ASSERT_ERROR(uSize > 0, "The size of the buffer cannot be zero."); m_pBase = ::operator new(uSize, alignment); m_pTop = m_pBase; }
void SQPoint::Translate(const QTranslationMatrix<QMatrix4x4> &translation, QVector4* arPoints, const unsigned int &uElements) { // Checks that the point array is not null QE_ASSERT_ERROR( arPoints != null_q, "Input array must not be null" ); for(unsigned int i = 0; i < uElements; ++i) { SQPoint::Translate(translation, arPoints[i]); } }
QLinearAllocator::QLinearAllocator(const pointer_uint_q uSize, void* pBuffer, const QAlignment &alignment) : m_pBase(pBuffer), m_pTop(pBuffer), m_uSize(uSize), m_bUsesExternalBuffer(true), m_uAlignment(alignment) { QE_ASSERT_ERROR(uSize > 0, "The size of the buffer cannot be zero."); QE_ASSERT_ERROR(pBuffer != null_q, "The pointer to the external buffer cannot be null."); pointer_uint_q uAdjustment = m_uAlignment - ((pointer_uint_q)m_pBase & (m_uAlignment - 1U)); // Changes the base pointer to the first memory address that is aligned as intended if(uAdjustment != m_uAlignment) { m_pBase = (void*)((pointer_uint_q)m_pBase + uAdjustment); m_pTop = m_pBase; m_uSize -= uAdjustment; // Some free space is lost } }
bool QLinearAllocator::CanAllocate(const pointer_uint_q uSize, const QAlignment &alignment) const { QE_ASSERT_ERROR(uSize > 0, "The size of the memory block to be allocated cannot be zero."); pointer_uint_q uAdjustment = alignment - ((pointer_uint_q)m_pTop & (alignment - 1U)); if(uAdjustment == alignment) uAdjustment = 0; return m_uSize - this->GetAllocatedBytes() >= uSize + uAdjustment; }
void QLinearAllocator::CopyTo(QLinearAllocator &destination) const { QE_ASSERT_ERROR(destination.GetSize() >= this->GetAllocatedBytes(), "The input allocator's size must be greater than or equal to the size of the allocated bytes in the resident allocator."); QE_ASSERT_WARNING(destination.m_uAlignment == m_uAlignment, "The alignment of the input allocator is different from the resident allocator's."); const pointer_uint_q BYTES_TO_COPY = this->GetAllocatedBytes(); memcpy(destination.m_pBase, m_pBase, BYTES_TO_COPY); destination.m_pTop = (void*)((pointer_uint_q)destination.m_pBase + BYTES_TO_COPY); }
void SQPoint::Scale(const float_q &fScaleX, const float_q &fScaleY, QVector2* arPoints, const unsigned int &uElements) { // Checks that the point array is not null QE_ASSERT_ERROR( arPoints != null_q, "Input array must not be null" ); for(unsigned int i = 0; i < uElements; ++i) { arPoints[i].x *= fScaleX; arPoints[i].y *= fScaleY; } }
QPoolAllocator::QPoolAllocator(const pointer_uint_q uSize, const pointer_uint_q uBlockSize, const void *pBuffer) : m_uBlockSize(uBlockSize), m_uPoolSize(uSize), m_uAllocatedBytes(0), m_uAlignment(QAlignment(sizeof(void**))), m_bNeedDestroyMemoryChunk(false) { QE_ASSERT_ERROR( 0 != uSize, "Size cannot be zero" ); QE_ASSERT_ERROR( 0 != uBlockSize, "Block size cannot be zero" ); QE_ASSERT_ERROR( 0 != pBuffer, "Pointer to buffer cannot be null" ); // Calculates needed memory address offset (adjustment) for the chunk starts at multiple of alignment pointer_uint_q uAdjustment = m_uAlignment - ((pointer_uint_q)pBuffer & (m_uAlignment - 1)); if(uAdjustment == m_uAlignment ) uAdjustment = 0; m_pAllocatedMemory = (void**)((pointer_uint_q)pBuffer + uAdjustment); m_pFirst = m_pAllocatedMemory; m_uBlocksCount = (m_uPoolSize - uAdjustment) / uBlockSize; this->AllocateFreeBlocksList(); }
void SQPoint::RotateWithPivot(const QRotationMatrix3x3 &rotation, const QBaseVector3 &vPivot, QVector3* arPoints, const unsigned int &uElements) { // Checks that the point array is not null QE_ASSERT_ERROR( arPoints != null_q, "Input array must not be null" ); for(unsigned int i = 0; i < uElements; ++i) { arPoints[i] -= vPivot; SQPoint::Rotate(rotation, arPoints[i]); arPoints[i] += vPivot; } }
void SQPoint::RotateWithPivot(const float_q &fRotationAngle, const QBaseVector2 &vPivot, QVector2* arPoints, const unsigned int &uElements) { // Checks that the point array is not null QE_ASSERT_ERROR( arPoints != null_q, "Input array must not be null" ); for(unsigned int i = 0; i < uElements; ++i) { arPoints[i] -= vPivot; arPoints[i] = arPoints[i].Transform(fRotationAngle); arPoints[i] += vPivot; } }
void SQPoint::ScaleWithPivot(const QScalingMatrix3x3 &scale, const QBaseVector4 &vPivot, QVector4* arPoints, const unsigned int &uElements) { // Checks that the point array is not null QE_ASSERT_ERROR( arPoints != null_q, "Input array must not be null" ); for(unsigned int i = 0; i < uElements; ++i) { arPoints[i] -= vPivot; SQPoint::Scale(scale, arPoints[i]); arPoints[i] += vPivot; } }
QPoolAllocator::QPoolAllocator(const pointer_uint_q uSize, const pointer_uint_q uBlockSize, const void *pBuffer, const QAlignment &alignment) : m_uBlockSize(uBlockSize), m_uPoolSize(uSize), m_uAllocatedBytes(0), m_uAlignment(alignment), m_bNeedDestroyMemoryChunk(false) { QE_ASSERT_ERROR( 0 != uSize, "Size cannot be zero" ); QE_ASSERT_ERROR( 0 != uBlockSize, "Block size cannot be zero" ); QE_ASSERT_ERROR( 0 != pBuffer, "Pointer to buffer cannot be null" ); pointer_uint_q uAdjustment = alignment - ((pointer_uint_q)pBuffer & (alignment - 1)); if(uAdjustment == alignment ) uAdjustment = 0; m_pAllocatedMemory = (void**)((pointer_uint_q)pBuffer + uAdjustment); m_pFirst = m_pAllocatedMemory; m_uPoolSize -= uAdjustment; // Some free space is lost m_uBlocksCount = m_uPoolSize / uBlockSize; this->AllocateFreeBlocksList(); }
void SQPoint::ScaleWithPivot(const float_q &fScaleX, const float_q fScaleY, const float_q &fScaleZ, const QBaseVector3 &vPivot, QVector3* arPoints, const unsigned int &uElements) { // Checks that the point array is not null QE_ASSERT_ERROR( arPoints != null_q, "Input array must not be null" ); for(unsigned int i = 0; i < uElements; ++i) { arPoints[i] -= vPivot; SQPoint::Scale(fScaleX, fScaleY, fScaleZ, arPoints[i]); arPoints[i] += vPivot; } }
void* QLinearAllocator::Allocate(const pointer_uint_q uSize) { QE_ASSERT_ERROR(uSize > 0, "The size of the memory block to be allocated cannot be zero."); QE_ASSERT_WARNING(this->CanAllocate(uSize), "The size of the memory block to be allocated does not fit in the available free space."); void* pAllocatedMemory = null_q; if(this->CanAllocate(uSize)) { pAllocatedMemory = m_pTop; m_pTop = (void*)((pointer_uint_q)m_pTop + uSize); } return pAllocatedMemory; }
void QPoolAllocator::Reallocate(const pointer_uint_q uNewSize, const void* pNewLocation) { QE_ASSERT_WARNING(uNewSize > m_uPoolSize, "The new size must be greater than the current size of the pool."); QE_ASSERT_ERROR(pNewLocation != null_q, "The input new location cannot be null."); if(uNewSize > m_uPoolSize && pNewLocation != null_q) { pointer_uint_q uNewLocationAddress = (pointer_uint_q)pNewLocation; pointer_uint_q uAlignmentOffset = m_uAlignment - (uNewLocationAddress % m_uAlignment); void* pAdjustedNewLocation = (void*)((pointer_uint_q)pNewLocation + uAlignmentOffset); this->InternalReallocate(uNewSize, pAdjustedNewLocation); m_bNeedDestroyMemoryChunk = false; } }
void QLinearAllocator::Reallocate(const pointer_uint_q uNewSize) { QE_ASSERT_ERROR(!m_bUsesExternalBuffer, "This allocator uses an external buffer so internal reallocation is not possible"); QE_ASSERT_WARNING(uNewSize > m_uSize, "The new size must be greater than the current size"); if(uNewSize > m_uSize) { const pointer_uint_q BYTES_TO_COPY = this->GetAllocatedBytes(); void* pNewBuffer = ::operator new(uNewSize, QAlignment(m_uAlignment)); memcpy(pNewBuffer, m_pBase, BYTES_TO_COPY); ::operator delete(m_pBase, QAlignment(m_uAlignment)); m_pBase = pNewBuffer; m_pTop = (void*)((pointer_uint_q)m_pBase + BYTES_TO_COPY); m_uSize = uNewSize; } }
void SQPoint::TransformWithPivot(const QTransformationMatrix<QMatrix4x4> &transformation, const QBaseVector4 &vPivot, QVector4* arPoints, const unsigned int &uElements) { // Checks that the point array is not null QE_ASSERT_ERROR( arPoints != null_q, "Input array must not be null" ); for(unsigned int i = 0; i < uElements; ++i) { arPoints[i].x -= vPivot.x; arPoints[i].y -= vPivot.y; arPoints[i].z -= vPivot.z; SQPoint::Transform(transformation, arPoints[i]); arPoints[i].x += vPivot.x; arPoints[i].y += vPivot.y; arPoints[i].z += vPivot.z; } }
void* QLinearAllocator::Allocate(const pointer_uint_q uSize, const QAlignment &alignment) { QE_ASSERT_ERROR(uSize > 0, "The size of the memory block to be allocated cannot be zero."); QE_ASSERT_WARNING(this->CanAllocate(uSize, alignment), "The size of the memory block to be allocated (plus the alignment adjustment) does not fit in the available free space."); void* pAllocatedMemory = null_q; if(this->CanAllocate(uSize, alignment)) { pointer_uint_q uAdjustment = alignment - ((pointer_uint_q)m_pTop & (alignment - 1U)); if(uAdjustment == alignment) uAdjustment = 0; pAllocatedMemory = (void*)((pointer_uint_q)m_pTop + uAdjustment); m_pTop = (void*)((pointer_uint_q)m_pTop + uSize + uAdjustment); } return pAllocatedMemory; }
void QPoolAllocator::InternalReallocate(const pointer_uint_q uNewSize, void* pNewLocation) { pointer_uint_q uNewBlocksCount = uNewSize / m_uBlockSize; QE_ASSERT_ERROR( null_q != pNewLocation, "Pointer to allocated memory is null" ); memcpy(pNewLocation, m_pFirst, m_uBlockSize * m_uBlocksCount); // Copies the free block list // ----------------------------------- void** ppNewFreeBlockList = (void**) operator new(uNewBlocksCount * sizeof(void**)); QE_ASSERT_ERROR( null_q != ppNewFreeBlockList, "Pointer to allocated memory for internals is null" ); if(null_q == m_ppNextFreeBlock) // No free blocks in source. { // Appends extra destination free blocks pointers // ppNext = first free block of remaining free blocks. void** ppNext = ppNewFreeBlockList + m_uBlocksCount; // Assigns the next free block m_ppNextFreeBlock = ppNext; // Frees remaining blocks from destination redoing the rest of the list. for( pointer_uint_q uIndex = m_uBlocksCount; uIndex < uNewBlocksCount - 1U; ++uIndex ) { *ppNext = (void*)(ppNext + 1U); ++ppNext; } *ppNext = null_q; } else { // Copy free blocks pointers list from source to destination void** ppLastFreeBlock = m_ppNextFreeBlock; while( null_q != *ppLastFreeBlock ) { // Index of the next free block in the source = *ppLastFreeBlock - m_ppFreeBlocks pointer_uint_q uLastFreeBlockPosition = (void**)(ppLastFreeBlock) - m_ppFreeBlocks; pointer_uint_q uNextFreeBlockPosition = (void**)(*ppLastFreeBlock) - m_ppFreeBlocks; *(ppNewFreeBlockList + uLastFreeBlockPosition) = ppNewFreeBlockList + uNextFreeBlockPosition; // Moves to the next free block ppLastFreeBlock = (void**)*ppLastFreeBlock; } // Assigns the next free block in the destination (same block index as in origin). m_ppNextFreeBlock = ppNewFreeBlockList + (m_ppNextFreeBlock - m_ppFreeBlocks); // Appends extra free blocks pointers of destination // Links copied free blocks list from source to remaining free blocks from destination. // ppNext = first free block of remaining free blocks. void** ppNext = ppNewFreeBlockList + m_uBlocksCount; // Links two lists. *(ppNewFreeBlockList + (ppLastFreeBlock - m_ppFreeBlocks)) = ppNext; // Frees the rest of blocks from destination redoing the rest of the list. for( pointer_uint_q uIndex = m_uBlocksCount; uIndex < uNewBlocksCount - 1U; ++uIndex ) { *ppNext = (void*)(ppNext + 1U); ++ppNext; } *ppNext = null_q; } // Updates some additional fields // --------------------------------- m_uBlocksCount = uNewBlocksCount; m_uPoolSize = uNewSize; m_uSize = m_uPoolSize + sizeof(void**) * m_uBlocksCount; // Frees the old buffers // ------------------------- if(m_bNeedDestroyMemoryChunk) operator delete(m_pAllocatedMemory, m_uAlignment); m_pAllocatedMemory = pNewLocation; m_pFirst = m_pAllocatedMemory; operator delete(m_ppFreeBlocks); m_ppFreeBlocks = ppNewFreeBlockList; }
bool QLinearAllocator::CanAllocate(const pointer_uint_q uSize) const { QE_ASSERT_ERROR(uSize > 0, "The size of the memory block to be allocated cannot be zero."); return m_uSize - this->GetAllocatedBytes() >= uSize; }
void QPoolAllocator::CopyTo(QPoolAllocator &poolAllocator) const { QE_ASSERT_ERROR(m_uBlocksCount <= poolAllocator.m_uBlocksCount, "Blocks count of destination pool allocator must be greater or equal than the source pool allocator" ); QE_ASSERT_ERROR(m_uPoolSize <= poolAllocator.m_uPoolSize, "Chunk size for allocations must be greater or equal in the destination pool allocator than in the source pool allocator" ); QE_ASSERT_ERROR(m_uBlockSize == poolAllocator.m_uBlockSize, "Block sizes of origin and destination pool allocators must be equal"); QE_ASSERT_WARNING(poolAllocator.m_uAlignment == m_uAlignment, "The alignment of the input allocator is different from the resident allocator's."); if(null_q == m_ppNextFreeBlock) { // No free blocks in source. Append extra destination free blocks pointers if it has more blocks count. if(m_uBlocksCount < poolAllocator.m_uBlocksCount) { // ppNext = first free block of remaining free blocks. void **ppNext = poolAllocator.m_ppFreeBlocks + m_uBlocksCount; // Assigns the next free block in the destination pool poolAllocator.m_ppNextFreeBlock = ppNext; // Frees remaining blocks from destination redoing the rest of the list. for( pointer_uint_q uIndex = m_uBlocksCount; uIndex < poolAllocator.m_uBlocksCount - 1; ++uIndex ) { *ppNext = (void*)((void**)ppNext + 1); ppNext = (void**)*ppNext; } *ppNext = null_q; } else { poolAllocator.m_ppNextFreeBlock = null_q; } } else { // Assigns the next free block in the destination pool (same block index as in origin). poolAllocator.m_ppNextFreeBlock = poolAllocator.m_ppFreeBlocks + (m_ppNextFreeBlock - m_ppFreeBlocks); // Copy free blocks pointers list from source to destination void **ppLastFreeBlock = m_ppNextFreeBlock; while( null_q != *ppLastFreeBlock ) { // Index of the next free block in the source = *ppLastFreeBlock - m_ppFreeBlocks *(poolAllocator.m_ppFreeBlocks + ((void**)ppLastFreeBlock - m_ppFreeBlocks)) = poolAllocator.m_ppFreeBlocks + ((void**)*ppLastFreeBlock - m_ppFreeBlocks); // ppLastFreeBlock will contain the pointer to last free block in the list or null if there are no free blocks // when exits from the while loop. if(null_q != *ppLastFreeBlock) ppLastFreeBlock = (void**)*ppLastFreeBlock; } if(m_uBlocksCount < poolAllocator.m_uBlocksCount) { // Appends extra free blocks pointers of destination // Links copied free blocks list from source to remaining free blocks from destination. // ppNext = first free block of remaining free blocks. void **ppNext = poolAllocator.m_ppFreeBlocks + m_uBlocksCount; // Links two lists. *(poolAllocator.m_ppFreeBlocks + (ppLastFreeBlock - m_ppFreeBlocks)) = ppNext; // Frees the rest of blocks from destination redoing the rest of the list. for( pointer_uint_q uIndex = m_uBlocksCount; uIndex < poolAllocator.m_uBlocksCount - 1; uIndex++ ) { *ppNext = (void*)((void**)ppNext + 1); ppNext = (void**)*ppNext; } *ppNext = null_q; } } // Copies all source blocks in destination memcpy(poolAllocator.m_pFirst, m_pFirst, m_uBlockSize * m_uBlocksCount); poolAllocator.m_uAllocatedBytes = m_uAllocatedBytes; }