tdf#148218 reduce OString alloc in dictionary searching
cache the information we need from the dictionary, so we avoid repeatedly calling LinguLocaleToLanguage in SearchDicList for every single word we spellcheck. Shaves 17% of the temporary allocations Change-Id: Ie28dab4224a35ec703ff7f698e9ea89775594c74 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198281 Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk> Tested-by: Jenkins
This commit is contained in:
@@ -32,6 +32,7 @@
|
||||
#include <rtl/ref.hxx>
|
||||
#include <linguistic/lngdllapi.h>
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace com::sun::star::beans { class XPropertySet; }
|
||||
@@ -154,7 +155,8 @@ css::uno::Reference<
|
||||
SearchDicList(
|
||||
const css::uno::Reference< css::linguistic2::XSearchableDictionaryList >& rDicList,
|
||||
const OUString& rWord, LanguageType nLanguage,
|
||||
bool bSearchPosDics, bool bSearchSpellEntry );
|
||||
bool bSearchPosDics, bool bSearchSpellEntry,
|
||||
std::map<LanguageType, std::vector<css::uno::Reference<css::linguistic2::XDictionary>>>& rDictionaryMap );
|
||||
|
||||
LNG_DLLPUBLIC DictionaryError AddEntryToDic(
|
||||
css::uno::Reference< css::linguistic2::XDictionary > const &rxDic,
|
||||
|
||||
@@ -42,7 +42,8 @@ std::vector< OUString >
|
||||
void SeqRemoveNegEntries(
|
||||
std::vector< OUString > &rSeq,
|
||||
css::uno::Reference< css::linguistic2::XSearchableDictionaryList > const &rxDicList,
|
||||
LanguageType nLanguage );
|
||||
LanguageType nLanguage,
|
||||
std::map<LanguageType, std::vector<css::uno::Reference<css::linguistic2::XDictionary>>>& rDictionaryMap );
|
||||
|
||||
void SearchSimilarText( const OUString &rText, LanguageType nLanguage,
|
||||
css::uno::Reference< css::linguistic2::XSearchableDictionaryList > const &xDicList,
|
||||
|
||||
@@ -509,8 +509,9 @@ uno::Reference< XDictionaryEntry > SAL_CALL
|
||||
sal_Bool bSearchPosDics, sal_Bool bSearchSpellEntry )
|
||||
{
|
||||
osl::MutexGuard aGuard( GetLinguMutex() );
|
||||
std::map<LanguageType, std::vector<css::uno::Reference<css::linguistic2::XDictionary>>> aDictionaryMap;
|
||||
return SearchDicList( this, rWord, LinguLocaleToLanguage( rLocale ),
|
||||
bSearchPosDics, bSearchSpellEntry );
|
||||
bSearchPosDics, bSearchSpellEntry, aDictionaryMap );
|
||||
}
|
||||
|
||||
|
||||
|
||||
+43
-24
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <sal/log.hxx>
|
||||
#include <svl/lngmisc.hxx>
|
||||
@@ -250,40 +251,58 @@ static bool lcl_HasHyphInfo( const uno::Reference<XDictionaryEntry> &xEntry )
|
||||
uno::Reference< XDictionaryEntry > SearchDicList(
|
||||
const uno::Reference< XSearchableDictionaryList > &xDicList,
|
||||
const OUString &rWord, LanguageType nLanguage,
|
||||
bool bSearchPosDics, bool bSearchSpellEntry )
|
||||
bool bSearchPosDics, bool bSearchSpellEntry,
|
||||
std::map<LanguageType, std::vector<css::uno::Reference<css::linguistic2::XDictionary>>>& rDictionaryMap )
|
||||
{
|
||||
MutexGuard aGuard( GetLinguMutex() );
|
||||
|
||||
uno::Reference< XDictionaryEntry > xEntry;
|
||||
|
||||
if (!xDicList.is())
|
||||
return xEntry;
|
||||
return uno::Reference< XDictionaryEntry >();
|
||||
|
||||
const uno::Sequence< uno::Reference< XDictionary > >
|
||||
aDics( xDicList->getDictionaries() );
|
||||
|
||||
for (const uno::Reference<XDictionary>& axDic : aDics)
|
||||
if (rDictionaryMap.empty())
|
||||
{
|
||||
DictionaryType eType = axDic->getDictionaryType();
|
||||
LanguageType nLang = LinguLocaleToLanguage( axDic->getLocale() );
|
||||
|
||||
if ( axDic.is() && axDic->isActive()
|
||||
&& (nLang == nLanguage || LinguIsUnspecified( nLang)) )
|
||||
const uno::Sequence< uno::Reference< XDictionary > >
|
||||
aDics( xDicList->getDictionaries() );
|
||||
for (const uno::Reference<XDictionary>& rxDic : aDics)
|
||||
{
|
||||
// DictionaryType_MIXED is deprecated
|
||||
SAL_WARN_IF(eType == DictionaryType_MIXED, "linguistic", "unexpected dictionary type");
|
||||
|
||||
if ( (!bSearchPosDics && eType == DictionaryType_NEGATIVE)
|
||||
|| ( bSearchPosDics && eType == DictionaryType_POSITIVE))
|
||||
{
|
||||
xEntry = axDic->getEntry( rWord );
|
||||
if ( xEntry.is() && (bSearchSpellEntry || lcl_HasHyphInfo( xEntry )) )
|
||||
break;
|
||||
xEntry = nullptr;
|
||||
}
|
||||
assert( rxDic.is() );
|
||||
LanguageType nLang = LinguLocaleToLanguage( rxDic->getLocale() );
|
||||
rDictionaryMap[nLang].push_back(rxDic);
|
||||
}
|
||||
}
|
||||
|
||||
auto lcl_search = [&rDictionaryMap, bSearchPosDics, bSearchSpellEntry, &rWord](LanguageType nLang)
|
||||
{
|
||||
auto it = rDictionaryMap.find(nLang);
|
||||
if (it != rDictionaryMap.end())
|
||||
for (const uno::Reference<XDictionary>& rxDic : it->second)
|
||||
{
|
||||
if ( rxDic->isActive() )
|
||||
{
|
||||
DictionaryType eType = rxDic->getDictionaryType();
|
||||
if ( (!bSearchPosDics && eType == DictionaryType_NEGATIVE)
|
||||
|| ( bSearchPosDics && eType == DictionaryType_POSITIVE))
|
||||
{
|
||||
uno::Reference< XDictionaryEntry > xEntry = rxDic->getEntry( rWord );
|
||||
if ( xEntry.is() && (bSearchSpellEntry || lcl_HasHyphInfo( xEntry )) )
|
||||
return xEntry;
|
||||
}
|
||||
}
|
||||
}
|
||||
return uno::Reference< XDictionaryEntry >();
|
||||
};
|
||||
|
||||
uno::Reference< XDictionaryEntry > xEntry;
|
||||
if ((xEntry = lcl_search(nLanguage)))
|
||||
return xEntry;
|
||||
|
||||
// check the same list as in the LinguIsUnspecified() function
|
||||
if ((xEntry = lcl_search(LANGUAGE_NONE)))
|
||||
return xEntry;
|
||||
if ((xEntry = lcl_search(LANGUAGE_UNDETERMINED)))
|
||||
return xEntry;
|
||||
xEntry = lcl_search(LANGUAGE_MULTIPLE);
|
||||
|
||||
return xEntry;
|
||||
}
|
||||
|
||||
|
||||
@@ -232,7 +232,9 @@ Reference< XSpellAlternatives > SAL_CALL
|
||||
// including the IgnoreAll list
|
||||
static Reference< XDictionaryEntry > lcl_GetRulingDictionaryEntry(
|
||||
const OUString &rWord,
|
||||
LanguageType nLanguage )
|
||||
LanguageType nLanguage,
|
||||
const Reference< XSearchableDictionaryList >& xDList,
|
||||
std::map<LanguageType, std::vector<css::uno::Reference<css::linguistic2::XDictionary>>>& rDictionaryMap )
|
||||
{
|
||||
Reference< XDictionaryEntry > xRes;
|
||||
|
||||
@@ -244,15 +246,14 @@ static Reference< XDictionaryEntry > lcl_GetRulingDictionaryEntry(
|
||||
xRes = xIgnoreAll->getEntry( rWord );
|
||||
if (!xRes.is())
|
||||
{
|
||||
Reference< XSearchableDictionaryList > xDList( GetDictionaryList() );
|
||||
Reference< XDictionaryEntry > xNegEntry( SearchDicList( xDList,
|
||||
rWord, nLanguage, false, true ) );
|
||||
rWord, nLanguage, false, true, rDictionaryMap ) );
|
||||
if (xNegEntry.is())
|
||||
xRes = std::move(xNegEntry);
|
||||
else
|
||||
{
|
||||
Reference< XDictionaryEntry > xPosEntry( SearchDicList( xDList,
|
||||
rWord, nLanguage, true, true ) );
|
||||
rWord, nLanguage, true, true, rDictionaryMap ) );
|
||||
if (xPosEntry.is())
|
||||
xRes = std::move(xPosEntry);
|
||||
}
|
||||
@@ -413,16 +414,17 @@ bool SpellCheckerDispatcher::isValid_Impl(
|
||||
}
|
||||
|
||||
// cross-check against results from dictionaries which have precedence!
|
||||
if (GetDicList().is() && IsUseDicList( rProperties, GetPropSet() ))
|
||||
auto xDicList = GetDicList();
|
||||
if (xDicList && IsUseDicList( rProperties, GetPropSet() ))
|
||||
{
|
||||
Reference< XDictionaryEntry > xTmp( lcl_GetRulingDictionaryEntry( aChkWord, nLanguage ) );
|
||||
Reference< XDictionaryEntry > xTmp( lcl_GetRulingDictionaryEntry( aChkWord, nLanguage, xDicList, m_aDictionaryMap ) );
|
||||
if (xTmp.is()) {
|
||||
bRes = !xTmp->isNegative();
|
||||
} else {
|
||||
setCharClass(LanguageTag(nLanguage));
|
||||
CapType ct = capitalType(aChkWord, m_oCharClass ? &*m_oCharClass : nullptr);
|
||||
if (ct == CapType::INITCAP || ct == CapType::ALLCAP) {
|
||||
Reference< XDictionaryEntry > xTmp2( lcl_GetRulingDictionaryEntry( makeLowerCase(aChkWord, m_oCharClass), nLanguage ) );
|
||||
Reference< XDictionaryEntry > xTmp2( lcl_GetRulingDictionaryEntry( makeLowerCase(aChkWord, m_oCharClass), nLanguage, xDicList, m_aDictionaryMap ) );
|
||||
if (xTmp2.is()) {
|
||||
bRes = !xTmp2->isNegative();
|
||||
}
|
||||
@@ -636,7 +638,7 @@ Reference< XSpellAlternatives > SpellCheckerDispatcher::spell_Impl(
|
||||
// cross-check against results from user-dictionaries which have precedence!
|
||||
if (xDList.is())
|
||||
{
|
||||
Reference< XDictionaryEntry > xTmp( lcl_GetRulingDictionaryEntry( aChkWord, nLanguage ) );
|
||||
Reference< XDictionaryEntry > xTmp( lcl_GetRulingDictionaryEntry( aChkWord, nLanguage, xDList, m_aDictionaryMap ) );
|
||||
if (xTmp.is())
|
||||
{
|
||||
if (xTmp->isNegative()) // negative entry found
|
||||
@@ -648,7 +650,7 @@ Reference< XSpellAlternatives > SpellCheckerDispatcher::spell_Impl(
|
||||
|
||||
// replacement text must not be in negative dictionary itself
|
||||
if (!aAddRplcTxt.isEmpty() &&
|
||||
!SearchDicList( xDList, aAddRplcTxt, nLanguage, false, true ).is())
|
||||
!SearchDicList( xDList, aAddRplcTxt, nLanguage, false, true, m_aDictionaryMap ).is())
|
||||
{
|
||||
aProposalList.Prepend( aAddRplcTxt );
|
||||
}
|
||||
@@ -665,7 +667,7 @@ Reference< XSpellAlternatives > SpellCheckerDispatcher::spell_Impl(
|
||||
CapType ct = capitalType(aChkWord, m_oCharClass ? &*m_oCharClass : nullptr);
|
||||
if (ct == CapType::INITCAP || ct == CapType::ALLCAP)
|
||||
{
|
||||
Reference< XDictionaryEntry > xTmp2( lcl_GetRulingDictionaryEntry( makeLowerCase(aChkWord, m_oCharClass), nLanguage ) );
|
||||
Reference< XDictionaryEntry > xTmp2( lcl_GetRulingDictionaryEntry( makeLowerCase(aChkWord, m_oCharClass), nLanguage, xDList, m_aDictionaryMap ) );
|
||||
if (xTmp2.is())
|
||||
{
|
||||
if (xTmp2->isNegative()) // negative entry found
|
||||
@@ -677,7 +679,7 @@ Reference< XSpellAlternatives > SpellCheckerDispatcher::spell_Impl(
|
||||
|
||||
// replacement text must not be in negative dictionary itself
|
||||
if (!aAddRplcTxt.isEmpty() &&
|
||||
!SearchDicList( xDList, aAddRplcTxt, nLanguage, false, true ).is())
|
||||
!SearchDicList( xDList, aAddRplcTxt, nLanguage, false, true, m_aDictionaryMap ).is())
|
||||
{
|
||||
switch ( ct )
|
||||
{
|
||||
@@ -715,7 +717,7 @@ Reference< XSpellAlternatives > SpellCheckerDispatcher::spell_Impl(
|
||||
// remove entries listed in negative dictionaries
|
||||
// (we don't want to display suggestions that will be regarded as misspelled later on)
|
||||
if (xDList.is())
|
||||
SeqRemoveNegEntries( aProposals, xDList, nLanguage );
|
||||
SeqRemoveNegEntries( aProposals, xDList, nLanguage, m_aDictionaryMap );
|
||||
|
||||
uno::Reference< linguistic2::XSetSpellAlternatives > xSetAlt( xRes, uno::UNO_QUERY );
|
||||
if (xSetAlt.is())
|
||||
|
||||
@@ -51,6 +51,7 @@ class SpellCheckerDispatcher :
|
||||
|
||||
css::uno::Reference< css::linguistic2::XLinguProperties > m_xPropSet;
|
||||
css::uno::Reference< css::linguistic2::XSearchableDictionaryList > m_xDicList;
|
||||
std::map<LanguageType, std::vector<css::uno::Reference<css::linguistic2::XDictionary>>> m_aDictionaryMap;
|
||||
|
||||
LngSvcMgr &m_rMgr;
|
||||
mutable std::unique_ptr<linguistic::SpellCache> m_pCache; // Spell Cache (holds known words)
|
||||
|
||||
@@ -97,14 +97,15 @@ void SearchSimilarText( const OUString &rText, LanguageType nLanguage,
|
||||
|
||||
void SeqRemoveNegEntries( std::vector< OUString > &rSeq,
|
||||
Reference< XSearchableDictionaryList > const &rxDicList,
|
||||
LanguageType nLanguage )
|
||||
LanguageType nLanguage,
|
||||
std::map<LanguageType, std::vector<css::uno::Reference<css::linguistic2::XDictionary>>>& rDictionaryMap )
|
||||
{
|
||||
bool bSthRemoved = false;
|
||||
sal_Int32 nLen = rSeq.size();
|
||||
for (sal_Int32 i = 0; i < nLen; ++i)
|
||||
{
|
||||
Reference< XDictionaryEntry > xNegEntry( SearchDicList( rxDicList,
|
||||
rSeq[i], nLanguage, false, true ) );
|
||||
rSeq[i], nLanguage, false, true, rDictionaryMap ) );
|
||||
if (xNegEntry.is())
|
||||
{
|
||||
rSeq[i].clear();
|
||||
|
||||
Reference in New Issue
Block a user