From 61ad3bf57adf9d8c42ad5c8a08eaeb5b1fb7c2e2 Mon Sep 17 00:00:00 2001 From: "aaronr%us.ibm.com" Date: Tue, 18 Sep 2007 18:14:35 +0000 Subject: [PATCH] move nsDeque .h and .cpp from xpcom/ds to xpcom/glue. Bug 395349, r+a=bsmedberg git-svn-id: svn://10.0.0.236/trunk@236229 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/xpcom/glue/Makefile.in | 1 + mozilla/xpcom/glue/nsDeque.cpp | 625 +++++++++++++++++++++++++++++++++ mozilla/xpcom/glue/nsDeque.h | 400 +++++++++++++++++++++ mozilla/xpcom/glue/objs.mk | 1 + 4 files changed, 1027 insertions(+) create mode 100644 mozilla/xpcom/glue/nsDeque.cpp create mode 100644 mozilla/xpcom/glue/nsDeque.h diff --git a/mozilla/xpcom/glue/Makefile.in b/mozilla/xpcom/glue/Makefile.in index 39d8465c4e9..91a07b06c81 100644 --- a/mozilla/xpcom/glue/Makefile.in +++ b/mozilla/xpcom/glue/Makefile.in @@ -112,6 +112,7 @@ SDK_HEADERS = \ nsIClassInfoImpl.h \ nsTObserverArray.h \ nsCycleCollectionParticipant.h \ + nsDeque.h \ $(NULL) EXPORTS = \ diff --git a/mozilla/xpcom/glue/nsDeque.cpp b/mozilla/xpcom/glue/nsDeque.cpp new file mode 100644 index 00000000000..7c1fd7a24f8 --- /dev/null +++ b/mozilla/xpcom/glue/nsDeque.cpp @@ -0,0 +1,625 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * 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. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsDeque.h" +#include "nsCRT.h" +#ifdef DEBUG_rickg +#include +#endif + +/** + * 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)) + +/** + * Standard constructor + * @param deallocator, called by Erase and ~nsDeque + */ +nsDeque::nsDeque(nsDequeFunctor* aDeallocator) { + MOZ_COUNT_CTOR(nsDeque); + mDeallocator=aDeallocator; + mOrigin=mSize=0; + mData=mBuffer; // don't allocate space until you must + mCapacity=sizeof(mBuffer)/sizeof(mBuffer[0]); + memset(mData, 0, mCapacity*sizeof(mBuffer[0])); +} + +/** + * Destructor + */ +nsDeque::~nsDeque() { + MOZ_COUNT_DTOR(nsDeque); + +#ifdef DEBUG_rickg + char buffer[30]; + 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) { + case 4: mCaps[0]++; break; + case 8: mCaps[1]++; break; + case 16: mCaps[2]++; break; + case 32: mCaps[3]++; break; + case 64: mCaps[4]++; break; + case 128: mCaps[5]++; break; + case 256: mCaps[6]++; break; + case 512: mCaps[7]++; break; + case 1024: mCaps[8]++; break; + case 2048: mCaps[9]++; break; + case 4096: mCaps[10]++; break; + default: + break; + } +#endif + + Erase(); + if (mData && (mData!=mBuffer)) { + delete [] mData; + } + mData=0; + SetDeallocator(0); +} + +/** + * Set the functor to be called by Erase() + * The deque owns the functor. + * + * @param aDeallocator functor object for use by Erase() + */ +void nsDeque::SetDeallocator(nsDequeFunctor* aDeallocator){ + if (mDeallocator) { + delete mDeallocator; + } + mDeallocator=aDeallocator; +} + +/** + * Remove all items from container without destroying them. + * + * @return *this + */ +nsDeque& nsDeque::Empty() { + if (mSize && mData) { + memset(mData, 0, mCapacity*sizeof(mData)); + } + mSize=0; + mOrigin=0; + return *this; +} + +/** + * Remove and delete all items from container + * + * @return *this + */ +nsDeque& nsDeque::Erase() { + if (mDeallocator && mSize) { + ForEach(*mDeallocator); + } + return Empty(); +} + +/** + * This method quadruples the size of the deque + * Elements in the deque are resequenced so that elements + * in the deque are stored sequentially + * + * If the deque actually overflows, there's very little we can do. + * Perhaps this function should return PRBool/nsresult indicating success/failure. + * + * @return capacity of the deque + * If the deque did not grow, + * and you knew its capacity beforehand, + * then this would be a way to indicate the failure. + */ +PRInt32 nsDeque::GrowCapacity() { + PRInt32 theNewSize=mCapacity<<2; + NS_ASSERTION(theNewSize>mCapacity, "Overflow"); + if (theNewSize<=mCapacity) + return mCapacity; + void** temp=new void*[theNewSize]; + + //Here's the interesting part: You can't just move the elements + //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 (temp) { + PRInt32 tempi=0; + PRInt32 i=0; + PRInt32 j=0; + for (i=mOrigin; i0) { + --mSize; + PRInt32 offset=modulus(mSize + mOrigin, mCapacity); + result=mData[offset]; + mData[offset]=0; + if (!mSize) { + mOrigin=0; + } + } + return result; +} + +/** + * This method gets called you want to remove and return + * the first member in the container. + * + * @return last item in container + */ +void* nsDeque::PopFront() { + void* result=0; + if (mSize>0) { + NS_ASSERTION(mOrigin < mCapacity, "Error: Bad origin"); + result=mData[mOrigin]; + mData[mOrigin++]=0; //zero it out for debugging purposes. + 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. + * + * @return last item in container + */ +void* nsDeque::Peek() { + 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. + * + * @return last item in container + */ +void* nsDeque::PeekFront() { + void* result=0; + if (mSize>0) { + result=mData[mOrigin]; + } + return result; +} + +/** + * Call this to retrieve the ith element from this container. + * 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). + * + * @param aIndex : 0 relative offset of item you want + * @return void* or null + */ +void* nsDeque::ObjectAt(PRInt32 aIndex) const { + void* result=0; + if ((aIndex>=0) && (aIndexoperator==(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))); +} + +/** + * Pre-increment operator + * + * @return object at post-incremented index + */ +void* nsDequeIterator::operator++() { + NS_ASSERTION(mIndex=mDeque.mSize) return 0; +#endif + return mDeque.ObjectAt(++mIndex); +} + +/** + * Post-increment operator + * + * @param param is ignored + * @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 + * + * @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 + * + * @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 + * + * @return object at ith index + */ +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); +} + +/** + * Call this method when you want to iterate all the + * members of the container, passing a functor along + * to call your code. + * + * @param aFunctor object to call for each member + * @return *this + */ +void nsDequeIterator::ForEach(nsDequeFunctor& aFunctor) const{ + mDeque.ForEach(aFunctor); +} + +/** + * Call this method when you want to iterate all the + * 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. + * + * @param aFunctor object to call for each member + * @return first nonzero result of aFunctor or 0. + */ +const void* nsDequeIterator::FirstThat(nsDequeFunctor& aFunctor) const{ + return mDeque.FirstThat(aFunctor); +} diff --git a/mozilla/xpcom/glue/nsDeque.h b/mozilla/xpcom/glue/nsDeque.h new file mode 100644 index 00000000000..f5db5a543d3 --- /dev/null +++ b/mozilla/xpcom/glue/nsDeque.h @@ -0,0 +1,400 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * 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. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/** + * MODULE NOTES: + * + * The Deque is a very small, very efficient container object + * than can hold elements of type void*, offering the following features: + * Its interface supports pushing and popping of elements. + * It can iterate (via an interator class) its elements. + * When full, it can efficiently resize dynamically. + * + * + * NOTE: The only bit of trickery here is that this deque is + * built upon a ring-buffer. Like all ring buffers, the first + * element may not be at index[0]. The mOrigin member determines + * where the first child is. This point is quietly hidden from + * customers of this class. + * + */ + +#ifndef _NSDEQUE +#define _NSDEQUE + +#include "nscore.h" + +/** + * The nsDequeFunctor class is used when you want to create + * callbacks between the deque and your generic code. + * Use these objects in a call to ForEach(); + * + */ + +class nsDequeFunctor{ +public: + virtual void* operator()(void* anObject)=0; +}; + +/****************************************************** + * Here comes the nsDeque class itself... + ******************************************************/ + +/** + * The deque (double-ended queue) class is a common container type, + * whose behavior mimics a line in your favorite checkout stand. + * Classic CS describes the common behavior of a queue as FIFO. + * A deque allows insertion and removal at both ends of + * the container. + * + * The deque stores pointers to items. + */ + +class nsDequeIterator; + +class NS_COM nsDeque { + friend class nsDequeIterator; + public: + nsDeque(nsDequeFunctor* aDeallocator = nsnull); + ~nsDeque(); + + /** + * Returns the number of elements currently stored in + * this deque. + * + * @return number of elements currently in the deque + */ + inline PRInt32 GetSize() const {return mSize;} + + /** + * Appends new member at the end of the deque. + * + * @param item to store in deque + * @return *this + */ + nsDeque& Push(void* aItem); + + /** + * Inserts new member at the front of the deque. + * + * @param item to store in deque + * @return *this + */ + nsDeque& PushFront(void* aItem); + + /** + * Remove and return the last item in the container. + * + * @return the item that was the last item in container + */ + void* Pop(); + + /** + * Remove and return the first item in the container. + * + * @return the item that was first item in container + */ + void* PopFront(); + + /** + * Retrieve the bottom item without removing it. + * + * @return the first item in container + */ + + void* Peek(); + /** + * Return topmost item without removing it. + * + * @return the first item in container + */ + void* PeekFront(); + + /** + * Retrieve the i'th member from the deque without removing it. + * + * @param index of desired item + * @return i'th element in list + */ + void* ObjectAt(int aIndex) const; + + /** + * Remove all items from container without destroying them. + * + * @return *this + */ + nsDeque& Empty(); + + /** + * Remove and delete all items from container. + * Deletes are handled by the deallocator nsDequeFunctor + * which is specified at deque construction. + * + * @return *this + */ + nsDeque& Erase(); + + /** + * Creates a new iterator, pointing to the first + * item in the deque. + * + * @return new dequeIterator + */ + nsDequeIterator Begin() const; + + /** + * Creates a new iterator, pointing to the last + * item in the deque. + * + * @return new dequeIterator + */ + nsDequeIterator End() const; + + void* Last() const; + /** + * Call this method when you want to iterate all the + * members of the container, passing a functor along + * to call your code. + * + * @param aFunctor object to call for each member + * @return *this + */ + void ForEach(nsDequeFunctor& aFunctor) const; + + /** + * Call this method when you want to iterate all the + * 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. + * + * @param aFunctor object to call for each member + * @return first nonzero result of aFunctor or 0. + */ + const void* FirstThat(nsDequeFunctor& aFunctor) const; + + void SetDeallocator(nsDequeFunctor* aDeallocator); + +protected: + PRInt32 mSize; + PRInt32 mCapacity; + PRInt32 mOrigin; + nsDequeFunctor* mDeallocator; + void* mBuffer[8]; + void** mData; + +private: + + /** + * Copy constructor (PRIVATE) + * + * @param another deque + */ + nsDeque(const nsDeque& other); + + /** + * Deque assignment operator (PRIVATE) + * + * @param another deque + * @return *this + */ + nsDeque& operator=(const nsDeque& anOther); + + PRInt32 GrowCapacity(); +}; + +/****************************************************** + * Here comes the nsDequeIterator class... + ******************************************************/ + +class NS_COM nsDequeIterator { +public: + /** + * DequeIterator is an object that knows how to iterate + * (forward and backward) through a Deque. Normally, + * you don't need to do this, but there are some special + * cases where it is pretty handy. + * + * One warning: the iterator is not bound to an item, + * it is bound to an index, so if you insert or remove + * from the beginning while using an iterator + * (which is not recommended) then the iterator will + * point to a different item. @see GetCurrent() + * + * Here you go. + * + * @param aQueue is the deque object to be iterated + * @param aIndex is the starting position for your iteration + */ + nsDequeIterator(const nsDeque& aQueue, int aIndex=0); + + /** + * Create a copy of a DequeIterator + * + * @param aCopy is another iterator to copy from + */ + nsDequeIterator(const nsDequeIterator& aCopy); + + /** + * Moves iterator to first element in the deque + * @return *this + */ + nsDequeIterator& First(); + + /** + * Standard assignment operator for dequeiterator + * @param aCopy is another iterator to copy from + * @return *this + */ + nsDequeIterator& operator=(const nsDequeIterator& aCopy); + + /** + * preform ! operation against two iterators to test for equivalence + * (or lack thereof)! + * + * @param aIter is the object to be compared to + * @return TRUE if NOT equal. + */ + PRBool operator!=(nsDequeIterator& 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 operator<(nsDequeIterator& aIter); + + /** + * Compare two iterators for equivalence. + * + * @param aIter is the other iterator to be compared to + * @return TRUE if EQUAL + */ + PRBool operator==(nsDequeIterator& aIter); + + /** + * Compare two iterators for non strict decreasing order. + * + * @param aIter is the other iterator to be compared to + * @return TRUE if this object points to the same element, or + * an element after the element pointed to by aIter. + * FALSE if this and aIter are not iterating over + * the same deque. + */ + PRBool operator>=(nsDequeIterator& aIter); + + /** + * Pre-increment operator + * Iterator will advance one index towards the end. + * + * @return object_at(++index) + */ + void* operator++(); + + /** + * Post-increment operator + * Iterator will advance one index towards the end. + * + * @param param is ignored + * @return object_at(mIndex++) + */ + void* operator++(int); + + /** + * Pre-decrement operator + * Iterator will advance one index towards the beginning. + * + * @return object_at(--index) + */ + void* operator--(); + + /** + * Post-decrement operator + * Iterator will advance one index towards the beginning. + * + * @param param is ignored + * @return object_at(index--) + */ + void* operator--(int); + + /** + * Retrieve the the iterator's notion of current node. + * + * Note that the iterator floats, so you don't need to do: + * ++iter; aDeque.PopFront(); + * Unless you actually want your iterator to jump 2 positions + * relative to its origin. + * + * Picture: [1 2i 3 4] + * PopFront() + * Picture: [2 3i 4] + * Note that I still happily points to object at the second index. + * + * @return object at i'th index + */ + void* GetCurrent(); + + /** + * Call this method when you want to iterate all the + * members of the container, passing a functor along + * to call your code. + * + * @param aFunctor object to call for each member + * @return *this + */ + void ForEach(nsDequeFunctor& aFunctor) const; + + /** + * Call this method when you want to iterate all the + * 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. + * + * @param aFunctor object to call for each member + * @return first nonzero result of aFunctor or 0. + */ + const void* FirstThat(nsDequeFunctor& aFunctor) const; + + protected: + + PRInt32 mIndex; + const nsDeque& mDeque; +}; +#endif diff --git a/mozilla/xpcom/glue/objs.mk b/mozilla/xpcom/glue/objs.mk index a4885f3860a..93555dba82f 100644 --- a/mozilla/xpcom/glue/objs.mk +++ b/mozilla/xpcom/glue/objs.mk @@ -64,6 +64,7 @@ XPCOM_GLUE_SRC_LCPPSRCS = \ nsThreadUtils.cpp \ nsTObserverArray.cpp \ nsCycleCollectionParticipant.cpp \ + nsDeque.cpp \ $(NULL) XPCOM_GLUE_SRC_CPPSRCS = $(addprefix $(topsrcdir)/xpcom/glue/, $(XPCOM_GLUE_SRC_LCPPSRCS))