Convert mozPersonalDictionary to use nsTHashTable

Bug 224625, r=dwitte, sr=alecf


git-svn-id: svn://10.0.0.236/trunk@152220 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
mvl%exedo.nl 2004-02-03 11:54:03 +00:00
parent 23399a7583
commit 49bfbadc1c
6 changed files with 140 additions and 209 deletions

View File

@ -38,6 +38,8 @@
#include "nsISupports.idl"
interface nsIStringEnumerator;
[scriptable, uuid(7EF52EAF-B7E1-462B-87E2-5D1DBACA9048)]
/**
@ -46,11 +48,6 @@
interface mozIPersonalDictionary : nsISupports {
/**
* Initialize the dictionary
*/
void init();
/**
* Load the dictionary
*/
@ -62,9 +59,9 @@ interface mozIPersonalDictionary : nsISupports {
void save();
/**
* Get the list of words
* Get the (lexicographically sorted) list of words
*/
void getWordList([array, size_is(count)] out wstring words, out PRUint32 count);
readonly attribute nsIStringEnumerator wordList;
/**
* Check a unicode string

View File

@ -74,7 +74,6 @@ CPPSRCS = \
mozEnglishWordUtils.cpp \
mozGenericWordUtils.cpp \
mozSpellI18NManager.cpp \
nsAVLTree.cpp \
$(NULL)
EXTRA_DSO_LDOPTS = \

View File

@ -42,7 +42,6 @@
#include "nsAppDirectoryServiceDefs.h"
#include "nsICharsetConverterManager.h"
#include "nsICharsetAlias.h"
#include "nsAVLTree.h"
#include "nsIObserverService.h"
#include "nsIPrefService.h"
#include "nsIPrefBranch.h"
@ -50,6 +49,7 @@
#include "nsIWeakReference.h"
#include "nsCRT.h"
#include "nsNetUtil.h"
#include "nsStringEnumerator.h"
#define MOZ_PERSONAL_DICT_NAME "persdict.dat"
static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID);
@ -72,108 +72,21 @@ static PRBool SessionSave=PR_FALSE;
NS_IMPL_ISUPPORTS3(mozPersonalDictionary, mozIPersonalDictionary, nsIObserver, nsISupportsWeakReference)
/* AVL node functors */
/*
* String comparitor for Unicode tree
**/
class StringNodeComparitor: public nsAVLNodeComparitor {
public:
StringNodeComparitor(){}
virtual ~StringNodeComparitor(){}
virtual PRInt32 operator() (void *item1,void *item2){
return nsCRT::strcmp((PRUnichar *)item1,(PRUnichar *)item2);
}
};
/*
* the generic deallocator
**/
class DeallocatorFunctor: public nsAVLNodeFunctor {
public:
DeallocatorFunctor(){}
virtual ~DeallocatorFunctor(){}
virtual void* operator() (void * anItem){
nsMemory::Free(anItem);
return nsnull;
}
};
static StringNodeComparitor *gStringNodeComparitor;
static DeallocatorFunctor *gDeallocatorFunctor;
/*
* Copy the tree to a waiting array of Unichar pointers.
* All the strings are newly created. It is the callers responsibility to free them
**/
class CopyToArrayFunctor: public nsAVLNodeFunctor {
public:
CopyToArrayFunctor(PRUnichar **tabulaRasa){
data = tabulaRasa;
count =0;
res = NS_OK;
}
virtual ~CopyToArrayFunctor(){}
nsresult GetResult(){return res;}
virtual void* operator() (void * anItem){
PRUnichar * word=(PRUnichar *) anItem;
if(NS_SUCCEEDED(res)){
data[count]=ToNewUnicode(nsDependentString(word));
if(!data[count]) res = NS_ERROR_OUT_OF_MEMORY;
return (void*) (data[count++]);
}
return nsnull;
}
protected:
nsresult res;
PRUnichar **data;
PRUint32 count;
};
/*
* Copy the tree to an open file.
**/
class CopyToStreamFunctor: public nsAVLNodeFunctor {
public:
CopyToStreamFunctor(nsIOutputStream *aStream):mStream(aStream){
res = NS_OK;
}
virtual ~CopyToStreamFunctor(){}
nsresult GetResult(){return res;}
virtual void* operator() (void * anItem){
nsString word((PRUnichar *) anItem);
if(NS_SUCCEEDED(res)){
PRUint32 bytesWritten;
word.Append(NS_LITERAL_STRING("\n"));
NS_ConvertUCS2toUTF8 UTF8word(word);
res = mStream->Write(UTF8word.get(),UTF8word.Length(),&bytesWritten);
}
return nsnull;
}
protected:
nsresult res;
nsIOutputStream* mStream;
};
mozPersonalDictionary::mozPersonalDictionary():mUnicodeTree(nsnull),mUnicodeIgnoreTree(nsnull)
mozPersonalDictionary::mozPersonalDictionary()
: mDirty(PR_FALSE)
{
NS_ASSERTION(!gStringNodeComparitor,"Someone's been writing in my statics! I'm a Singleton Bear!");
if(!gStringNodeComparitor){
gStringNodeComparitor = new StringNodeComparitor;
gDeallocatorFunctor = new DeallocatorFunctor;
}
}
mozPersonalDictionary::~mozPersonalDictionary()
{
delete mUnicodeTree;
delete mUnicodeIgnoreTree;
}
NS_IMETHODIMP mozPersonalDictionary::Init()
nsresult mozPersonalDictionary::Init()
{
nsresult rv;
if (!mDictionaryTable.Init() || !mIgnoreTable.Init())
return NS_ERROR_OUT_OF_MEMORY;
nsresult rv;
nsCOMPtr<nsIObserverService> svc =
do_GetService("@mozilla.org/observer-service;1", &rv);
if (NS_SUCCEEDED(rv) && svc) {
@ -183,13 +96,13 @@ NS_IMETHODIMP mozPersonalDictionary::Init()
if (NS_SUCCEEDED(rv))
rv = svc->AddObserver(this, "profile-before-change", PR_TRUE);
if (NS_SUCCEEDED(rv))
rv = svc->AddObserver(this, "profile-after-change", PR_TRUE);
rv = svc->AddObserver(this, "profile-do-change", PR_TRUE);
}
if(NS_FAILED(rv)) return rv;
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIPrefBranchInternal> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
if(NS_SUCCEEDED(rv)) {
if(NS_FAILED(prefs->GetBoolPref(spellchecker_savePref, &SessionSave))){
if (NS_SUCCEEDED(rv)) {
if (NS_FAILED(prefs->GetBoolPref(spellchecker_savePref, &SessionSave))){
SessionSave = PR_TRUE;
}
prefs->AddObserver(spellchecker_savePref, this, PR_TRUE);
@ -198,9 +111,11 @@ NS_IMETHODIMP mozPersonalDictionary::Init()
SessionSave = PR_FALSE;
}
if(NS_FAILED(rv)) return rv;
if (NS_FAILED(rv)) return rv;
return Load();
Load();
return NS_OK;
}
/* void Load (); */
@ -219,14 +134,9 @@ NS_IMETHODIMP mozPersonalDictionary::Load()
res = theFile->Exists(&dictExists);
if(NS_FAILED(res)) return res;
if(!dictExists) {
//create new user dictionary
nsCOMPtr<nsIOutputStream> outStream;
NS_NewLocalFileOutputStream(getter_AddRefs(outStream), theFile, PR_CREATE_FILE | PR_WRONLY | PR_TRUNCATE ,0664);
CopyToStreamFunctor writer(outStream);
if(NS_FAILED(res)) return res;
if(!outStream)return NS_ERROR_FAILURE;
if (!dictExists) {
// Nothing is really wrong...
return NS_OK;
}
nsCOMPtr<nsIInputStream> inStream;
@ -236,8 +146,7 @@ NS_IMETHODIMP mozPersonalDictionary::Load()
if(NS_FAILED(res)) return res;
// we're rereading to get rid of the old data -- we shouldn't have any, but...
delete mUnicodeTree;
mUnicodeTree = new nsAVLTree(*gStringNodeComparitor,gDeallocatorFunctor);
mDictionaryTable.Clear();
PRUnichar c;
PRUint32 nRead;
@ -253,14 +162,24 @@ NS_IMETHODIMP mozPersonalDictionary::Load()
word.Append(c);
if( (NS_OK != convStream->Read(&c, 1, &nRead)) || (nRead != 1)) done = PR_TRUE;
}
mUnicodeTree->AddItem((void *)ToNewUnicode(word));
mDictionaryTable.PutEntry(word.get());
}
}while(!done);
} while(!done);
mDirty = PR_FALSE;
return res;
}
// A little helper function to add the key to the list.
// This is not threadsafe, and only safe if the consumer does not
// modify the list.
PR_STATIC_CALLBACK(PLDHashOperator)
AddHostToStringArray(nsUniCharEntry *aEntry, void *aArg)
{
NS_STATIC_CAST(nsStringArray*, aArg)->AppendString(nsDependentString(aEntry->GetKey()));
return PL_DHASH_NEXT;
}
/* void Save (); */
NS_IMETHODIMP mozPersonalDictionary::Save()
{
@ -268,8 +187,8 @@ NS_IMETHODIMP mozPersonalDictionary::Save()
nsresult res;
if(!mDirty) return NS_OK;
//FIXME Deinst -- get dictionary name from prefs;
//FIXME Deinst -- get dictionary name from prefs;
res = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(theFile));
if(NS_FAILED(res)) return res;
if(!theFile)return NS_ERROR_FAILURE;
@ -279,97 +198,83 @@ NS_IMETHODIMP mozPersonalDictionary::Save()
nsCOMPtr<nsIOutputStream> outStream;
NS_NewLocalFileOutputStream(getter_AddRefs(outStream), theFile, PR_CREATE_FILE | PR_WRONLY | PR_TRUNCATE ,0664);
CopyToStreamFunctor writer(outStream);
if(NS_FAILED(res)) return res;
if(!outStream)return NS_ERROR_FAILURE;
if (mUnicodeTree) mUnicodeTree->ForEach(writer);
mDirty = PR_FALSE;
return NS_OK;
}
// get a buffered output stream 4096 bytes big, to optimize writes
nsCOMPtr<nsIOutputStream> bufferedOutputStream;
res = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream), outStream, 4096);
if (NS_FAILED(res)) return res;
/* void GetWordList ([array, size_is (count)] out wstring words, out PRUint32 count); */
NS_IMETHODIMP mozPersonalDictionary::GetWordList(PRUnichar ***words, PRUint32 *count)
{
if(!words || !count)
return NS_ERROR_NULL_POINTER;
*words=0;
*count=0;
PRUnichar **tmpPtr = 0;
if(!mUnicodeTree){
return NS_OK;
}
tmpPtr = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * (mUnicodeTree->GetCount()));
if (!tmpPtr)
return NS_ERROR_OUT_OF_MEMORY;
CopyToArrayFunctor pitneyBowes(tmpPtr);
mUnicodeTree->ForEach(pitneyBowes);
nsStringArray array(mDictionaryTable.Count());
mDictionaryTable.EnumerateEntries(AddHostToStringArray, &array);
nsresult res = pitneyBowes.GetResult();
if(NS_SUCCEEDED(res)){
*count = mUnicodeTree->GetCount();
*words = tmpPtr;
PRUint32 bytesWritten;
nsCAutoString utf8Key;
for (PRInt32 i = 0; i < array.Count(); ++i ) {
const nsString *key = array[i];
CopyUTF16toUTF8(*key, utf8Key);
bufferedOutputStream->Write(utf8Key.get(), utf8Key.Length(), &bytesWritten);
bufferedOutputStream->Write("\n", 1, &bytesWritten);
}
return res;
}
/* boolean Check (in wstring word, in wstring language); */
NS_IMETHODIMP mozPersonalDictionary::Check(const PRUnichar *word, const PRUnichar *aLanguage, PRBool *_retval)
/* readonly attribute nsIStringEnumerator GetWordList() */
NS_IMETHODIMP mozPersonalDictionary::GetWordList(nsIStringEnumerator **aWords)
{
if(!word || !_retval || !mUnicodeTree)
return NS_ERROR_NULL_POINTER;
if(mUnicodeTree->FindItem((void *)word)){
*_retval = PR_TRUE;
}
else{
if(mUnicodeIgnoreTree&&mUnicodeIgnoreTree->FindItem((void *)word)){
*_retval = PR_TRUE;
}
else{
*_retval = PR_FALSE;
}
}
NS_ENSURE_ARG_POINTER(aWords);
*aWords = nsnull;
nsStringArray *array = new nsStringArray(mDictionaryTable.Count());
if (!array)
return NS_ERROR_OUT_OF_MEMORY;
mDictionaryTable.EnumerateEntries(AddHostToStringArray, array);
array->Sort();
return NS_NewAdoptingStringEnumerator(aWords, array);
}
/* boolean Check (in wstring word, in wstring language); */
NS_IMETHODIMP mozPersonalDictionary::Check(const PRUnichar *aWord, const PRUnichar *aLanguage, PRBool *aResult)
{
NS_ENSURE_ARG_POINTER(aWord);
NS_ENSURE_ARG_POINTER(aResult);
*aResult = (mDictionaryTable.GetEntry(aWord) || mIgnoreTable.GetEntry(aWord));
return NS_OK;
}
/* void AddWord (in wstring word); */
NS_IMETHODIMP mozPersonalDictionary::AddWord(const PRUnichar *word, const PRUnichar *lang)
NS_IMETHODIMP mozPersonalDictionary::AddWord(const PRUnichar *aWord, const PRUnichar *aLang)
{
nsAutoString temp(word);
if(mUnicodeTree) mUnicodeTree->AddItem(ToNewUnicode(nsDependentString(word)));
mDirty=PR_TRUE;
mDictionaryTable.PutEntry(aWord);
mDirty = PR_TRUE;
return NS_OK;
}
/* void RemoveWord (in wstring word); */
NS_IMETHODIMP mozPersonalDictionary::RemoveWord(const PRUnichar *word, const PRUnichar *lang)
NS_IMETHODIMP mozPersonalDictionary::RemoveWord(const PRUnichar *aWord, const PRUnichar *aLang)
{
nsAutoString temp(word);
if(mUnicodeTree) mUnicodeTree->RemoveItem((void *)word);
mDirty=PR_TRUE;
mDictionaryTable.RemoveEntry(aWord);
mDirty = PR_TRUE;
return NS_OK;
}
/* void IgnoreWord (in wstring word); */
NS_IMETHODIMP mozPersonalDictionary::IgnoreWord(const PRUnichar *word)
NS_IMETHODIMP mozPersonalDictionary::IgnoreWord(const PRUnichar *aWord)
{
if(!mUnicodeIgnoreTree){
mUnicodeIgnoreTree=new nsAVLTree(*gStringNodeComparitor,gDeallocatorFunctor);
}
if(!mUnicodeIgnoreTree){
return NS_ERROR_OUT_OF_MEMORY;
}
mUnicodeIgnoreTree->AddItem(ToNewUnicode(nsDependentString(word)));
mIgnoreTable.PutEntry(aWord);
return NS_OK;
}
/* void EndSession (); */
NS_IMETHODIMP mozPersonalDictionary::EndSession()
{
if(SessionSave)Save();
delete mUnicodeIgnoreTree;
mUnicodeIgnoreTree=nsnull;
if (SessionSave)
Save();
mIgnoreTable.Clear();
return NS_OK;
}
@ -396,17 +301,15 @@ NS_IMETHODIMP mozPersonalDictionary::Observe(nsISupports *aSubject, const char *
{
if (!nsCRT::strcmp(aTopic, "profile-before-change") || !nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
Save();
delete mUnicodeTree;
delete mUnicodeIgnoreTree;
mUnicodeTree=nsnull;
mUnicodeIgnoreTree=nsnull;
mDictionaryTable.Clear();
mIgnoreTable.Clear();
}
else if (!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
nsCOMPtr<nsIPrefBranch> prefs(do_QueryInterface(aSubject));
if(prefs)
prefs->GetBoolPref(spellchecker_savePref, &SessionSave);
}
if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
if (!nsCRT::strcmp(aTopic, "profile-do-change")) {
Load();
}

View File

@ -45,8 +45,8 @@
#include "nsIUnicodeEncoder.h"
#include "nsIObserver.h"
#include "nsWeakReference.h"
class nsAVLTree;
#include "nsTHashtable.h"
#include "nsCRT.h"
#define MOZ_PERSONALDICTIONARY_CONTRACTID "@mozilla.org/spellchecker/personaldictionary;1"
#define MOZ_PERSONALDICTIONARY_CID \
@ -54,6 +54,39 @@ class nsAVLTree;
0X7EF52EAF, 0XB7E1, 0X462B, \
{ 0X87, 0XE2, 0X5D, 0X1D, 0XBA, 0XCA, 0X90, 0X48 } }
class nsUniCharEntry : public PLDHashEntryHdr
{
public:
// Hash methods
typedef const PRUnichar* KeyType;
typedef const PRUnichar* KeyTypePointer;
nsUniCharEntry(const PRUnichar* aKey) : mKey(nsCRT::strdup(aKey)) {}
nsUniCharEntry(const nsUniCharEntry& toCopy)
{
NS_NOTREACHED("ALLOW_MEMMOVE is set, so copy ctor shouldn't be called");
}
~nsUniCharEntry()
{
if (mKey)
nsCRT::free(mKey);
}
KeyType GetKey() const { return mKey; }
KeyTypePointer GetKeyPointer() const { return mKey; }
PRBool KeyEquals(KeyTypePointer aKey) const { return !nsCRT::strcmp(mKey, aKey); }
static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; }
static PLDHashNumber HashKey(KeyTypePointer aKey) { return nsCRT::HashCode(aKey); }
enum { ALLOW_MEMMOVE = PR_TRUE };
private:
PRUnichar *mKey;
};
class mozPersonalDictionary : public mozIPersonalDictionary,
public nsIObserver,
public nsSupportsWeakReference
@ -66,12 +99,14 @@ public:
mozPersonalDictionary();
virtual ~mozPersonalDictionary();
nsresult Init();
protected:
nsStringArray mDictionary; /* use something a little smarter eventually*/
PRBool mDirty; /* has the dictionary been modified */
nsAVLTree *mUnicodeTree; /* the dictionary entries */
nsAVLTree *mUnicodeIgnoreTree; /* the ignore all entries */
nsCOMPtr<nsIUnicodeEncoder> mEncoder; /*Encoder to use to compare with spellchecker word */
nsTHashtable<nsUniCharEntry> mDictionaryTable;
nsTHashtable<nsUniCharEntry> mIgnoreTable;
nsCOMPtr<nsIUnicodeEncoder> mEncoder; /*Encoder to use to compare with spellchecker word */
};
#endif

