Unify and deduplicate to[U]Int[_WithLength]

Change-Id: I05e71b36030da0a91c24b3926ee1d069912849f4
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/130815
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
diff --git a/sal/rtl/strtmpl.hxx b/sal/rtl/strtmpl.hxx
index 78375ae..a6b06ad 100644
--- a/sal/rtl/strtmpl.hxx
+++ b/sal/rtl/strtmpl.hxx
@@ -761,58 +761,63 @@ template <typename IMPL_RTL_STRCODE> sal_Bool toBoolean( const IMPL_RTL_STRCODE*
}

/* ----------------------------------------------------------------------- */
template <typename T, typename U, typename IMPL_RTL_STRCODE>
T toInt_WithLength                                              ( const IMPL_RTL_STRCODE* pStr,
                                                                  sal_Int16 nRadix,
                                                                  sal_Int32 nStrLength )

template <typename T, class Iter> inline bool HandleSignChar(Iter& iter)
{
    static_assert(std::numeric_limits<T>::is_signed, "is signed");
    if constexpr (std::numeric_limits<T>::is_signed)
    {
        if (*iter == '-')
        {
            ++iter;
            return true;
        }
    }
    if (*iter == '+')
        ++iter;
    return false;
}

template <typename T> std::pair<T, sal_Int16> DivMod(sal_Int16 nRadix, [[maybe_unused]] bool bNeg)
{
    if constexpr (std::numeric_limits<T>::is_signed)
        if (bNeg)
            return { -(std::numeric_limits<T>::min() / nRadix),
                     -(std::numeric_limits<T>::min() % nRadix) };
    return { std::numeric_limits<T>::max() / nRadix, std::numeric_limits<T>::max() % nRadix };
}

template <class SV> auto getIter(const SV& sv) { return sv.begin(); }
template <typename C> auto getIter(const C* pStr) { return pStr; }

template <class SV> auto good(typename SV::iterator iter, const SV& sv) { return iter != sv.end(); }
template <typename C> auto good(const C* pStr, const C*) { return *pStr != 0; }

