void QLinearAllocator::Reallocate(const pointer_uint_q uNewSize, void* pNewLocation)
{
    QE_ASSERT_ERROR(m_bUsesExternalBuffer, "This allocator uses an internal buffer so external reallocation is not possible");
    QE_ASSERT_ERROR(pNewLocation != null_q, "The pointer to the new buffer cannot be null");
    QE_ASSERT_WARNING(uNewSize > m_uSize, "The new size must be greater than the current size");

    if(uNewSize > m_uSize)
    {
        pointer_uint_q uAdjustment = m_uAlignment - ((pointer_uint_q)pNewLocation & (m_uAlignment - 1U));

        if(uAdjustment == m_uAlignment)
            uAdjustment = 0;

        const pointer_uint_q ADJUSTED_SIZE = uNewSize - uAdjustment;
        QE_ASSERT_WARNING(ADJUSTED_SIZE > m_uSize, "Due to the alignment adjustment, there is not enough space in the new buffer to allocate the data to be moved");

        if(ADJUSTED_SIZE > m_uSize)
        {
            const pointer_uint_q BYTES_TO_COPY = this->GetAllocatedBytes();
            void* pAdjustedLocation = (void*)((pointer_uint_q)pNewLocation + uAdjustment);
            memcpy(pAdjustedLocation, m_pBase, BYTES_TO_COPY);

            // Changes the base pointer to the first memory address that is aligned as intended
            m_pBase = pAdjustedLocation;
            m_pTop = (void*)((pointer_uint_q)m_pBase + BYTES_TO_COPY);
            m_uSize = ADJUSTED_SIZE; // Some free space may be lost
        }
    }
}
QAlignment::QAlignment(const pointer_uint_q &uAlignment)
{
    // Checking first if the alignment value is a power of 2.
    QE_ASSERT_WARNING( !(0 == uAlignment) && !(uAlignment & (uAlignment - 1)) , "The input alignment value must be a power of 2");

    m_uAlignment = uAlignment;
}
bool SQFloat::AreEqual(const float_q &fValueA, const float_q &fValueB, const float_q &fTolerance)
{
    // The tolerance provided must be equal to or greater than the system tolerance. If the tolerance is too small it could become useless.
    QE_ASSERT_WARNING(fTolerance >= SQFloat::Epsilon, "The tolerance provided must be equal to or greater than the system tolerance. If the tolerance is too small it could become useless");

    return SQFloat::Abs(fValueA - fValueB) <= fTolerance;
}
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);
}
QMatrix2x2& QMatrix2x2::operator/=(const float_q &fScalar)
{
    QE_ASSERT_WARNING(fScalar != SQFloat::_0, "Input value must not equal zero");

    const float_q &DIVISOR = SQFloat::_1/fScalar;

    this->ij[0][0] *= DIVISOR;
    this->ij[0][1] *= DIVISOR;
    this->ij[1][0] *= DIVISOR;
    this->ij[1][1] *= DIVISOR;

    return *this;
}
void QPoolAllocator::Reallocate(const pointer_uint_q uNewSize)
{
    QE_ASSERT_WARNING(uNewSize > m_uPoolSize, "The new size must be greater than the current size of the pool.");

    if(uNewSize > m_uPoolSize)
    {
        void* pNewLocation = operator new(uNewSize, m_uAlignment);

        this->InternalReallocate(uNewSize, pNewLocation);

        m_bNeedDestroyMemoryChunk = true;
    }
}
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;
}
QMatrix2x2 QMatrix2x2::operator/(const float_q &fScalar) const
{

    QE_ASSERT_WARNING(fScalar != SQFloat::_0, "Input value must not equal zero");

    const float_q &DIVISOR = SQFloat::_1/fScalar;

    QMatrix2x2 aux;

    aux.ij[0][0] = this->ij[0][0] * DIVISOR;
    aux.ij[0][1] = this->ij[0][1] * DIVISOR;
    aux.ij[1][0] = this->ij[1][0] * DIVISOR;
    aux.ij[1][1] = this->ij[1][1] * DIVISOR;

    return aux;
}
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;
    }
}
QTimeSpan& QTimeSpan::operator+= (const QTimeSpan& timeSpan)
{
    bool bNotGreaterThanMaxValue = ((QTimeSpan::MAXIMUM_VALUE  - this->m_uTimeSpan) >= timeSpan.m_uTimeSpan);
    // Assertion to verify that we will not get overflow while calculating the time span
    QE_ASSERT_WARNING(bNotGreaterThanMaxValue == true, "The addition of the two timespan objects can not be higher than maximum value");

    if (bNotGreaterThanMaxValue)
    {
        this->m_uTimeSpan += timeSpan.m_uTimeSpan;
    }
    else
    {
        this->m_uTimeSpan = QTimeSpan::MAXIMUM_VALUE;
    }

    return *this;
}
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* 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::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;
}
QTimeSpan::QTimeSpan(const u64_q uDays, const u64_q uHours, const u64_q uMinutes, const u64_q uSeconds, const u64_q uMilliseconds, const u64_q uMicroseconds, const u64_q uHundredsNanoseconds)
{
    // Constants containing the max value for each parameter.
    // Remember we have to convert them to hundreds of nanoseconds.
    const u64_q MAX_MICROSECONDS = MAXIMUM_VALUE / HUNDREDS_OF_NANOSECONDS_PER_MICROSECOND;
    const u64_q MAX_MILLISECONDS = MAXIMUM_VALUE / (HUNDREDS_OF_NANOSECONDS_PER_MICROSECOND * MICROSECONDS_PER_MILLISECOND );
    const u64_q MAX_SECONDS = MAXIMUM_VALUE / (HUNDREDS_OF_NANOSECONDS_PER_MICROSECOND * MILLISECONDS_PER_SECOND * MICROSECONDS_PER_MILLISECOND);
    const u64_q MAX_MINUTES = MAXIMUM_VALUE / (HUNDREDS_OF_NANOSECONDS_PER_MICROSECOND * SECONDS_PER_MINUTE * MILLISECONDS_PER_SECOND * MICROSECONDS_PER_MILLISECOND);
    const u64_q MAX_HOURS = MAXIMUM_VALUE / (HUNDREDS_OF_NANOSECONDS_PER_MICROSECOND * MINUTES_PER_HOUR * SECONDS_PER_MINUTE * MILLISECONDS_PER_SECOND * MICROSECONDS_PER_MILLISECOND);
    const u64_q MAX_DAYS = MAXIMUM_VALUE / (HUNDREDS_OF_NANOSECONDS_PER_MICROSECOND * HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE * MILLISECONDS_PER_SECOND * MICROSECONDS_PER_MILLISECOND);

    bool bNotGreaterThanMaxValue = (uDays <= MAX_DAYS                &&
                                   uHours <= MAX_HOURS               &&
                                   uMinutes <= MAX_MINUTES           &&
                                   uSeconds <= MAX_SECONDS           &&
                                   uMilliseconds <= MAX_MILLISECONDS &&
                                   uMicroseconds <= MAX_MICROSECONDS &&
                                   uHundredsNanoseconds <= MAXIMUM_VALUE);

    // Assertion to verify that we will not get overflow while calculating the time span
    QE_ASSERT_WARNING(bNotGreaterThanMaxValue == true, "Parameters must be lower than maximum values");

    // To avoid overflow if it happens return max value allowed
    if (!bNotGreaterThanMaxValue)
    {
          m_uTimeSpan = MAXIMUM_VALUE;
    }
    else
    {
        u64_q uMicrosecondsToHundreds = QTimeSpan::HUNDREDS_OF_NANOSECONDS_PER_MICROSECOND * uMicroseconds;
        u64_q uMillisecondsToHundreds = QTimeSpan::HUNDREDS_OF_NANOSECONDS_PER_MICROSECOND * QTimeSpan::MICROSECONDS_PER_MILLISECOND * uMilliseconds;
        u64_q uSecondsToHundreds = QTimeSpan::HUNDREDS_OF_NANOSECONDS_PER_MICROSECOND * QTimeSpan::MILLISECONDS_PER_SECOND * uSeconds * QTimeSpan::MICROSECONDS_PER_MILLISECOND;
        u64_q uMinutesToHundreds = QTimeSpan::HUNDREDS_OF_NANOSECONDS_PER_MICROSECOND * QTimeSpan::SECONDS_PER_MINUTE * uMinutes * QTimeSpan::MILLISECONDS_PER_SECOND * QTimeSpan::MICROSECONDS_PER_MILLISECOND;
        u64_q uHoursToHundreds = QTimeSpan::HUNDREDS_OF_NANOSECONDS_PER_MICROSECOND * QTimeSpan::MINUTES_PER_HOUR * uHours * QTimeSpan::SECONDS_PER_MINUTE * QTimeSpan::MILLISECONDS_PER_SECOND * QTimeSpan::MICROSECONDS_PER_MILLISECOND;
        u64_q uDaysToHundreds = QTimeSpan::HUNDREDS_OF_NANOSECONDS_PER_MICROSECOND * QTimeSpan::HOURS_PER_DAY * uDays * QTimeSpan::MINUTES_PER_HOUR * QTimeSpan::SECONDS_PER_MINUTE * QTimeSpan::MILLISECONDS_PER_SECOND * QTimeSpan::MICROSECONDS_PER_MILLISECOND;

        // Now check that we will not have overflow with the addition either
        bNotGreaterThanMaxValue = uMicrosecondsToHundreds <= (MAXIMUM_VALUE - uHundredsNanoseconds ) &&
                                  uMillisecondsToHundreds <= (MAXIMUM_VALUE - (uHundredsNanoseconds + uMicrosecondsToHundreds)) &&
                                  uSecondsToHundreds <= (MAXIMUM_VALUE - (uHundredsNanoseconds + uMicrosecondsToHundreds + uMillisecondsToHundreds)) &&
                                  uMinutesToHundreds <= (MAXIMUM_VALUE - (uHundredsNanoseconds + uMicrosecondsToHundreds + uMillisecondsToHundreds + uSecondsToHundreds)) &&
                                  uHoursToHundreds <= (MAXIMUM_VALUE - (uHundredsNanoseconds + uMicrosecondsToHundreds + uMillisecondsToHundreds + uSecondsToHundreds + uMinutesToHundreds)) &&
                                  uDaysToHundreds <= (MAXIMUM_VALUE - (uHundredsNanoseconds + uMicrosecondsToHundreds + uMillisecondsToHundreds + uSecondsToHundreds + uMinutesToHundreds + uHoursToHundreds));

        QE_ASSERT_WARNING(bNotGreaterThanMaxValue == true, "The converted values must be low enough to avoid overflow");

        // To avoid overflow if it happens return max value allowed
        if (!bNotGreaterThanMaxValue)
        {
           m_uTimeSpan = MAXIMUM_VALUE;
        }
        else
        {
           // Add all the parameters
           m_uTimeSpan = uHundredsNanoseconds + uMicrosecondsToHundreds +
                         uMillisecondsToHundreds + uSecondsToHundreds +
                         uMinutesToHundreds + uHoursToHundreds + uDaysToHundreds;
        }
    }

}