View File

@ -39,13 +39,12 @@
#include "mozSpellChecker.h"
#include "nsIServiceManager.h"
#include "mozISpellI18NManager.h"
#include "nsIStringEnumerator.h"
NS_IMPL_ISUPPORTS1(mozSpellChecker, nsISpellChecker)
mozSpellChecker::mozSpellChecker()
{
mDictionaryName.SetLength(0);
nsresult rv;
mPersonalDictionary = do_GetService("@mozilla.org/spellchecker/personaldictionary;1",&rv);
@ -56,7 +55,6 @@ mozSpellChecker::mozSpellChecker()
if (NS_FAILED(rv)) {
NS_ERROR("Could not get spell checker");
}
mPersonalDictionary->Init();
mSpellCheckingEngine->SetPersonalDictionary(mPersonalDictionary);
}
@ -255,19 +253,18 @@ mozSpellChecker::RemoveWordFromPersonalDictionary(const nsAString &aWord)
NS_IMETHODIMP
mozSpellChecker::GetPersonalDictionary(nsStringArray *aWordList)
{
nsAutoString temp;
PRUint32 count,i;
PRUnichar **words;
if(!aWordList || !mPersonalDictionary)
return NS_ERROR_NULL_POINTER;
mPersonalDictionary->GetWordList(&words,&count);
for(i=0;i<count;i++){
temp.Assign(words[i]);
aWordList->AppendString(temp);
}
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, words);
nsCOMPtr<nsIStringEnumerator> words;
mPersonalDictionary->GetWordList(getter_AddRefs(words));
PRBool hasMore;
nsAutoString word;
while (NS_SUCCEEDED(words->HasMore(&hasMore)) && hasMore) {
words->GetNext(word);
aWordList->AppendString(word);
}
return NS_OK;
}

View File

@ -55,7 +55,7 @@
//
NS_GENERIC_FACTORY_CONSTRUCTOR(mozSpellChecker)
NS_GENERIC_FACTORY_CONSTRUCTOR(mozPersonalDictionary)
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(mozPersonalDictionary, Init)
NS_GENERIC_FACTORY_CONSTRUCTOR(mozSpellI18NManager)
////////////////////////////////////////////////////////////////////////