template <typename T, class S> T toInt(S str, sal_Int16 nRadix)
{
    assert( nRadix >= RTL_STR_MIN_RADIX && nRadix <= RTL_STR_MAX_RADIX );
    assert( nStrLength >= 0 );
    bool    bNeg;
    sal_Int16   nDigit;
    U           n = 0;
    const IMPL_RTL_STRCODE* pEnd = pStr + nStrLength;

    if ( (nRadix < RTL_STR_MIN_RADIX) || (nRadix > RTL_STR_MAX_RADIX) )
        nRadix = 10;

    auto pStr = getIter(str);

    /* Skip whitespaces */
    while ( pStr != pEnd && rtl_ImplIsWhitespace( IMPL_RTL_USTRCODE( *pStr ) ) )
    while (good(pStr, str) && rtl_ImplIsWhitespace(IMPL_RTL_USTRCODE(*pStr)))
        pStr++;
    if (!good(pStr, str))
        return 0;

    if ( *pStr == '-' )
    {
        bNeg = true;
        pStr++;
    }
    else
    {
        if ( *pStr == '+' )
            pStr++;
        bNeg = false;
    }
    const bool bNeg = HandleSignChar<T>(pStr);
    const auto& [nDiv, nMod] = DivMod<T>(nRadix, bNeg);
    assert(nDiv > 0);

    T nDiv;
    sal_Int16 nMod;
    if ( bNeg )
    std::make_unsigned_t<T> n = 0;
    while (good(pStr, str))
    {
        nDiv = -(std::numeric_limits<T>::min() / nRadix);
        nMod = -(std::numeric_limits<T>::min() % nRadix);
    }
    else
    {
        nDiv = std::numeric_limits<T>::max() / nRadix;
        nMod = std::numeric_limits<T>::max() % nRadix;
    }

    while ( pStr != pEnd )
    {
        nDigit = rtl_ImplGetDigit( IMPL_RTL_USTRCODE( *pStr ), nRadix );
        sal_Int16 nDigit = rtl_ImplGetDigit(IMPL_RTL_USTRCODE(*pStr), nRadix);
        if ( nDigit < 0 )
            break;
        assert(nDiv > 0);
        if( static_cast<U>( nMod < nDigit ? nDiv-1 : nDiv ) < n )
        if (static_cast<std::make_unsigned_t<T>>(nMod < nDigit ? nDiv - 1 : nDiv) < n)
            return 0;

        n *= nRadix;
@@ -821,11 +826,12 @@ T toInt_WithLength                                              ( const IMPL_RTL
        pStr++;
    }

    if ( bNeg )
        return n == static_cast<U>(std::numeric_limits<T>::min())
            ? std::numeric_limits<T>::min() : -static_cast<T>(n);
    else
        return static_cast<T>(n);
    if constexpr (std::numeric_limits<T>::is_signed)
        if (bNeg)
            return n == static_cast<std::make_unsigned_t<T>>(std::numeric_limits<T>::min())
                       ? std::numeric_limits<T>::min()
                       : -static_cast<T>(n);
    return static_cast<T>(n);
}

template <typename IMPL_RTL_STRCODE>
@@ -833,7 +839,7 @@ sal_Int32 toInt32                             ( const IMPL_RTL_STRCODE* pStr,
                                                sal_Int16 nRadix )
{
    assert(pStr);
    return toInt_WithLength<sal_Int32, sal_uInt32>(pStr, nRadix, getLength(pStr));
    return toInt<sal_Int32>(pStr, nRadix);
}

template <typename IMPL_RTL_STRCODE>
@@ -843,7 +849,7 @@ sal_Int32 toInt32_WithLength                  ( const IMPL_RTL_STRCODE* pStr,

{
    assert(pStr);
    return toInt_WithLength<sal_Int32, sal_uInt32>(pStr, nRadix, nStrLength);
    return toInt<sal_Int32>(std::basic_string_view(pStr, nStrLength), nRadix);
}

template <typename IMPL_RTL_STRCODE>
@@ -851,7 +857,7 @@ sal_Int64 toInt64                             ( const IMPL_RTL_STRCODE* pStr,
                                                sal_Int16 nRadix )
{
    assert(pStr);
    return toInt_WithLength<sal_Int64, sal_uInt64>(pStr, nRadix, getLength(pStr));
    return toInt<sal_Int64>(pStr, nRadix);
}

template <typename IMPL_RTL_STRCODE>
@@ -861,46 +867,7 @@ sal_Int64 toInt64_WithLength                  ( const IMPL_RTL_STRCODE* pStr,

{
    assert(pStr);
    return toInt_WithLength<sal_Int64, sal_uInt64>(pStr, nRadix, nStrLength);
}

/* ----------------------------------------------------------------------- */
template <typename T, typename IMPL_RTL_STRCODE> T toUInt( const IMPL_RTL_STRCODE* pStr,
                                                                      sal_Int16 nRadix )
{
    static_assert(!std::numeric_limits<T>::is_signed, "is not signed");
    assert( nRadix >= RTL_STR_MIN_RADIX && nRadix <= RTL_STR_MAX_RADIX );
    sal_Int16   nDigit;
    T           n = 0;

    if ( (nRadix < RTL_STR_MIN_RADIX) || (nRadix > RTL_STR_MAX_RADIX) )
        nRadix = 10;

    /* Skip whitespaces */
    while ( *pStr && rtl_ImplIsWhitespace( IMPL_RTL_USTRCODE( *pStr ) ) )
        ++pStr;

    // skip optional explicit sign
    if ( *pStr == '+' )
        ++pStr;

    T nDiv = std::numeric_limits<T>::max() / nRadix;
    sal_Int16 nMod = std::numeric_limits<T>::max() % nRadix;
    while ( *pStr )
    {
        nDigit = rtl_ImplGetDigit( IMPL_RTL_USTRCODE( *pStr ), nRadix );
        if ( nDigit < 0 )
            break;
        if( ( nMod < nDigit ? nDiv-1 : nDiv ) < n )
            return 0;

        n *= nRadix;
        n += nDigit;

        ++pStr;
    }

    return n;
    return toInt<sal_Int64>(std::basic_string_view(pStr, nStrLength), nRadix);
}

template <typename IMPL_RTL_STRCODE>
@@ -908,7 +875,7 @@ sal_uInt32 toUInt32                             ( const IMPL_RTL_STRCODE* pStr,
                                                  sal_Int16 nRadix )
{
    assert(pStr);
    return toUInt<sal_uInt32>(pStr, nRadix);
    return toInt<sal_uInt32>(pStr, nRadix);
}

template <typename IMPL_RTL_STRCODE>
@@ -916,7 +883,7 @@ sal_uInt64 toUInt64                             ( const IMPL_RTL_STRCODE* pStr,
                                                  sal_Int16 nRadix )
{
    assert(pStr);
    return toUInt<sal_uInt64>(pStr, nRadix);
    return toInt<sal_uInt64>(pStr, nRadix);
}

/* ======================================================================= */