void QStringUnicode::ReplaceBinaryCaseInsensitive(const QStringUnicode &strSearchedPattern, const QStringUnicode &strReplacement)
{
    icu::UnicodeString strPatternCopy = strSearchedPattern.m_strString;
    strPatternCopy.foldCase(U_FOLD_CASE_DEFAULT);
    icu::UnicodeString strResidentCopy = m_strString;
    strResidentCopy.foldCase(U_FOLD_CASE_DEFAULT);

    // Iterates over a copy of the original string, but modifying the original string
    int32_t nPosition = strResidentCopy.indexOf(strPatternCopy);
    int32_t nAccumulatedOffset = 0;
    const int32_t PATTERN_LENGTH = scast_q(strSearchedPattern.GetLength(), int32_t);
    const int32_t REPLACEMENT_LENGTH = scast_q(strReplacement.GetLength(), int32_t);
    const int32_t REPLACEMENT_LENGTH_DIFFERENCE = REPLACEMENT_LENGTH - PATTERN_LENGTH;

    while(nPosition != USEARCH_DONE)
    {
        m_strString.replace(nPosition + nAccumulatedOffset, PATTERN_LENGTH, strReplacement.m_strString);

        // An offset must be kept because the string being modified and the string the iterator traverses are not the same instance
        // Adding this offset we get the position of the found match in the modified string
        nAccumulatedOffset += REPLACEMENT_LENGTH_DIFFERENCE;

        nPosition = strResidentCopy.indexOf(strPatternCopy, nPosition + 1);
    }
}
void QStringUnicode::ReplaceCanonical(const QStringUnicode& strSearchedPattern, const QStringUnicode &strReplacement, const EQComparisonType &eComparisonType)
{
    // Creates the search object
    UErrorCode errorCode = U_ZERO_ERROR;
    icu::StringSearch search(strSearchedPattern.m_strString, m_strString, Locale::getEnglish(), NULL, errorCode);
    QE_ASSERT(U_SUCCESS(errorCode), "An unexpected error occurred when creating the internal search object");

    QStringUnicode::ConfigureSearch(eComparisonType, search);

    // Iterates over a copy of the original string, modifying the original string
    int32_t nPosition = search.next(errorCode);
    int32_t nAccumulatedOffset = 0;
    const int32_t PATTERN_LENGTH = scast_q(strSearchedPattern.GetLength(), int32_t);
    const int32_t REPLACEMENT_LENGTH = scast_q(strReplacement.GetLength(), int32_t);
    const int32_t REPLACEMENT_LENGTH_DIFFERENCE = REPLACEMENT_LENGTH - PATTERN_LENGTH;

    QE_ASSERT(U_SUCCESS(errorCode), "An unexpected error occurred when searching the pattern");

    while(nPosition != USEARCH_DONE)
    {
        m_strString.replace(nPosition + nAccumulatedOffset, PATTERN_LENGTH, strReplacement.m_strString);

        // An offset must be kept because the string being modified and the string the iterator traverses are not the same instance
        // Adding this offset we get the position of the found match in the modified string
        nAccumulatedOffset += REPLACEMENT_LENGTH_DIFFERENCE;

        nPosition = search.next(errorCode);
        QE_ASSERT(U_SUCCESS(errorCode), "An unexpected error occurred when searching the pattern");
    }
}
void SQVF32::Unpack(const vf32_q &pack, float_q &fFirst, float_q &fSecond, float_q &fThird, float_q &fFourth)
{
    #define QE_4BYTES_SIZE 4 // We are working with a 32-bits floats pack

    #if QE_FLOAT_SIZE != QE_4BYTES_SIZE
        // Types are different so we need to use known-size types and then invoke
        // implicit casting when copying to auxiliar variables.
        f32_q f_1 = scast_q(SQFloat::_0, f32_q);
        f32_q f_2 = scast_q(SQFloat::_0, f32_q);
        f32_q f_3 = scast_q(SQFloat::_0, f32_q);
        f32_q f_4 = scast_q(SQFloat::_0, f32_q);
    #else
        // Types are the same, no casting is needed so we only use references to maintain names used below
        f32_q& f_1 = fFirst;
        f32_q& f_2 = fSecond;
        f32_q& f_3 = fThird;
        f32_q& f_4 = fFourth;
    #endif

    f_1 = pack.m128_f32[0];
    f_2 = pack.m128_f32[1];
    f_3 = pack.m128_f32[2];
    f_4 = pack.m128_f32[3];

    #if QE_FLOAT_SIZE != QE_4BYTES_SIZE
        fFirst  = scast_q(f_1, float_q);
        fSecond = scast_q(f_2, float_q);
        fThird  = scast_q(f_3, float_q);
        fFourth = scast_q(f_4, float_q);
    #endif
}
u32_q QTimeSpan::GetMinutes() const
{
    return scast_q(m_uTimeSpan / (QTimeSpan::SECONDS_PER_MINUTE *
                                  QTimeSpan::MILLISECONDS_PER_SECOND *
                                  QTimeSpan::MICROSECONDS_PER_MILLISECOND *
                                  QTimeSpan::HUNDREDS_OF_NANOSECONDS_PER_MICROSECOND), u32_q);
}
string_q SQInteger::ToString<i8_q>(const i8_q &nValue)
{
    // [SMELL] Thund: This specialization is necessary since STL's converter treats signed chars
    //                in a different way than how it does with the other integer types.
    std::ostringstream output;
    output << scast_q(nValue, i32_q);

    return output.str().c_str();
}
u32_q QTimeSpan::GetDays() const
{
    return scast_q(m_uTimeSpan / (QTimeSpan::HOURS_PER_DAY *
                                  QTimeSpan::MINUTES_PER_HOUR *
                                  QTimeSpan::SECONDS_PER_MINUTE *
                                  QTimeSpan::MILLISECONDS_PER_SECOND *
                                  QTimeSpan::MICROSECONDS_PER_MILLISECOND *
                                  QTimeSpan::HUNDREDS_OF_NANOSECONDS_PER_MICROSECOND), u32_q);
}
int QStringUnicode::IndexOf(const QStringUnicode &strPattern, const EQComparisonType &eComparisonType, const unsigned int uStart) const
{
    int32_t nPosition = QStringUnicode::PATTERN_NOT_FOUND;

    if(!strPattern.IsEmpty() && !this->IsEmpty() && uStart < this->GetLength())
    {
        if(eComparisonType == EQComparisonType::E_BinaryCaseSensitive)
        {
            nPosition = m_strString.indexOf(strPattern.m_strString, scast_q(uStart, int32_t));
        }
        else if(eComparisonType == EQComparisonType::E_BinaryCaseInsensitive)
        {
            // There is no case insensitive indexOf in ICU so both strings are converted to lowercase before searching
            icu::UnicodeString strResidentCopy = m_strString;
            strResidentCopy.foldCase(U_FOLD_CASE_DEFAULT);
            icu::UnicodeString strPatternCopy = strPattern.m_strString;
            strPatternCopy.foldCase(U_FOLD_CASE_DEFAULT);
            nPosition = strResidentCopy.indexOf(strPatternCopy);
        }
        else
        {
            UErrorCode errorCode = U_ZERO_ERROR;

            // About string search with ICU: http://userguide.icu-project.org/collation/icu-string-search-service
            icu::StringSearch search(strPattern.m_strString, m_strString, Locale::getEnglish(), NULL, errorCode);
            QE_ASSERT(U_SUCCESS(errorCode), "An unexpected error occurred when creating the internal search object");

            search.setOffset(scast_q(uStart, int32_t), errorCode);
            QE_ASSERT(U_SUCCESS(errorCode), "An unexpected error occurred when setting the offset of the search");

            QStringUnicode::ConfigureSearch(eComparisonType, search);
            nPosition = search.next(errorCode);

            QE_ASSERT(U_SUCCESS(errorCode), "An unexpected error occurred when searching the pattern");
        }

        if(nPosition == USEARCH_DONE)
            nPosition = QStringUnicode::PATTERN_NOT_FOUND;
    }

    return nPosition;
}
void SQVF32::Pack(const float_q &fFirst, const float_q &fSecond, const float_q &fThird, const float_q &fFourth, vf32_q &pack)
{
    #define QE_4BYTES_SIZE 4 // We are working with a 32-bits floats pack

    #if QE_FLOAT_SIZE != QE_4BYTES_SIZE
        // Types are different so we need to use known-size types and then invoke
        // implicit casting when copying to auxiliar variables.
        f32_q f_1 = scast_q(fFirst, f32_q);
        f32_q f_2 = scast_q(fSecond, f32_q);
        f32_q f_3 = scast_q(fThird, f32_q);
        f32_q f_4 = scast_q(fFourth, f32_q);
    #else
        // Types are the same, no casting is needed so we only use references to maintain names used below
        const f32_q& f_1 = fFirst;
        const f32_q& f_2 = fSecond;
        const f32_q& f_3 = fThird;
        const f32_q& f_4 = fFourth;
    #endif

    pack.m128_f32[0] = f_1;
    pack.m128_f32[1] = f_2;
    pack.m128_f32[2] = f_3;
    pack.m128_f32[3] = f_4;
}