Related: tdf#144245 Optimize case-insensitive handling

1. Make BasicCollection::implGetIndexForName take OUString again,
after commit f7de7de1189ae4e63f73468076da47b37fe61ede made it take
std::u16string_view. All call sites pass OUStrings, and commit
ef32c3b4f9b80918d6018e14297fa41245afd381 made it create OUString
from the argument.
2. Have SbxVariable cache a case-insensitive variant of the name.
It is currently only used in the Collection implementation, but
may be used in other places; Tthe names are case-insensitive in
Basic, and VBA allows non-ASCII characters in names, so this
caching might be useful elsewhere.
3. Skip non-ASCII characters when calculating name hash, to allow
non-ASCII-containing strings still have some hash variance, when
at least some of the first 6 characters are ASCII.

Change-Id: If90ccea2c4b44c34967e6b764b6fab45b2976c40
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132493
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
diff --git a/basic/source/classes/sb.cxx b/basic/source/classes/sb.cxx
index 5c99408..902f7ad 100644
--- a/basic/source/classes/sb.cxx
+++ b/basic/source/classes/sb.cxx
@@ -2065,26 +2065,26 @@ sal_Int32 BasicCollection::implGetIndex( SbxVariable const * pIndexVar )
    return nIndex;
}

sal_Int32 BasicCollection::implGetIndexForName(std::u16string_view rName)
sal_Int32 BasicCollection::implGetIndexForName(const OUString& rName)
{
    sal_Int32 nIndex = -1;
    sal_Int32 nCount = xItemArray->Count();
    sal_Int32 nNameHash = MakeHashCode( rName );

    // tdf#144245 - case-insensitive operation for non-ASCII characters
    utl::TransliterationWrapper& rTransliteration = SbGlobal::GetTransliteration();
    OUString aNameCI; // Only initialize when matching hash found

    for( sal_Int32 i = 0 ; i < nCount ; i++ )
    {
        SbxVariable* pVar = xItemArray->Get(i);
        if (pVar->GetHashCode() == nNameHash
            && rTransliteration.isEqual(pVar->GetName(), OUString(rName)))
        if (pVar->GetHashCode() == nNameHash)
        {
            nIndex = i;
            break;
            if (aNameCI.isEmpty() && !rName.isEmpty())
                aNameCI = SbGlobal::GetTransliteration().transliterate(rName, 0, rName.getLength());
            if (aNameCI == pVar->GetName(SbxNameType::CaseInsensitive))
                return i;
        }
    }
    return nIndex;
    return -1;
}

void BasicCollection::CollAdd( SbxArray* pPar_ )
diff --git a/basic/source/inc/sbunoobj.hxx b/basic/source/inc/sbunoobj.hxx
index 1f30429..1fc8ebe 100644
--- a/basic/source/inc/sbunoobj.hxx
+++ b/basic/source/inc/sbunoobj.hxx
@@ -350,7 +350,7 @@ class BasicCollection final : public SbxObject
    virtual ~BasicCollection() override;
    virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
    sal_Int32 implGetIndex( SbxVariable const * pIndexVar );
    sal_Int32 implGetIndexForName(std::u16string_view rName);
    sal_Int32 implGetIndexForName(const OUString& rName);
    void CollAdd( SbxArray* pPar_ );
    void CollItem( SbxArray* pPar_ );
    void CollRemove( SbxArray* pPar_ );
diff --git a/basic/source/sbx/sbxvar.cxx b/basic/source/sbx/sbxvar.cxx
index 8fb11bf..a081229 100644
--- a/basic/source/sbx/sbxvar.cxx
+++ b/basic/source/sbx/sbxvar.cxx
@@ -30,6 +30,8 @@
#include <sbunoobj.hxx>
#include <rtl/ustrbuf.hxx>
#include <sal/log.hxx>
#include <global.hxx>
#include <unotools/transliterationwrapper.hxx>

#include <com/sun/star/uno/XInterface.hpp>
using namespace com::sun::star::uno;
@@ -183,6 +185,7 @@ void SbxVariable::SetName( const OUString& rName )
{
    maName = rName;
    nHash = MakeHashCode( rName );
    maNameCI.clear();
}

const OUString& SbxVariable::GetName( SbxNameType t ) const
@@ -192,6 +195,12 @@ const OUString& SbxVariable::GetName( SbxNameType t ) const
    {
        return maName;
    }
    if (t == SbxNameType::CaseInsensitive)
    {
        if (maNameCI.isEmpty() && !maName.isEmpty())
            maNameCI = SbGlobal::GetTransliteration().transliterate(maName, 0, maName.getLength());
        return maNameCI;
    }
    // Request parameter-information (not for objects)
    const_cast<SbxVariable*>(this)->GetInfo();
    // Append nothing, if it is a simple property (no empty brackets)
diff --git a/include/basic/sbxdef.hxx b/include/basic/sbxdef.hxx
index b52b0be..e85f1a2 100644
--- a/include/basic/sbxdef.hxx
+++ b/include/basic/sbxdef.hxx
@@ -122,6 +122,7 @@ enum SbxOperator {

enum class SbxNameType {          // Type of the questioned name of a variable
    NONE,           // plain name
    CaseInsensitive, // plain name - case insensitive
    ShortTypes,     // Name%(A%,B$)
};

diff --git a/include/basic/sbxvar.hxx b/include/basic/sbxvar.hxx
index 1f1ac8a..d302f26 100644
--- a/include/basic/sbxvar.hxx
+++ b/include/basic/sbxvar.hxx
@@ -248,6 +248,7 @@ class BASIC_DLLPUBLIC SbxVariable : public SbxValue
    StarBASIC*       m_pComListenerParentBasic = nullptr;
    std::unique_ptr<SfxBroadcaster>  mpBroadcaster; // Broadcaster, if needed
    OUString         maName;            // Name, if available
    mutable OUString maNameCI;          // Name, case insentitive - cached for fast comparison
    SbxArrayRef      mpPar;             // Parameter-Array, if set
    sal_uInt16       nHash = 0;         // Hash-ID for search

@@ -308,9 +309,8 @@ public:
        const auto first6 = aName.substr(0, 6);
        for (const auto& c : first6)
        {
            // If we have a filthy non-ASCII character, break!!
            if (c >= 0x80)
                return 0;
            if (!rtl::isAscii(c))
                continue; // Just skip it to let non-ASCII strings have some hash variance
            n = static_cast<sal_uInt16>((n << 3) + rtl::toAsciiUpperCase(c));
        }
        return n;