diff --git a/editor/txmgr/src/nsTransactionManager.cpp b/editor/txmgr/src/nsTransactionManager.cpp index 6e8e7e537a67..463d92527709 100644 --- a/editor/txmgr/src/nsTransactionManager.cpp +++ b/editor/txmgr/src/nsTransactionManager.cpp @@ -482,22 +482,26 @@ nsTransactionManager::SetMaxTransactionCount(PRInt32 aMaxCount) LOCK_TX_MANAGER(this); - // It is illegal to call SetMaxTransactionCount() while the transaction - // manager is executing a transaction's DoTransaction() method because - // the undo and redo stacks might get pruned! If this happens, the - // SetMaxTransactionCount() request is ignored, and we return - // NS_ERROR_FAILURE. + result = mDoStack.GetSize(&total); + if (NS_SUCCEEDED(result) && total) { - result = mDoStack.Peek(&tx); + // It is illegal to call SetMaxTransactionCount() while the transaction + // manager is executing a transaction's DoTransaction() method because + // the undo and redo stacks might get pruned! If this happens, the + // SetMaxTransactionCount() request is ignored, and we return + // NS_ERROR_FAILURE. - if (NS_FAILED(result)) { - UNLOCK_TX_MANAGER(this); - return result; - } + result = mDoStack.Peek(&tx); - if (tx) { - UNLOCK_TX_MANAGER(this); - return NS_ERROR_FAILURE; + if (NS_FAILED(result)) { + UNLOCK_TX_MANAGER(this); + return result; + } + + if (tx) { + UNLOCK_TX_MANAGER(this); + return NS_ERROR_FAILURE; + } } // If aMaxCount is less than zero, the user wants unlimited diff --git a/editor/txmgr/src/nsTransactionStack.cpp b/editor/txmgr/src/nsTransactionStack.cpp index b3bb916a25ae..40e86e3a1bbc 100644 --- a/editor/txmgr/src/nsTransactionStack.cpp +++ b/editor/txmgr/src/nsTransactionStack.cpp @@ -101,6 +101,9 @@ nsTransactionStack::Peek(nsTransactionItem **aTransaction) if (!aTransaction) return NS_ERROR_NULL_POINTER; + if (!mQue.GetSize()) + return NS_ERROR_NULL_POINTER; + /* nsDeque's End() method returns an iterator that is * passed the last entry of the deque. We need to decrement * to get to the last entry. diff --git a/embedding/components/find/src/nsFind.cpp b/embedding/components/find/src/nsFind.cpp index bf91569ea67f..1ffd2c90af12 100644 --- a/embedding/components/find/src/nsFind.cpp +++ b/embedding/components/find/src/nsFind.cpp @@ -744,7 +744,7 @@ PRBool nsFind::FindInQ(const PRUnichar* aPatStr, PRInt32 aPatLen, #endif // Get the current node, either from the deque or the tree. - if (fromQ && (iter != iterEnd)) + if (fromQ && mNodeQ.GetSize() > 0 && (iter != iterEnd)) tc = NS_STATIC_CAST(nsITextContent*, iter.GetCurrent()); else tc = nsnull; @@ -871,7 +871,6 @@ PRBool nsFind::FindInQ(const PRUnichar* aPatStr, PRInt32 aPatLen, if (restart <= 0) mNodeQ.Pop(); } else { - ++iter; if (restart >= frag->GetLength()) mNodeQ.PopFront(); } diff --git a/htmlparser/src/nsDTDUtils.h b/htmlparser/src/nsDTDUtils.h index 4f9d7f0138ad..c32ffbfe7fd5 100644 --- a/htmlparser/src/nsDTDUtils.h +++ b/htmlparser/src/nsDTDUtils.h @@ -580,6 +580,7 @@ public: protected: nsAutoString mTopic; // This will rarely be empty, so make it an auto string nsVoidArray* mObservers[NS_HTML_TAG_MAX + 1]; + friend class nsMatchesTopic; }; /*********************************************************************************************/ diff --git a/htmlparser/src/nsHTMLTokenizer.cpp b/htmlparser/src/nsHTMLTokenizer.cpp index 504ebb812785..37e0532596f9 100644 --- a/htmlparser/src/nsHTMLTokenizer.cpp +++ b/htmlparser/src/nsHTMLTokenizer.cpp @@ -241,7 +241,7 @@ CToken* nsHTMLTokenizer::PopToken() { */ CToken* nsHTMLTokenizer::PushTokenFront(CToken* theToken) { mTokenDeque.PushFront(theToken); - return theToken; + return theToken; } /** @@ -252,7 +252,7 @@ CToken* nsHTMLTokenizer::PushTokenFront(CToken* theToken) { */ CToken* nsHTMLTokenizer::PushToken(CToken* theToken) { mTokenDeque.Push(theToken); - return theToken; + return theToken; } /** @@ -285,7 +285,7 @@ nsresult nsHTMLTokenizer::WillTokenize(PRBool aIsFinalChunk,nsTokenAllocator* aT { mTokenAllocator=aTokenAllocator; mIsFinalChunk=aIsFinalChunk; - mTokenScanPos=mTokenDeque.GetSize()+1; //cause scanDocStructure to search from here for new tokens... + mTokenScanPos=mTokenDeque.GetSize(); //cause scanDocStructure to search from here for new tokens... return NS_OK; } @@ -345,7 +345,8 @@ static PRInt32 FindLastIndexOfTag(eHTMLTags aTag,nsDeque &aTagStack) { */ nsresult nsHTMLTokenizer::ScanDocStructure(PRBool aFinalChunk) { nsresult result=NS_OK; - + if (!mTokenDeque.GetSize()) + return result; CHTMLToken *theRootToken=0; diff --git a/htmlparser/src/nsParserService.cpp b/htmlparser/src/nsParserService.cpp index 850963c5d812..7c5fbef5c15c 100644 --- a/htmlparser/src/nsParserService.cpp +++ b/htmlparser/src/nsParserService.cpp @@ -183,28 +183,33 @@ nsParserService::GetTopicObservers(const nsAString& aTopic, return result; } +class nsMatchesTopic : public nsDequeFunctor{ + const nsAString& mString; +public: + PRBool matched; + nsObserverEntry* entry; + nsMatchesTopic(const nsAString& aString):mString(aString),matched(PR_FALSE){}; + virtual void* operator()(void* anObject){ + entry=NS_STATIC_CAST(nsObserverEntry*, anObject); + matched=mString.Equals(entry->mTopic); + return matched ? nsnull : anObject; + }; +}; + // XXX This may be more efficient as a HashTable instead of linear search nsObserverEntry* nsParserService::GetEntry(const nsAString& aTopic) { - if(!mHaveNotifiedCategoryObservers) { + if (!mHaveNotifiedCategoryObservers) { mHaveNotifiedCategoryObservers = PR_TRUE; NS_CreateServicesFromCategory("parser-service-category", NS_STATIC_CAST(nsISupports*,NS_STATIC_CAST(void*,this)), "parser-service-start"); } - - PRInt32 index = 0; - nsObserverEntry* entry = nsnull; - - while (entry = NS_STATIC_CAST(nsObserverEntry*,mEntries.ObjectAt(index++))) { - if (entry->Matches(aTopic)) { - break; - } - } - - return entry; + nsMatchesTopic matchesTopic(aTopic); + mEntries.FirstThat(*&matchesTopic); + return matchesTopic.matched?matchesTopic.entry:nsnull; } nsresult diff --git a/parser/htmlparser/src/nsDTDUtils.h b/parser/htmlparser/src/nsDTDUtils.h index 4f9d7f0138ad..c32ffbfe7fd5 100644 --- a/parser/htmlparser/src/nsDTDUtils.h +++ b/parser/htmlparser/src/nsDTDUtils.h @@ -580,6 +580,7 @@ public: protected: nsAutoString mTopic; // This will rarely be empty, so make it an auto string nsVoidArray* mObservers[NS_HTML_TAG_MAX + 1]; + friend class nsMatchesTopic; }; /*********************************************************************************************/ diff --git a/parser/htmlparser/src/nsHTMLTokenizer.cpp b/parser/htmlparser/src/nsHTMLTokenizer.cpp index 504ebb812785..37e0532596f9 100644 --- a/parser/htmlparser/src/nsHTMLTokenizer.cpp +++ b/parser/htmlparser/src/nsHTMLTokenizer.cpp @@ -241,7 +241,7 @@ CToken* nsHTMLTokenizer::PopToken() { */ CToken* nsHTMLTokenizer::PushTokenFront(CToken* theToken) { mTokenDeque.PushFront(theToken); - return theToken; + return theToken; } /** @@ -252,7 +252,7 @@ CToken* nsHTMLTokenizer::PushTokenFront(CToken* theToken) { */ CToken* nsHTMLTokenizer::PushToken(CToken* theToken) { mTokenDeque.Push(theToken); - return theToken; + return theToken; } /** @@ -285,7 +285,7 @@ nsresult nsHTMLTokenizer::WillTokenize(PRBool aIsFinalChunk,nsTokenAllocator* aT { mTokenAllocator=aTokenAllocator; mIsFinalChunk=aIsFinalChunk; - mTokenScanPos=mTokenDeque.GetSize()+1; //cause scanDocStructure to search from here for new tokens... + mTokenScanPos=mTokenDeque.GetSize(); //cause scanDocStructure to search from here for new tokens... return NS_OK; } @@ -345,7 +345,8 @@ static PRInt32 FindLastIndexOfTag(eHTMLTags aTag,nsDeque &aTagStack) { */ nsresult nsHTMLTokenizer::ScanDocStructure(PRBool aFinalChunk) { nsresult result=NS_OK; - + if (!mTokenDeque.GetSize()) + return result; CHTMLToken *theRootToken=0; diff --git a/parser/htmlparser/src/nsParserService.cpp b/parser/htmlparser/src/nsParserService.cpp index 850963c5d812..7c5fbef5c15c 100644 --- a/parser/htmlparser/src/nsParserService.cpp +++ b/parser/htmlparser/src/nsParserService.cpp @@ -183,28 +183,33 @@ nsParserService::GetTopicObservers(const nsAString& aTopic, return result; } +class nsMatchesTopic : public nsDequeFunctor{ + const nsAString& mString; +public: + PRBool matched; + nsObserverEntry* entry; + nsMatchesTopic(const nsAString& aString):mString(aString),matched(PR_FALSE){}; + virtual void* operator()(void* anObject){ + entry=NS_STATIC_CAST(nsObserverEntry*, anObject); + matched=mString.Equals(entry->mTopic); + return matched ? nsnull : anObject; + }; +}; + // XXX This may be more efficient as a HashTable instead of linear search nsObserverEntry* nsParserService::GetEntry(const nsAString& aTopic) { - if(!mHaveNotifiedCategoryObservers) { + if (!mHaveNotifiedCategoryObservers) { mHaveNotifiedCategoryObservers = PR_TRUE; NS_CreateServicesFromCategory("parser-service-category", NS_STATIC_CAST(nsISupports*,NS_STATIC_CAST(void*,this)), "parser-service-start"); } - - PRInt32 index = 0; - nsObserverEntry* entry = nsnull; - - while (entry = NS_STATIC_CAST(nsObserverEntry*,mEntries.ObjectAt(index++))) { - if (entry->Matches(aTopic)) { - break; - } - } - - return entry; + nsMatchesTopic matchesTopic(aTopic); + mEntries.FirstThat(*&matchesTopic); + return matchesTopic.matched?matchesTopic.entry:nsnull; } nsresult diff --git a/xpcom/ds/nsDeque.cpp b/xpcom/ds/nsDeque.cpp index e3f5d70c391a..6f992ecf9f4b 100644 --- a/xpcom/ds/nsDeque.cpp +++ b/xpcom/ds/nsDeque.cpp @@ -14,7 +14,7 @@ * * The Original Code is mozilla.org code. * - * The Initial Developer of the Original Code is + * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. @@ -22,7 +22,7 @@ * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or + * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only @@ -35,20 +35,49 @@ * * ***** END LICENSE BLOCK ***** */ - #include "nsDeque.h" #include "nsCRT.h" +#ifdef DEBUG_rickg #include +#endif -//#define _SELFTEST_DEQUE 1 -#undef _SELFTEST_DEQUE +/** + * 07/02/2001 09:17p 509,104 clangref.pdf from openwatcom's site + * Watcom C Language Reference Edition 11.0c + * page 118 of 297 + * + * The % symbol yields the remainder from the division of the first operand + * by the second operand. The operands of % must have integral type. + * + * When both operands of % are positive, the result is a positive value + * smaller than the second operand. When one or both operands is negative, + * whether the result is positive or negative is implementation-defined. + * + */ +/* Ok, so first of all, C is underspecified. joy. + * The following functions do not provide a correct implementation of modulus + * They provide functionality for x>-y. + * There are risks of 2*y being greater than max int, which is part of the + * reason no multiplication is used and other operations are avoided. + * + * modasgn + * @param x variable + * @param y expression + * approximately equivalent to x %= y + * + * modulus + * @param x expression + * @param y expression + * approximately equivalent to x % y + */ +#define modasgn(x,y) if (x<0) x+=y; x%=y +#define modulus(x,y) ((x<0)?(x+y)%(y):(x)%(y)) MOZ_DECL_CTOR_COUNTER(nsDeque) /** * Standard constructor - * @update gess4/18/98 - * @return new deque + * @param deallocator, called by Erase and ~nsDeque */ nsDeque::nsDeque(nsDequeFunctor* aDeallocator) { MOZ_COUNT_CTOR(nsDeque); @@ -59,17 +88,15 @@ nsDeque::nsDeque(nsDequeFunctor* aDeallocator) { memset(mData, 0, mCapacity*sizeof(mBuffer[0])); } - /** * Destructor - * @update gess4/18/98 */ nsDeque::~nsDeque() { MOZ_COUNT_DTOR(nsDeque); -#if 0 +#ifdef DEBUG_rickg char buffer[30]; - printf("Capacity: %i\n",mCapacity); + printf("Capacity: %i\n", mCapacity); static int mCaps[15] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; switch(mCapacity) { @@ -90,24 +117,21 @@ nsDeque::~nsDeque() { #endif Erase(); - if(mData && (mData!=mBuffer)) + if (mData && (mData!=mBuffer)) { delete [] mData; - mData=0; - if(mDeallocator) { - delete mDeallocator; } - mDeallocator=0; + mData=0; + SetDeallocator(0); } - /** + * Set the functor to be called by Erase() + * The deque owns the functor. * - * @update gess4/18/98 - * @param - * @return - */ + * @param aDeallocator functor object for use by Erase() + */ void nsDeque::SetDeallocator(nsDequeFunctor* aDeallocator){ - if(mDeallocator) { + if (mDeallocator) { delete mDeallocator; } mDeallocator=aDeallocator; @@ -116,12 +140,10 @@ void nsDeque::SetDeallocator(nsDequeFunctor* aDeallocator){ /** * Remove all items from container without destroying them. * - * @update gess4/18/98 - * @param - * @return + * @return *this */ nsDeque& nsDeque::Empty() { - if((0mCapacity, "Overflow"); + if (theNewSize<=mCapacity) + return mCapacity; void** temp=new void*[theNewSize]; //Here's the interesting part: You can't just move the elements - //directy (in situ) from the old buffer to the new one. + //directly (in situ) from the old buffer to the new one. //Since capacity has changed, the old origin doesn't make //sense anymore. It's better to resequence the elements now. - if(mData) { - int tempi=0; - int i=0; - int j=0; - for(i=mOrigin;i0) { - int offset=mOrigin+mSize-1; - if(offset>=mCapacity) - offset-=mCapacity; + if (mSize>0) { + --mSize; + PRInt32 offset=modulus(mSize + mOrigin, mCapacity); result=mData[offset]; mData[offset]=0; - mSize--; - if(0==mSize) + if (!mSize) { mOrigin=0; + } } return result; } @@ -249,52 +291,47 @@ void* nsDeque::Pop(void) { * This method gets called you want to remove and return * the first member in the container. * - * @update gess4/18/98 - * @param nada * @return last item in container */ void* nsDeque::PopFront() { void* result=0; - if(mSize>0) { - NS_ASSERTION(mOrigin0) { + NS_ASSERTION(mOrigin < mCapacity, "Error: Bad origin"); result=mData[mOrigin]; mData[mOrigin++]=0; //zero it out for debugging purposes. mSize--; - if(mCapacity==mOrigin) //you popped off the end, so cycle back around... - mOrigin=0; - if(0==mSize) + // Cycle around if we pop off the end + // and reset origin if when we pop the last element + if (mCapacity==mOrigin || !mSize) { mOrigin=0; + } } return result; } + /** * This method gets called you want to peek at the bottom * member without removing it. * - * @update sford 11/25/99 - * @param nada * @return last item in container */ void* nsDeque::Peek() { - void* result=0; - if(mSize>0) { - int offset=mOrigin+mSize-1; - result=mData[offset]; - } - return result; -} + void* result=0; + if (mSize>0) { + result = mData[modulus(mSize - 1 + mOrigin, mCapacity)]; + } + return result; +} /** * This method gets called you want to peek at the topmost * member without removing it. * - * @update sford 11/25/99 - * @param nada * @return last item in container */ void* nsDeque::PeekFront() { void* result=0; - if(mSize>0) { + if (mSize>0) { result=mData[mOrigin]; } return result; @@ -302,25 +339,17 @@ void* nsDeque::PeekFront() { /** * Call this to retrieve the ith element from this container. - * Keep in mind that accessing the underlying elements is + * Keep in mind that accessing the underlying elements is * done in a relative fashion. Object 0 is not necessarily * the first element (the first element is at mOrigin). * - * @update gess4/18/98 - * @param anIndex : 0 relative offset of item you want + * @param aIndex : 0 relative offset of item you want * @return void* or null */ -void* nsDeque::ObjectAt(PRInt32 anIndex) const { +void* nsDeque::ObjectAt(PRInt32 aIndex) const { void* result=0; - - if((anIndex>=0) && (anIndex=0) && (aIndexoperator==(anIter)); +PRBool nsDequeIterator::operator!=(nsDequeIterator& aIter) { + return PRBool(!this->operator==(aIter)); } +/** + * Compare two iterators for increasing order. + * + * @param aIter is the other iterator to be compared to + * @return TRUE if this object points to an element before + * the element pointed to by aIter. + * FALSE if this and aIter are not iterating over the same deque. + */ +PRBool nsDequeIterator::operator<(nsDequeIterator& aIter) { + return PRBool(((mIndex=(nsDequeIterator& aIter) { + return PRBool(((mIndex>=aIter.mIndex) && (&mDeque==&aIter.mDeque))); } /** - * Compare 2 iterators for equivalence. + * Pre-increment operator * - * @update gess4/18/98 - * @param anIter is the other iterator to be compared to - * @return TRUE if EQUAL - */ -PRBool nsDequeIterator::operator>=(nsDequeIterator& anIter) { - return PRBool(((mIndex>=anIter.mIndex) && (&mDeque==&anIter.mDeque))); -} - -/** - * Pre-increment operator - * - * @update gess4/18/98 - * @return object at preincremented index + * @return object at post-incremented index */ void* nsDequeIterator::operator++() { + NS_ASSERTION(mIndex=mDeque.mSize) return 0; +#endif return mDeque.ObjectAt(++mIndex); } /** - * Post-increment operator + * Post-increment operator * - * @update gess4/18/98 * @param param is ignored - * @return object at post-incremented index + * @return object at pre-incremented index */ void* nsDequeIterator::operator++(int) { + NS_ASSERTION(mIndex<=mDeque.mSize, + "You have already reached the end of the Internet."\ + "You have seen everything there is to see. Please go back. Now." + ); +#ifndef TIMELESS_LIGHTWEIGHT + if (mIndex>mDeque.mSize) return 0; +#endif return mDeque.ObjectAt(mIndex++); } /** * Pre-decrement operator * - * @update gess4/18/98 * @return object at pre-decremented index */ void* nsDequeIterator::operator--() { + NS_ASSERTION(mIndex>=0, + "You have reached the beginning of the Internet."\ + "You have seen everything there is to see. Please go forward. Now." + ); +#ifndef TIMELESS_LIGHTWEIGHT + if (mIndex<0) return 0; +#endif return mDeque.ObjectAt(--mIndex); } /** * Post-decrement operator * - * @update gess4/18/98 * @param param is ignored * @return object at post-decremented index */ void* nsDequeIterator::operator--(int) { + NS_ASSERTION(mIndex>=0, + "You have already reached the beginning of the Internet."\ + "You have seen everything there is to see. Please go forward. Now." + ); +#ifndef TIMELESS_LIGHTWEIGHT + if (mIndex<0) return 0; +#endif return mDeque.ObjectAt(mIndex--); } /** * Dereference operator + * Note that the iterator floats, so you don't need to do: + * ++iter; aDeque.PopFront(); + * Unless you actually want your iterator to jump 2 spaces. + * + * Picture: [1 2I 3 4] + * PopFront() + * Picture: [2 3I 4] + * Note that I still happily points to object at the second index * - * @update gess4/18/98 * @return object at ith index */ -void* nsDequeIterator::GetCurrent(void) { +void* nsDequeIterator::GetCurrent() { + NS_ASSERTION(mIndex=0,"Current is out of bounds"); +#ifndef TIMELESS_LIGHTWEIGHT + if (mIndex>=mDeque.mSize||mIndex<0) return 0; +#endif return mDeque.ObjectAt(mIndex); } @@ -542,7 +598,6 @@ void* nsDequeIterator::GetCurrent(void) { * members of the container, passing a functor along * to call your code. * - * @update gess4/20/98 * @param aFunctor object to call for each member * @return *this */ @@ -552,82 +607,13 @@ void nsDequeIterator::ForEach(nsDequeFunctor& aFunctor) const{ /** * Call this method when you want to iterate all the - * members of the container, passing a functor along - * to call your code. + * members of the container, calling the functor you + * passed with each member. This process will interrupt + * if your function returns non 0 to this method. * - * @update gess4/20/98 * @param aFunctor object to call for each member - * @return *this + * @return first nonzero result of aFunctor or 0. */ const void* nsDequeIterator::FirstThat(nsDequeFunctor& aFunctor) const{ return mDeque.FirstThat(aFunctor); } - -#ifdef _SELFTEST_DEQUE -/************************************************************** - Now define the token deallocator class... - **************************************************************/ -class _SelfTestDeallocator: public nsDequeFunctor{ -public: - _SelfTestDeallocator::_SelfTestDeallocator() { - nsDeque::SelfTest(); - } - virtual void* operator()(void* anObject) { - return 0; - } -}; -static _SelfTestDeallocator gDeallocator; -#endif - -/** - * conduct automated self test for this class - * - * @update gess4/18/98 - * @param - * @return - */ -void nsDeque::SelfTest(void) { -#ifdef _SELFTEST_DEQUE - - { - nsDeque theDeque(gDeallocator); //construct a simple one... - - int ints[200]; - int count=sizeof(ints)/sizeof(int); - int i=0; - - for(i=0;i