Files
libreoffice/linguistic/source/iprcache.cxx

553 lines
16 KiB
C++
Raw Normal View History

2000-11-17 11:37:46 +00:00
/*************************************************************************
*
* OpenOffice.org - a multi-platform office productivity suite
2000-11-17 11:37:46 +00:00
*
* $RCSfile: iprcache.cxx,v $
2000-11-17 11:37:46 +00:00
*
* $Revision: 1.6 $
2000-11-17 11:37:46 +00:00
*
* last change: $Author: rt $ $Date: 2005-09-07 19:52:48 $
2000-11-17 11:37:46 +00:00
*
* The Contents of this file are made available subject to
* the terms of GNU Lesser General Public License Version 2.1.
2000-11-17 11:37:46 +00:00
*
*
* GNU Lesser General Public License Version 2.1
* =============================================
* Copyright 2005 by Sun Microsystems, Inc.
* 901 San Antonio Road, Palo Alto, CA 94303, USA
2000-11-17 11:37:46 +00:00
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
2000-11-17 11:37:46 +00:00
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
2000-11-17 11:37:46 +00:00
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
2000-11-17 11:37:46 +00:00
*
************************************************************************/
#include <string.h>
#include "iprcache.hxx"
#include "misc.hxx"
#include <com/sun/star/linguistic2/DictionaryListEventFlags.hpp>
#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif
#ifndef _OSL_MUTEX_HXX_
#include <osl/mutex.hxx>
#endif
//#define IPR_DEF_CACHE_SIZE 503
#define IPR_DEF_CACHE_MAX 375
#define IPR_DEF_CACHE_MAXINPUT 200
#ifdef DBG_STATISTIC
#ifndef _STREAM_HXX
#include <tools/stream.hxx>
#endif
//#define IPR_CACHE_SIZE nTblSize
#define IPR_CACHE_MAX nMax
#define IPR_CACHE_MAXINPUT nMaxInput
#else
//#define IPR_CACHE_SIZE IPR_DEF_CACHE_SIZE
#define IPR_CACHE_MAX IPR_DEF_CACHE_MAX
#define IPR_CACHE_MAXINPUT IPR_DEF_CACHE_MAXINPUT
#endif
#ifndef _UNOTOOLS_PROCESSFACTORY_HXX_
#include <unotools/processfactory.hxx>
#endif
#include <lngprops.hxx>
2000-11-17 11:37:46 +00:00
using namespace utl;
using namespace osl;
using namespace rtl;
using namespace com::sun::star;
using namespace com::sun::star::beans;
2000-11-17 11:37:46 +00:00
using namespace com::sun::star::lang;
using namespace com::sun::star::uno;
using namespace com::sun::star::linguistic2;
2000-11-17 11:37:46 +00:00
namespace linguistic
{
///////////////////////////////////////////////////////////////////////////
#define NUM_FLUSH_PROPS 6
static const struct
{
const char *pPropName;
INT32 nPropHdl;
} aFlushProperties[ NUM_FLUSH_PROPS ] =
{
UPN_IS_GERMAN_PRE_REFORM, UPH_IS_GERMAN_PRE_REFORM,
UPN_IS_USE_DICTIONARY_LIST, UPH_IS_USE_DICTIONARY_LIST,
UPN_IS_IGNORE_CONTROL_CHARACTERS, UPH_IS_IGNORE_CONTROL_CHARACTERS,
UPN_IS_SPELL_UPPER_CASE, UPH_IS_SPELL_UPPER_CASE,
UPN_IS_SPELL_WITH_DIGITS, UPH_IS_SPELL_WITH_DIGITS,
UPN_IS_SPELL_CAPITALIZATION, UPH_IS_SPELL_CAPITALIZATION
};
static void lcl_AddAsPropertyChangeListener(
Reference< XPropertyChangeListener > xListener,
Reference< XPropertySet > &rPropSet )
{
if (xListener.is() && rPropSet.is())
{
for (int i = 0; i < NUM_FLUSH_PROPS; ++i)
{
rPropSet->addPropertyChangeListener(
A2OU(aFlushProperties[i].pPropName), xListener );
}
}
}
static void lcl_RemoveAsPropertyChangeListener(
Reference< XPropertyChangeListener > xListener,
Reference< XPropertySet > &rPropSet )
{
if (xListener.is() && rPropSet.is())
{
for (int i = 0; i < NUM_FLUSH_PROPS; ++i)
{
rPropSet->removePropertyChangeListener(
A2OU(aFlushProperties[i].pPropName), xListener );
}
}
}
static BOOL lcl_IsFlushProperty( INT32 nHandle )
{
int i;
for (i = 0; i < NUM_FLUSH_PROPS; ++i)
{
if (nHandle == aFlushProperties[i].nPropHdl)
break;
}
return i < NUM_FLUSH_PROPS;
}
2000-11-17 11:37:46 +00:00
FlushListener::FlushListener( Flushable *pFO )
{
SetFlushObj( pFO );
}
2000-11-17 11:37:46 +00:00
FlushListener::~FlushListener()
{
}
void FlushListener::SetDicList( Reference<XDictionaryList> &rDL )
2000-11-17 11:37:46 +00:00
{
MutexGuard aGuard( GetLinguMutex() );
if (xDicList != rDL)
2000-11-17 11:37:46 +00:00
{
if (xDicList.is())
xDicList->removeDictionaryListEventListener( this );
xDicList = rDL;
2000-11-17 11:37:46 +00:00
if (xDicList.is())
xDicList->addDictionaryListEventListener( this, FALSE );
}
}
void FlushListener::SetPropSet( Reference< XPropertySet > &rPS )
{
MutexGuard aGuard( GetLinguMutex() );
if (xPropSet != rPS)
{
if (xPropSet.is())
lcl_RemoveAsPropertyChangeListener( this, xPropSet );
xPropSet = rPS;
if (xPropSet.is())
lcl_AddAsPropertyChangeListener( this, xPropSet );
}
}
2000-11-17 11:37:46 +00:00
void SAL_CALL FlushListener::disposing( const EventObject& rSource )
throw(RuntimeException)
{
MutexGuard aGuard( GetLinguMutex() );
if (xDicList.is() && rSource.Source == xDicList)
{
xDicList->removeDictionaryListEventListener( this );
xDicList = NULL; //! release reference
}
if (xPropSet.is() && rSource.Source == xPropSet)
{
lcl_RemoveAsPropertyChangeListener( this, xPropSet );
xPropSet = NULL; //! release reference
}
2000-11-17 11:37:46 +00:00
}
2000-11-17 11:37:46 +00:00
void SAL_CALL FlushListener::processDictionaryListEvent(
const DictionaryListEvent& rDicListEvent )
2000-11-17 11:37:46 +00:00
throw(RuntimeException)
{
MutexGuard aGuard( GetLinguMutex() );
if (rDicListEvent.Source == xDicList)
{
INT16 nEvt = rDicListEvent.nCondensedEvent;
INT16 nFlushFlags =
DictionaryListEventFlags::ADD_NEG_ENTRY |
DictionaryListEventFlags::DEL_POS_ENTRY |
DictionaryListEventFlags::ACTIVATE_NEG_DIC |
DictionaryListEventFlags::DEACTIVATE_POS_DIC;
BOOL bFlush = 0 != (nEvt & nFlushFlags);
DBG_ASSERT( pFlushObj, "missing object (NULL pointer)" );
if (bFlush && pFlushObj != NULL)
pFlushObj->Flush();
}
}
void SAL_CALL FlushListener::propertyChange(
const PropertyChangeEvent& rEvt )
throw(RuntimeException)
{
MutexGuard aGuard( GetLinguMutex() );
2000-11-17 11:37:46 +00:00
if (rEvt.Source == xPropSet)
{
BOOL bFlush = lcl_IsFlushProperty( rEvt.PropertyHandle );
DBG_ASSERT( pFlushObj, "missing object (NULL pointer)" );
2000-11-17 11:37:46 +00:00
if (bFlush && pFlushObj != NULL)
pFlushObj->Flush();
}
}
2000-11-17 11:37:46 +00:00
///////////////////////////////////////////////////////////////////////////
class IPRCachedWord
{
String aWord;
IPRCachedWord *pNext;
IPRCachedWord *pPrev;
IPRCachedWord *pFollow;
INT16 nLanguage;
ULONG nFound;
// don't allow to use copy-constructor and assignment-operator
IPRCachedWord(const IPRCachedWord &);
IPRCachedWord & operator = (const IPRCachedWord &);
public:
IPRCachedWord( const String& rWord, IPRCachedWord* pFollow, INT16 nLang )
2001-11-08 06:04:30 +00:00
: aWord( rWord ), pNext( 0 ), pPrev( 0 ), pFollow( pFollow ),
2000-11-17 11:37:46 +00:00
nLanguage( nLang ), nFound( 0 ) {}
~IPRCachedWord(){}
const String& GetWord() { return aWord; }
void SetWord( const String& aNew ) { aWord = aNew; }
USHORT GetLang() { return nLanguage; }
void SetLang( INT16 nNew ) { nLanguage = nNew; }
IPRCachedWord* GetNext() { return pNext; }
void SetNext( IPRCachedWord* pNew ) { pNext = pNew; }
IPRCachedWord* GetPrev() { return pPrev; }
void SetPrev( IPRCachedWord* pNew ) { pPrev = pNew; }
IPRCachedWord* GetFollow() { return pFollow; }
void SetFollow( IPRCachedWord* pNew ){ pFollow = pNew; }
void IncFound() { ++nFound; }
ULONG GetFound() { return nFound; }
void SetFound( ULONG nNew ) { nFound = nNew; }
};
///////////////////////////////////////////////////////////////////////////
IPRSpellCache::IPRSpellCache( ULONG nSize ) :
ppHash ( NULL ),
pFirst ( NULL ),
pLast ( NULL ),
nIndex ( 0 ),
nCount ( 0 ),
nInputPos ( 0 ),
nInputValue ( 0 ),
nTblSize ( nSize )
#ifdef DBG_STATISTIC
,nMax ( IPR_DEF_CACHE_MAX ),
nMaxInput ( IPR_DEF_CACHE_MAXINPUT ),
nFound ( 0 ),
nLost ( 0 )
#endif
{
pFlushLstnr = new FlushListener( this );
xFlushLstnr = pFlushLstnr;
2001-10-11 16:13:17 +00:00
Reference<XDictionaryList> aDictionaryList(GetDictionaryList());
pFlushLstnr->SetDicList( aDictionaryList ); //! after reference is established
Reference<XPropertySet> aPropertySet(GetLinguProperties());
pFlushLstnr->SetPropSet( aPropertySet ); //! after reference is established
2000-11-17 11:37:46 +00:00
}
IPRSpellCache::~IPRSpellCache()
{
MutexGuard aGuard( GetLinguMutex() );
2001-10-11 16:13:17 +00:00
Reference<XDictionaryList> aDictionaryList;
pFlushLstnr->SetDicList( aDictionaryList );
Reference<XPropertySet> aPropertySet;
pFlushLstnr->SetPropSet( aPropertySet );
2000-11-17 11:37:46 +00:00
#ifdef DBG_STATISTIC
// Binary File oeffnen
String aOutTmp( String::CreateFromAscii( "iprcache.stk" ) )
SvFileStream aOut( aOutTmp, STREAM_STD_WRITE );
if( aOut.IsOpen() && !aOut.GetError() && ppHash )
{
ByteString aStr( "Gefunden: ");
aStr += nFound;
aStr += " Verloren: ";
aStr += nLost;
ULONG nSumSum = 0;
aOut << aStr.GetBuffer() << endl;
for( ULONG i = 0; i < nTblSize; ++i )
{
aStr = "Index: ";
aStr += i;
aStr += " Tiefe: ";
ULONG nDeep = 0;
ULONG nSum = 0;
IPRCachedWord* pTmp = *( ppHash + i );
while( pTmp )
{
++nDeep;
nSum += pTmp->GetFound();
pTmp = pTmp->GetNext();
}
aStr += nDeep;
aStr += " Anzahl: ";
aStr += nSum;
nSumSum += nSum;
aOut << aStr.GetBuffer() << endl;
pTmp = *( ppHash + i );
aStr = " Found: ";
while( pTmp )
{
aStr += pTmp->GetFound();
aStr += " ";
pTmp = pTmp->GetNext();
}
aOut << aStr.GetBuffer() << endl;
}
aStr = "Summe: ";
aStr += nSumSum;
aOut << aStr.GetBuffer() << endl;
}
#endif
while( pFirst )
{
pLast = pFirst->GetNext();
delete pFirst;
pFirst = pLast;
}
delete ppHash;
}
void IPRSpellCache::Flush()
{
MutexGuard aGuard( GetLinguMutex() );
if( ppHash )
{
while( pFirst )
{
pLast = pFirst->GetNext();
delete pFirst;
pFirst = pLast;
}
delete ppHash;
ppHash = NULL;
nIndex = 0;
nCount = 0;
nInputPos = 0;
nInputValue = 0;
#ifdef DBG_STATISTIC
nFound = 0;
nLost = 0;
#endif
}
}
BOOL IPRSpellCache::CheckWord( const String& rWord, INT16 nLang, BOOL bAllLang )
{
MutexGuard aGuard( GetLinguMutex() );
BOOL bRet = FALSE;
// Hash-Index-Berechnung
nIndex = 0;
const sal_Unicode* pp = rWord.GetBuffer();
while( *pp )
nIndex = nIndex << 1 ^ *pp++;
nIndex %= nTblSize;
if( ppHash )
{
pRun = *(ppHash + nIndex);
if( pRun && !( bRet = (rWord == pRun->GetWord() &&
(nLang == pRun->GetLang() || bAllLang)) ) )
{
IPRCachedWord* pTmp = pRun->GetNext();
while( pTmp && !( bRet = ( rWord == pTmp->GetWord() &&
2001-11-08 06:04:30 +00:00
(nLang == pTmp->GetLang() || bAllLang) ) ) )
2000-11-17 11:37:46 +00:00
{
pRun = pTmp;
pTmp = pTmp->GetNext();
}
if ( bRet )
{ // Gefunden: Umsortieren in der Hash-Liste
pRun->SetNext( pTmp->GetNext() );
pTmp->SetNext( *( ppHash + nIndex ) );
*( ppHash + nIndex ) = pTmp;
pRun = pTmp;
}
}
if( bRet )
{
if ( pRun->GetPrev() )
{ // Wenn wir noch nicht erster sind, werden wir es jetzt:
if ( ( pRun->GetFound() <= nInputValue ) &&
( ++nInputPos > IPR_CACHE_MAXINPUT )
|| ( pInput == pRun ) && !( pInput = pRun->GetFollow() ) )
{ // Wenn die Input-Stelle am Maximum anlangt, erhoehen
++nInputValue; // wir den InputValue und gehen wieder
nInputPos = 0; // an den Anfang
pInput = pFirst;
}
IPRCachedWord* pTmp = pRun->GetFollow();
pRun->GetPrev()->SetFollow( pTmp ); //Unser Ex-Prev -> Ex-Follow
pRun->SetFollow( pFirst ); // Wir selbst -> Ex-First
pFirst->SetPrev( pRun ); // Wir selbst <- Ex-First
if( pTmp )
pTmp->SetPrev( pRun->GetPrev() ); // Ex-Prev <- Ex-Follow
else
pLast = pRun->GetPrev(); // falls wir letzter waren
pRun->SetPrev( NULL ); // Erste haben keinen Prev
pFirst = pRun; // Wir sind Erster!
}
pRun->IncFound(); // Mitzaehlen, wie oft wiedergefunden
}
}
return bRet;
}
void IPRSpellCache::AddWord( const String& rWord, INT16 nLang )
{
MutexGuard aGuard( GetLinguMutex() );
if( !ppHash )
{
ppHash = new IPRCachedWord* [ nTblSize ];
memset( (void *)ppHash, 0, ( sizeof( IPRCachedWord* ) * nTblSize ) );
}
IPRCachedWord* pTmp;
if( nCount == IPR_CACHE_MAX-1 )
{
ULONG nDel = 0;
pRun = pLast; // Der letzte wird ueberschrieben
const sal_Unicode* pp = pRun->GetWord().GetBuffer();
while( *pp )
nDel = nDel << 1 ^ *pp++;
nDel %= nTblSize; // Hash-Index des letzten
// Der letzte wird aus seiner alten Hash-Liste entfernt
if( ( pTmp = *( ppHash + nDel ) ) == pRun )
*( ppHash + nDel ) = pRun->GetNext();
else
{
while( pTmp->GetNext() != pRun )
pTmp = pTmp->GetNext();
pTmp->SetNext( pRun->GetNext() );
}
pRun->SetWord( rWord ); // Ueberschreiben des alten Inhalts
pRun->SetLang( nLang );
pRun->SetFound( 0 );
}
else
{
++nCount;
pRun = new IPRCachedWord( rWord, pFirst, nLang );
if( pFirst )
pFirst->SetPrev( pRun );
pFirst = pRun; // Ganz Neue kommen erstmal nach vorne
if ( !pLast )
{
pLast = pRun;
pInput = pRun;
}
}
pRun->SetNext( *( ppHash + nIndex ) ); // In der Hash-Liste
*(ppHash + nIndex ) = pRun; // vorne einsortieren
// In der LRU-Kette umsortieren ...
if ( pRun != pInput && pRun != pInput->GetPrev() )
{
pTmp = pRun->GetPrev();
IPRCachedWord* pFoll = pRun->GetFollow();
// Entfernen aus der alten Position
if( pTmp )
pTmp->SetFollow( pFoll );
else
pFirst = pFoll; // wir waren erster
if( pFoll )
pFoll->SetPrev( pTmp );
else
pLast = pTmp; // wir waren letzter
// Einfuegen vor pInput
if( pTmp = pInput->GetPrev() )
pTmp->SetFollow( pRun );
else
pFirst = pRun; // pInput war erster
pRun->SetPrev( pTmp );
pRun->SetFollow( pInput );
pInput->SetPrev( pRun );
}
pInput = pRun; // pInput zeigt auf den zuletzt einsortierten
}
///////////////////////////////////////////////////////////////////////////
} // namespace linguistic