1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/glue/nsDeque.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,610 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsDeque.h" 1.10 +#include "nsISupportsImpl.h" 1.11 +#include <string.h> 1.12 +#ifdef DEBUG_rickg 1.13 +#include <stdio.h> 1.14 +#endif 1.15 + 1.16 +/** 1.17 + * 07/02/2001 09:17p 509,104 clangref.pdf from openwatcom's site 1.18 + * Watcom C Language Reference Edition 11.0c 1.19 + * page 118 of 297 1.20 + * 1.21 + * The % symbol yields the remainder from the division of the first operand 1.22 + * by the second operand. The operands of % must have integral type. 1.23 + * 1.24 + * When both operands of % are positive, the result is a positive value 1.25 + * smaller than the second operand. When one or both operands is negative, 1.26 + * whether the result is positive or negative is implementation-defined. 1.27 + * 1.28 + */ 1.29 +/* Ok, so first of all, C is underspecified. joy. 1.30 + * The following functions do not provide a correct implementation of modulus 1.31 + * They provide functionality for x>-y. 1.32 + * There are risks of 2*y being greater than max int, which is part of the 1.33 + * reason no multiplication is used and other operations are avoided. 1.34 + * 1.35 + * modasgn 1.36 + * @param x variable 1.37 + * @param y expression 1.38 + * approximately equivalent to x %= y 1.39 + * 1.40 + * modulus 1.41 + * @param x expression 1.42 + * @param y expression 1.43 + * approximately equivalent to x % y 1.44 + */ 1.45 +#define modasgn(x,y) if (x<0) x+=y; x%=y 1.46 +#define modulus(x,y) ((x<0)?(x+y)%(y):(x)%(y)) 1.47 + 1.48 +/** 1.49 + * Standard constructor 1.50 + * @param deallocator, called by Erase and ~nsDeque 1.51 + */ 1.52 +nsDeque::nsDeque(nsDequeFunctor* aDeallocator) { 1.53 + MOZ_COUNT_CTOR(nsDeque); 1.54 + mDeallocator=aDeallocator; 1.55 + mOrigin=mSize=0; 1.56 + mData=mBuffer; // don't allocate space until you must 1.57 + mCapacity=sizeof(mBuffer)/sizeof(mBuffer[0]); 1.58 + memset(mData, 0, mCapacity*sizeof(mBuffer[0])); 1.59 +} 1.60 + 1.61 +/** 1.62 + * Destructor 1.63 + */ 1.64 +nsDeque::~nsDeque() { 1.65 + MOZ_COUNT_DTOR(nsDeque); 1.66 + 1.67 +#ifdef DEBUG_rickg 1.68 + char buffer[30]; 1.69 + printf("Capacity: %i\n", mCapacity); 1.70 + 1.71 + static int mCaps[15] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; 1.72 + switch(mCapacity) { 1.73 + case 4: mCaps[0]++; break; 1.74 + case 8: mCaps[1]++; break; 1.75 + case 16: mCaps[2]++; break; 1.76 + case 32: mCaps[3]++; break; 1.77 + case 64: mCaps[4]++; break; 1.78 + case 128: mCaps[5]++; break; 1.79 + case 256: mCaps[6]++; break; 1.80 + case 512: mCaps[7]++; break; 1.81 + case 1024: mCaps[8]++; break; 1.82 + case 2048: mCaps[9]++; break; 1.83 + case 4096: mCaps[10]++; break; 1.84 + default: 1.85 + break; 1.86 + } 1.87 +#endif 1.88 + 1.89 + Erase(); 1.90 + if (mData && (mData!=mBuffer)) { 1.91 + free(mData); 1.92 + } 1.93 + mData=0; 1.94 + SetDeallocator(0); 1.95 +} 1.96 + 1.97 +size_t nsDeque::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const { 1.98 + size_t size = 0; 1.99 + if (mData != mBuffer) { 1.100 + size += aMallocSizeOf(mData); 1.101 + } 1.102 + 1.103 + if (mDeallocator) { 1.104 + size += aMallocSizeOf(mDeallocator); 1.105 + } 1.106 + 1.107 + return size; 1.108 +} 1.109 + 1.110 +size_t nsDeque::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const { 1.111 + return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); 1.112 +} 1.113 + 1.114 +/** 1.115 + * Set the functor to be called by Erase() 1.116 + * The deque owns the functor. 1.117 + * 1.118 + * @param aDeallocator functor object for use by Erase() 1.119 + */ 1.120 +void nsDeque::SetDeallocator(nsDequeFunctor* aDeallocator){ 1.121 + delete mDeallocator; 1.122 + mDeallocator=aDeallocator; 1.123 +} 1.124 + 1.125 +/** 1.126 + * Remove all items from container without destroying them. 1.127 + */ 1.128 +void nsDeque::Empty() { 1.129 + if (mSize && mData) { 1.130 + memset(mData, 0, mCapacity*sizeof(mData)); 1.131 + } 1.132 + mSize=0; 1.133 + mOrigin=0; 1.134 +} 1.135 + 1.136 +/** 1.137 + * Remove and delete all items from container 1.138 + */ 1.139 +void nsDeque::Erase() { 1.140 + if (mDeallocator && mSize) { 1.141 + ForEach(*mDeallocator); 1.142 + } 1.143 + Empty(); 1.144 +} 1.145 + 1.146 +/** 1.147 + * This method quadruples the size of the deque 1.148 + * Elements in the deque are resequenced so that elements 1.149 + * in the deque are stored sequentially 1.150 + * 1.151 + * @return whether growing succeeded 1.152 + */ 1.153 +bool nsDeque::GrowCapacity() { 1.154 + int32_t theNewSize=mCapacity<<2; 1.155 + NS_ASSERTION(theNewSize>mCapacity, "Overflow"); 1.156 + if (theNewSize<=mCapacity) 1.157 + return false; 1.158 + void** temp=(void**)malloc(theNewSize * sizeof(void*)); 1.159 + if (!temp) 1.160 + return false; 1.161 + 1.162 + //Here's the interesting part: You can't just move the elements 1.163 + //directly (in situ) from the old buffer to the new one. 1.164 + //Since capacity has changed, the old origin doesn't make 1.165 + //sense anymore. It's better to resequence the elements now. 1.166 + 1.167 + memcpy(temp, mData + mOrigin, sizeof(void*) * (mCapacity - mOrigin)); 1.168 + memcpy(temp + (mCapacity - mOrigin), mData, sizeof(void*) * mOrigin); 1.169 + 1.170 + if (mData != mBuffer) { 1.171 + free(mData); 1.172 + } 1.173 + 1.174 + mCapacity=theNewSize; 1.175 + mOrigin=0; //now realign the origin... 1.176 + mData=temp; 1.177 + 1.178 + return true; 1.179 +} 1.180 + 1.181 +/** 1.182 + * This method adds an item to the end of the deque. 1.183 + * This operation has the potential to cause the 1.184 + * underlying buffer to resize. 1.185 + * 1.186 + * @param aItem: new item to be added to deque 1.187 + */ 1.188 +bool nsDeque::Push(void* aItem, const fallible_t&) { 1.189 + if (mSize==mCapacity && !GrowCapacity()) { 1.190 + return false; 1.191 + } 1.192 + mData[modulus(mOrigin + mSize, mCapacity)]=aItem; 1.193 + mSize++; 1.194 + return true; 1.195 +} 1.196 + 1.197 +/** 1.198 + * This method adds an item to the front of the deque. 1.199 + * This operation has the potential to cause the 1.200 + * underlying buffer to resize. 1.201 + * 1.202 + * --Commments for GrowCapacity() case 1.203 + * We've grown and shifted which means that the old 1.204 + * final element in the deque is now the first element 1.205 + * in the deque. This is temporary. 1.206 + * We haven't inserted the new element at the front. 1.207 + * 1.208 + * To continue with the idea of having the front at zero 1.209 + * after a grow, we move the old final item (which through 1.210 + * the voodoo of mOrigin-- is now the first) to its final 1.211 + * position which is conveniently the old length. 1.212 + * 1.213 + * Note that this case only happens when the deque is full. 1.214 + * [And that pieces of this magic only work if the deque is full.] 1.215 + * picture: 1.216 + * [ABCDEFGH] @[mOrigin:3]:D. 1.217 + * Task: PushFront("Z") 1.218 + * shift mOrigin so, @[mOrigin:2]:C 1.219 + * stretch and rearrange: (mOrigin:0) 1.220 + * [CDEFGHAB ________ ________ ________] 1.221 + * copy: (The second C is currently out of bounds) 1.222 + * [CDEFGHAB C_______ ________ ________] 1.223 + * later we will insert Z: 1.224 + * [ZDEFGHAB C_______ ________ ________] 1.225 + * and increment size: 9. (C is no longer out of bounds) 1.226 + * -- 1.227 + * @param aItem: new item to be added to deque 1.228 + */ 1.229 +bool nsDeque::PushFront(void* aItem, const fallible_t&) { 1.230 + mOrigin--; 1.231 + modasgn(mOrigin,mCapacity); 1.232 + if (mSize==mCapacity) { 1.233 + if (!GrowCapacity()) { 1.234 + return false; 1.235 + } 1.236 + /* Comments explaining this are above*/ 1.237 + mData[mSize]=mData[mOrigin]; 1.238 + } 1.239 + mData[mOrigin]=aItem; 1.240 + mSize++; 1.241 + return true; 1.242 +} 1.243 + 1.244 +/** 1.245 + * Remove and return the last item in the container. 1.246 + * 1.247 + * @return ptr to last item in container 1.248 + */ 1.249 +void* nsDeque::Pop() { 1.250 + void* result=0; 1.251 + if (mSize>0) { 1.252 + --mSize; 1.253 + int32_t offset=modulus(mSize + mOrigin, mCapacity); 1.254 + result=mData[offset]; 1.255 + mData[offset]=0; 1.256 + if (!mSize) { 1.257 + mOrigin=0; 1.258 + } 1.259 + } 1.260 + return result; 1.261 +} 1.262 + 1.263 +/** 1.264 + * This method gets called you want to remove and return 1.265 + * the first member in the container. 1.266 + * 1.267 + * @return last item in container 1.268 + */ 1.269 +void* nsDeque::PopFront() { 1.270 + void* result=0; 1.271 + if (mSize>0) { 1.272 + NS_ASSERTION(mOrigin < mCapacity, "Error: Bad origin"); 1.273 + result=mData[mOrigin]; 1.274 + mData[mOrigin++]=0; //zero it out for debugging purposes. 1.275 + mSize--; 1.276 + // Cycle around if we pop off the end 1.277 + // and reset origin if when we pop the last element 1.278 + if (mCapacity==mOrigin || !mSize) { 1.279 + mOrigin=0; 1.280 + } 1.281 + } 1.282 + return result; 1.283 +} 1.284 + 1.285 +/** 1.286 + * This method gets called you want to peek at the bottom 1.287 + * member without removing it. 1.288 + * 1.289 + * @return last item in container 1.290 + */ 1.291 +void* nsDeque::Peek() { 1.292 + void* result=0; 1.293 + if (mSize>0) { 1.294 + result = mData[modulus(mSize - 1 + mOrigin, mCapacity)]; 1.295 + } 1.296 + return result; 1.297 +} 1.298 + 1.299 +/** 1.300 + * This method gets called you want to peek at the topmost 1.301 + * member without removing it. 1.302 + * 1.303 + * @return last item in container 1.304 + */ 1.305 +void* nsDeque::PeekFront() { 1.306 + void* result=0; 1.307 + if (mSize>0) { 1.308 + result=mData[mOrigin]; 1.309 + } 1.310 + return result; 1.311 +} 1.312 + 1.313 +/** 1.314 + * Call this to retrieve the ith element from this container. 1.315 + * Keep in mind that accessing the underlying elements is 1.316 + * done in a relative fashion. Object 0 is not necessarily 1.317 + * the first element (the first element is at mOrigin). 1.318 + * 1.319 + * @param aIndex : 0 relative offset of item you want 1.320 + * @return void* or null 1.321 + */ 1.322 +void* nsDeque::ObjectAt(int32_t aIndex) const { 1.323 + void* result=0; 1.324 + if ((aIndex>=0) && (aIndex<mSize)) { 1.325 + result=mData[modulus(mOrigin + aIndex, mCapacity)]; 1.326 + } 1.327 + return result; 1.328 +} 1.329 + 1.330 +void* nsDeque::RemoveObjectAt(int32_t aIndex) { 1.331 + if ((aIndex<0) || (aIndex>=mSize)) { 1.332 + return 0; 1.333 + } 1.334 + void* result=mData[modulus(mOrigin + aIndex, mCapacity)]; 1.335 + 1.336 + // "Shuffle down" all elements in the array by 1, overwritting the element 1.337 + // being removed. 1.338 + for (int32_t i=aIndex; i<mSize; i++) { 1.339 + mData[modulus(mOrigin + i, mCapacity)] = mData[modulus(mOrigin + i + 1, mCapacity)]; 1.340 + } 1.341 + mSize--; 1.342 + 1.343 + return result; 1.344 +} 1.345 + 1.346 +/** 1.347 + * Create and return an iterator pointing to 1.348 + * the beginning of the queue. Note that this 1.349 + * takes the circular buffer semantics into account. 1.350 + * 1.351 + * @return new deque iterator, init'ed to 1st item 1.352 + */ 1.353 +nsDequeIterator nsDeque::Begin() const{ 1.354 + return nsDequeIterator(*this, 0); 1.355 +} 1.356 + 1.357 +/** 1.358 + * Create and return an iterator pointing to 1.359 + * the last item in the deque. 1.360 + * Note that this takes the circular buffer semantics 1.361 + * into account. 1.362 + * 1.363 + * @return new deque iterator, init'ed to the last item 1.364 + */ 1.365 +nsDequeIterator nsDeque::End() const{ 1.366 + return nsDequeIterator(*this, mSize - 1); 1.367 +} 1.368 + 1.369 +void* nsDeque::Last() const { 1.370 + return End().GetCurrent(); 1.371 +} 1.372 + 1.373 +/** 1.374 + * Call this method when you want to iterate all the 1.375 + * members of the container, passing a functor along 1.376 + * to call your code. 1.377 + * 1.378 + * @param aFunctor object to call for each member 1.379 + * @return *this 1.380 + */ 1.381 +void nsDeque::ForEach(nsDequeFunctor& aFunctor) const{ 1.382 + for (int32_t i=0; i<mSize; i++) { 1.383 + aFunctor(ObjectAt(i)); 1.384 + } 1.385 +} 1.386 + 1.387 +/** 1.388 + * Call this method when you want to iterate all the 1.389 + * members of the container, calling the functor you 1.390 + * passed with each member. This process will interrupt 1.391 + * if your function returns non 0 to this method. 1.392 + * 1.393 + * @param aFunctor object to call for each member 1.394 + * @return first nonzero result of aFunctor or 0. 1.395 + */ 1.396 +const void* nsDeque::FirstThat(nsDequeFunctor& aFunctor) const{ 1.397 + for (int32_t i=0; i<mSize; i++) { 1.398 + void* obj=aFunctor(ObjectAt(i)); 1.399 + if (obj) { 1.400 + return obj; 1.401 + } 1.402 + } 1.403 + return 0; 1.404 +} 1.405 + 1.406 +/****************************************************** 1.407 + * Here comes the nsDequeIterator class... 1.408 + ******************************************************/ 1.409 + 1.410 +/** 1.411 + * DequeIterator is an object that knows how to iterate (forward and backward) 1.412 + * through a Deque. Normally, you don't need to do this, but there are some special 1.413 + * cases where it is pretty handy, so here you go. 1.414 + * 1.415 + * This is a standard dequeiterator constructor 1.416 + * 1.417 + * @param aQueue is the deque object to be iterated 1.418 + * @param aIndex is the starting position for your iteration 1.419 + */ 1.420 +nsDequeIterator::nsDequeIterator(const nsDeque& aQueue, int aIndex) 1.421 +: mIndex(aIndex), 1.422 + mDeque(aQueue) 1.423 +{ 1.424 +} 1.425 + 1.426 +/** 1.427 + * Create a copy of a DequeIterator 1.428 + * 1.429 + * @param aCopy is another iterator to copy from 1.430 + */ 1.431 +nsDequeIterator::nsDequeIterator(const nsDequeIterator& aCopy) 1.432 +: mIndex(aCopy.mIndex), 1.433 + mDeque(aCopy.mDeque) 1.434 +{ 1.435 +} 1.436 + 1.437 +/** 1.438 + * Moves iterator to first element in deque 1.439 + * @return *this 1.440 + */ 1.441 +nsDequeIterator& nsDequeIterator::First(){ 1.442 + mIndex=0; 1.443 + return *this; 1.444 +} 1.445 + 1.446 +/** 1.447 + * Standard assignment operator for dequeiterator 1.448 + * 1.449 + * @param aCopy is an iterator to be copied from 1.450 + * @return *this 1.451 + */ 1.452 +nsDequeIterator& nsDequeIterator::operator=(const nsDequeIterator& aCopy) { 1.453 + NS_ASSERTION(&mDeque==&aCopy.mDeque,"you can't change the deque that an interator is iterating over, sorry."); 1.454 + mIndex=aCopy.mIndex; 1.455 + return *this; 1.456 +} 1.457 + 1.458 +/** 1.459 + * preform ! operation against to iterators to test for equivalence 1.460 + * (or lack thereof)! 1.461 + * 1.462 + * @param aIter is the object to be compared to 1.463 + * @return TRUE if NOT equal. 1.464 + */ 1.465 +bool nsDequeIterator::operator!=(nsDequeIterator& aIter) { 1.466 + return bool(!this->operator==(aIter)); 1.467 +} 1.468 + 1.469 +/** 1.470 + * Compare two iterators for increasing order. 1.471 + * 1.472 + * @param aIter is the other iterator to be compared to 1.473 + * @return TRUE if this object points to an element before 1.474 + * the element pointed to by aIter. 1.475 + * FALSE if this and aIter are not iterating over the same deque. 1.476 + */ 1.477 +bool nsDequeIterator::operator<(nsDequeIterator& aIter) { 1.478 + return bool(((mIndex<aIter.mIndex) && (&mDeque==&aIter.mDeque))); 1.479 +} 1.480 + 1.481 +/** 1.482 + * Compare two iterators for equivalence. 1.483 + * 1.484 + * @param aIter is the other iterator to be compared to 1.485 + * @return TRUE if EQUAL 1.486 + */ 1.487 +bool nsDequeIterator::operator==(nsDequeIterator& aIter) { 1.488 + return bool(((mIndex==aIter.mIndex) && (&mDeque==&aIter.mDeque))); 1.489 +} 1.490 + 1.491 +/** 1.492 + * Compare two iterators for non strict decreasing order. 1.493 + * 1.494 + * @param aIter is the other iterator to be compared to 1.495 + * @return TRUE if this object points to the same element, or 1.496 + * an element after the element pointed to by aIter. 1.497 + * FALSE if this and aIter are not iterating over the same deque. 1.498 + */ 1.499 +bool nsDequeIterator::operator>=(nsDequeIterator& aIter) { 1.500 + return bool(((mIndex>=aIter.mIndex) && (&mDeque==&aIter.mDeque))); 1.501 +} 1.502 + 1.503 +/** 1.504 + * Pre-increment operator 1.505 + * 1.506 + * @return object at post-incremented index 1.507 + */ 1.508 +void* nsDequeIterator::operator++() { 1.509 + NS_ASSERTION(mIndex<mDeque.mSize, 1.510 + "You have reached the end of the Internet."\ 1.511 + "You have seen everything there is to see. Please go back. Now." 1.512 + ); 1.513 +#ifndef TIMELESS_LIGHTWEIGHT 1.514 + if (mIndex>=mDeque.mSize) return 0; 1.515 +#endif 1.516 + return mDeque.ObjectAt(++mIndex); 1.517 +} 1.518 + 1.519 +/** 1.520 + * Post-increment operator 1.521 + * 1.522 + * @param param is ignored 1.523 + * @return object at pre-incremented index 1.524 + */ 1.525 +void* nsDequeIterator::operator++(int) { 1.526 + NS_ASSERTION(mIndex<=mDeque.mSize, 1.527 + "You have already reached the end of the Internet."\ 1.528 + "You have seen everything there is to see. Please go back. Now." 1.529 + ); 1.530 +#ifndef TIMELESS_LIGHTWEIGHT 1.531 + if (mIndex>mDeque.mSize) return 0; 1.532 +#endif 1.533 + return mDeque.ObjectAt(mIndex++); 1.534 +} 1.535 + 1.536 +/** 1.537 + * Pre-decrement operator 1.538 + * 1.539 + * @return object at pre-decremented index 1.540 + */ 1.541 +void* nsDequeIterator::operator--() { 1.542 + NS_ASSERTION(mIndex>=0, 1.543 + "You have reached the beginning of the Internet."\ 1.544 + "You have seen everything there is to see. Please go forward. Now." 1.545 + ); 1.546 +#ifndef TIMELESS_LIGHTWEIGHT 1.547 + if (mIndex<0) return 0; 1.548 +#endif 1.549 + return mDeque.ObjectAt(--mIndex); 1.550 +} 1.551 + 1.552 +/** 1.553 + * Post-decrement operator 1.554 + * 1.555 + * @param param is ignored 1.556 + * @return object at post-decremented index 1.557 + */ 1.558 +void* nsDequeIterator::operator--(int) { 1.559 + NS_ASSERTION(mIndex>=0, 1.560 + "You have already reached the beginning of the Internet."\ 1.561 + "You have seen everything there is to see. Please go forward. Now." 1.562 + ); 1.563 +#ifndef TIMELESS_LIGHTWEIGHT 1.564 + if (mIndex<0) return 0; 1.565 +#endif 1.566 + return mDeque.ObjectAt(mIndex--); 1.567 +} 1.568 + 1.569 +/** 1.570 + * Dereference operator 1.571 + * Note that the iterator floats, so you don't need to do: 1.572 + * <code>++iter; aDeque.PopFront();</code> 1.573 + * Unless you actually want your iterator to jump 2 spaces. 1.574 + * 1.575 + * Picture: [1 2I 3 4] 1.576 + * PopFront() 1.577 + * Picture: [2 3I 4] 1.578 + * Note that I still happily points to object at the second index 1.579 + * 1.580 + * @return object at ith index 1.581 + */ 1.582 +void* nsDequeIterator::GetCurrent() { 1.583 + NS_ASSERTION(mIndex<mDeque.mSize&&mIndex>=0,"Current is out of bounds"); 1.584 +#ifndef TIMELESS_LIGHTWEIGHT 1.585 + if (mIndex>=mDeque.mSize||mIndex<0) return 0; 1.586 +#endif 1.587 + return mDeque.ObjectAt(mIndex); 1.588 +} 1.589 + 1.590 +/** 1.591 + * Call this method when you want to iterate all the 1.592 + * members of the container, passing a functor along 1.593 + * to call your code. 1.594 + * 1.595 + * @param aFunctor object to call for each member 1.596 + * @return *this 1.597 + */ 1.598 +void nsDequeIterator::ForEach(nsDequeFunctor& aFunctor) const{ 1.599 + mDeque.ForEach(aFunctor); 1.600 +} 1.601 + 1.602 +/** 1.603 + * Call this method when you want to iterate all the 1.604 + * members of the container, calling the functor you 1.605 + * passed with each member. This process will interrupt 1.606 + * if your function returns non 0 to this method. 1.607 + * 1.608 + * @param aFunctor object to call for each member 1.609 + * @return first nonzero result of aFunctor or 0. 1.610 + */ 1.611 +const void* nsDequeIterator::FirstThat(nsDequeFunctor& aFunctor) const{ 1.612 + return mDeque.FirstThat(aFunctor); 1.613 +}