1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include "nsDeque.h"
39 : #include "nsCRT.h"
40 : #ifdef DEBUG_rickg
41 : #include <stdio.h>
42 : #endif
43 :
44 : /**
45 : * 07/02/2001 09:17p 509,104 clangref.pdf from openwatcom's site
46 : * Watcom C Language Reference Edition 11.0c
47 : * page 118 of 297
48 : *
49 : * The % symbol yields the remainder from the division of the first operand
50 : * by the second operand. The operands of % must have integral type.
51 : *
52 : * When both operands of % are positive, the result is a positive value
53 : * smaller than the second operand. When one or both operands is negative,
54 : * whether the result is positive or negative is implementation-defined.
55 : *
56 : */
57 : /* Ok, so first of all, C is underspecified. joy.
58 : * The following functions do not provide a correct implementation of modulus
59 : * They provide functionality for x>-y.
60 : * There are risks of 2*y being greater than max int, which is part of the
61 : * reason no multiplication is used and other operations are avoided.
62 : *
63 : * modasgn
64 : * @param x variable
65 : * @param y expression
66 : * approximately equivalent to x %= y
67 : *
68 : * modulus
69 : * @param x expression
70 : * @param y expression
71 : * approximately equivalent to x % y
72 : */
73 : #define modasgn(x,y) if (x<0) x+=y; x%=y
74 : #define modulus(x,y) ((x<0)?(x+y)%(y):(x)%(y))
75 :
76 : /**
77 : * Standard constructor
78 : * @param deallocator, called by Erase and ~nsDeque
79 : */
80 19016 : nsDeque::nsDeque(nsDequeFunctor* aDeallocator) {
81 19016 : MOZ_COUNT_CTOR(nsDeque);
82 19016 : mDeallocator=aDeallocator;
83 19016 : mOrigin=mSize=0;
84 19016 : mData=mBuffer; // don't allocate space until you must
85 19016 : mCapacity=sizeof(mBuffer)/sizeof(mBuffer[0]);
86 19016 : memset(mData, 0, mCapacity*sizeof(mBuffer[0]));
87 19016 : }
88 :
89 : /**
90 : * Destructor
91 : */
92 19016 : nsDeque::~nsDeque() {
93 19016 : MOZ_COUNT_DTOR(nsDeque);
94 :
95 : #ifdef DEBUG_rickg
96 : char buffer[30];
97 : printf("Capacity: %i\n", mCapacity);
98 :
99 : static int mCaps[15] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
100 : switch(mCapacity) {
101 : case 4: mCaps[0]++; break;
102 : case 8: mCaps[1]++; break;
103 : case 16: mCaps[2]++; break;
104 : case 32: mCaps[3]++; break;
105 : case 64: mCaps[4]++; break;
106 : case 128: mCaps[5]++; break;
107 : case 256: mCaps[6]++; break;
108 : case 512: mCaps[7]++; break;
109 : case 1024: mCaps[8]++; break;
110 : case 2048: mCaps[9]++; break;
111 : case 4096: mCaps[10]++; break;
112 : default:
113 : break;
114 : }
115 : #endif
116 :
117 19016 : Erase();
118 19016 : if (mData && (mData!=mBuffer)) {
119 4533 : free(mData);
120 : }
121 19016 : mData=0;
122 19016 : SetDeallocator(0);
123 19016 : }
124 :
125 : /**
126 : * Set the functor to be called by Erase()
127 : * The deque owns the functor.
128 : *
129 : * @param aDeallocator functor object for use by Erase()
130 : */
131 19016 : void nsDeque::SetDeallocator(nsDequeFunctor* aDeallocator){
132 19016 : delete mDeallocator;
133 19016 : mDeallocator=aDeallocator;
134 19016 : }
135 :
136 : /**
137 : * Remove all items from container without destroying them.
138 : *
139 : * @return *this
140 : */
141 19016 : nsDeque& nsDeque::Empty() {
142 19016 : if (mSize && mData) {
143 25 : memset(mData, 0, mCapacity*sizeof(mData));
144 : }
145 19016 : mSize=0;
146 19016 : mOrigin=0;
147 19016 : return *this;
148 : }
149 :
150 : /**
151 : * Remove and delete all items from container
152 : *
153 : * @return *this
154 : */
155 19016 : nsDeque& nsDeque::Erase() {
156 19016 : if (mDeallocator && mSize) {
157 0 : ForEach(*mDeallocator);
158 : }
159 19016 : return Empty();
160 : }
161 :
162 : /**
163 : * This method quadruples the size of the deque
164 : * Elements in the deque are resequenced so that elements
165 : * in the deque are stored sequentially
166 : *
167 : * If the deque actually overflows, there's very little we can do.
168 : * Perhaps this function should return bool/nsresult indicating success/failure.
169 : *
170 : * @return whether growing succeeded
171 : */
172 9683 : bool nsDeque::GrowCapacity() {
173 9683 : PRInt32 theNewSize=mCapacity<<2;
174 9683 : NS_ASSERTION(theNewSize>mCapacity, "Overflow");
175 9683 : if (theNewSize<=mCapacity)
176 0 : return false;
177 9683 : void** temp=(void**)malloc(theNewSize * sizeof(void*));
178 9683 : if (!temp)
179 0 : return false;
180 :
181 : //Here's the interesting part: You can't just move the elements
182 : //directly (in situ) from the old buffer to the new one.
183 : //Since capacity has changed, the old origin doesn't make
184 : //sense anymore. It's better to resequence the elements now.
185 :
186 9683 : memcpy(temp, mData + mOrigin, sizeof(void*) * (mCapacity - mOrigin));
187 9683 : memcpy(temp + (mCapacity - mOrigin), mData, sizeof(void*) * mOrigin);
188 :
189 9683 : if (mData != mBuffer) {
190 5150 : free(mData);
191 : }
192 :
193 9683 : mCapacity=theNewSize;
194 9683 : mOrigin=0; //now realign the origin...
195 9683 : mData=temp;
196 :
197 9683 : return true;
198 : }
199 :
200 : /**
201 : * This method adds an item to the end of the deque.
202 : * This operation has the potential to cause the
203 : * underlying buffer to resize.
204 : *
205 : * @param aItem: new item to be added to deque
206 : * @return *this
207 : */
208 1901445 : nsDeque& nsDeque::Push(void* aItem) {
209 1901445 : if (mSize==mCapacity && !GrowCapacity()) {
210 0 : NS_WARNING("out of memory");
211 0 : return *this;
212 : }
213 1901445 : mData[modulus(mOrigin + mSize, mCapacity)]=aItem;
214 1901445 : mSize++;
215 1901445 : return *this;
216 : }
217 :
218 : /**
219 : * This method adds an item to the front of the deque.
220 : * This operation has the potential to cause the
221 : * underlying buffer to resize.
222 : *
223 : * --Commments for GrowCapacity() case
224 : * We've grown and shifted which means that the old
225 : * final element in the deque is now the first element
226 : * in the deque. This is temporary.
227 : * We haven't inserted the new element at the front.
228 : *
229 : * To continue with the idea of having the front at zero
230 : * after a grow, we move the old final item (which through
231 : * the voodoo of mOrigin-- is now the first) to its final
232 : * position which is conveniently the old length.
233 : *
234 : * Note that this case only happens when the deque is full.
235 : * [And that pieces of this magic only work if the deque is full.]
236 : * picture:
237 : * [ABCDEFGH] @[mOrigin:3]:D.
238 : * Task: PushFront("Z")
239 : * shift mOrigin so, @[mOrigin:2]:C
240 : * stretch and rearrange: (mOrigin:0)
241 : * [CDEFGHAB ________ ________ ________]
242 : * copy: (The second C is currently out of bounds)
243 : * [CDEFGHAB C_______ ________ ________]
244 : * later we will insert Z:
245 : * [ZDEFGHAB C_______ ________ ________]
246 : * and increment size: 9. (C is no longer out of bounds)
247 : * --
248 : * @param aItem: new item to be added to deque
249 : * @return *this
250 : */
251 85 : nsDeque& nsDeque::PushFront(void* aItem) {
252 85 : mOrigin--;
253 85 : modasgn(mOrigin,mCapacity);
254 85 : if (mSize==mCapacity) {
255 0 : if (!GrowCapacity()) {
256 0 : NS_WARNING("out of memory");
257 0 : return *this;
258 : }
259 : /* Comments explaining this are above*/
260 0 : mData[mSize]=mData[mOrigin];
261 : }
262 85 : mData[mOrigin]=aItem;
263 85 : mSize++;
264 85 : return *this;
265 : }
266 :
267 : /**
268 : * Remove and return the last item in the container.
269 : *
270 : * @return ptr to last item in container
271 : */
272 20179 : void* nsDeque::Pop() {
273 20179 : void* result=0;
274 20179 : if (mSize>0) {
275 17539 : --mSize;
276 17539 : PRInt32 offset=modulus(mSize + mOrigin, mCapacity);
277 17539 : result=mData[offset];
278 17539 : mData[offset]=0;
279 17539 : if (!mSize) {
280 4755 : mOrigin=0;
281 : }
282 : }
283 20179 : return result;
284 : }
285 :
286 : /**
287 : * This method gets called you want to remove and return
288 : * the first member in the container.
289 : *
290 : * @return last item in container
291 : */
292 1885349 : void* nsDeque::PopFront() {
293 1885349 : void* result=0;
294 1885349 : if (mSize>0) {
295 1883566 : NS_ASSERTION(mOrigin < mCapacity, "Error: Bad origin");
296 1883566 : result=mData[mOrigin];
297 1883566 : mData[mOrigin++]=0; //zero it out for debugging purposes.
298 1883566 : mSize--;
299 : // Cycle around if we pop off the end
300 : // and reset origin if when we pop the last element
301 1883566 : if (mCapacity==mOrigin || !mSize) {
302 36955 : mOrigin=0;
303 : }
304 : }
305 1885349 : return result;
306 : }
307 :
308 : /**
309 : * This method gets called you want to peek at the bottom
310 : * member without removing it.
311 : *
312 : * @return last item in container
313 : */
314 319 : void* nsDeque::Peek() {
315 319 : void* result=0;
316 319 : if (mSize>0) {
317 319 : result = mData[modulus(mSize - 1 + mOrigin, mCapacity)];
318 : }
319 319 : return result;
320 : }
321 :
322 : /**
323 : * This method gets called you want to peek at the topmost
324 : * member without removing it.
325 : *
326 : * @return last item in container
327 : */
328 0 : void* nsDeque::PeekFront() {
329 0 : void* result=0;
330 0 : if (mSize>0) {
331 0 : result=mData[mOrigin];
332 : }
333 0 : return result;
334 : }
335 :
336 : /**
337 : * Call this to retrieve the ith element from this container.
338 : * Keep in mind that accessing the underlying elements is
339 : * done in a relative fashion. Object 0 is not necessarily
340 : * the first element (the first element is at mOrigin).
341 : *
342 : * @param aIndex : 0 relative offset of item you want
343 : * @return void* or null
344 : */
345 23227 : void* nsDeque::ObjectAt(PRInt32 aIndex) const {
346 23227 : void* result=0;
347 23227 : if ((aIndex>=0) && (aIndex<mSize)) {
348 23199 : result=mData[modulus(mOrigin + aIndex, mCapacity)];
349 : }
350 23227 : return result;
351 : }
352 :
353 0 : void* nsDeque::RemoveObjectAt(PRInt32 aIndex) {
354 0 : if ((aIndex<0) || (aIndex>=mSize)) {
355 0 : return 0;
356 : }
357 0 : void* result=mData[modulus(mOrigin + aIndex, mCapacity)];
358 :
359 : // "Shuffle down" all elements in the array by 1, overwritting the element
360 : // being removed.
361 0 : for (PRInt32 i=aIndex; i<mSize; i++) {
362 0 : mData[modulus(mOrigin + i, mCapacity)] = mData[modulus(mOrigin + i + 1, mCapacity)];
363 : }
364 0 : mSize--;
365 :
366 0 : return result;
367 : }
368 :
369 : /**
370 : * Create and return an iterator pointing to
371 : * the beginning of the queue. Note that this
372 : * takes the circular buffer semantics into account.
373 : *
374 : * @return new deque iterator, init'ed to 1st item
375 : */
376 0 : nsDequeIterator nsDeque::Begin() const{
377 0 : return nsDequeIterator(*this, 0);
378 : }
379 :
380 : /**
381 : * Create and return an iterator pointing to
382 : * the last item in the deque.
383 : * Note that this takes the circular buffer semantics
384 : * into account.
385 : *
386 : * @return new deque iterator, init'ed to the last item
387 : */
388 14574 : nsDequeIterator nsDeque::End() const{
389 14574 : return nsDequeIterator(*this, mSize - 1);
390 : }
391 :
392 14364 : void* nsDeque::Last() const {
393 14364 : return End().GetCurrent();
394 : }
395 :
396 : /**
397 : * Call this method when you want to iterate all the
398 : * members of the container, passing a functor along
399 : * to call your code.
400 : *
401 : * @param aFunctor object to call for each member
402 : * @return *this
403 : */
404 0 : void nsDeque::ForEach(nsDequeFunctor& aFunctor) const{
405 0 : for (PRInt32 i=0; i<mSize; i++) {
406 0 : aFunctor(ObjectAt(i));
407 : }
408 0 : }
409 :
410 : /**
411 : * Call this method when you want to iterate all the
412 : * members of the container, calling the functor you
413 : * passed with each member. This process will interrupt
414 : * if your function returns non 0 to this method.
415 : *
416 : * @param aFunctor object to call for each member
417 : * @return first nonzero result of aFunctor or 0.
418 : */
419 0 : const void* nsDeque::FirstThat(nsDequeFunctor& aFunctor) const{
420 0 : for (PRInt32 i=0; i<mSize; i++) {
421 0 : void* obj=aFunctor(ObjectAt(i));
422 0 : if (obj) {
423 0 : return obj;
424 : }
425 : }
426 0 : return 0;
427 : }
428 :
429 : /******************************************************
430 : * Here comes the nsDequeIterator class...
431 : ******************************************************/
432 :
433 : /**
434 : * DequeIterator is an object that knows how to iterate (forward and backward)
435 : * through a Deque. Normally, you don't need to do this, but there are some special
436 : * cases where it is pretty handy, so here you go.
437 : *
438 : * This is a standard dequeiterator constructor
439 : *
440 : * @param aQueue is the deque object to be iterated
441 : * @param aIndex is the starting position for your iteration
442 : */
443 14784 : nsDequeIterator::nsDequeIterator(const nsDeque& aQueue, int aIndex)
444 : : mIndex(aIndex),
445 14784 : mDeque(aQueue)
446 : {
447 14784 : }
448 :
449 : /**
450 : * Create a copy of a DequeIterator
451 : *
452 : * @param aCopy is another iterator to copy from
453 : */
454 0 : nsDequeIterator::nsDequeIterator(const nsDequeIterator& aCopy)
455 : : mIndex(aCopy.mIndex),
456 0 : mDeque(aCopy.mDeque)
457 : {
458 0 : }
459 :
460 : /**
461 : * Moves iterator to first element in deque
462 : * @return *this
463 : */
464 0 : nsDequeIterator& nsDequeIterator::First(){
465 0 : mIndex=0;
466 0 : return *this;
467 : }
468 :
469 : /**
470 : * Standard assignment operator for dequeiterator
471 : *
472 : * @param aCopy is an iterator to be copied from
473 : * @return *this
474 : */
475 0 : nsDequeIterator& nsDequeIterator::operator=(const nsDequeIterator& aCopy) {
476 0 : NS_ASSERTION(&mDeque==&aCopy.mDeque,"you can't change the deque that an interator is iterating over, sorry.");
477 0 : mIndex=aCopy.mIndex;
478 0 : return *this;
479 : }
480 :
481 : /**
482 : * preform ! operation against to iterators to test for equivalence
483 : * (or lack thereof)!
484 : *
485 : * @param aIter is the object to be compared to
486 : * @return TRUE if NOT equal.
487 : */
488 0 : bool nsDequeIterator::operator!=(nsDequeIterator& aIter) {
489 0 : return bool(!this->operator==(aIter));
490 : }
491 :
492 : /**
493 : * Compare two iterators for increasing order.
494 : *
495 : * @param aIter is the other iterator to be compared to
496 : * @return TRUE if this object points to an element before
497 : * the element pointed to by aIter.
498 : * FALSE if this and aIter are not iterating over the same deque.
499 : */
500 501 : bool nsDequeIterator::operator<(nsDequeIterator& aIter) {
501 501 : return bool(((mIndex<aIter.mIndex) && (&mDeque==&aIter.mDeque)));
502 : }
503 :
504 : /**
505 : * Compare two iterators for equivalence.
506 : *
507 : * @param aIter is the other iterator to be compared to
508 : * @return TRUE if EQUAL
509 : */
510 0 : bool nsDequeIterator::operator==(nsDequeIterator& aIter) {
511 0 : return bool(((mIndex==aIter.mIndex) && (&mDeque==&aIter.mDeque)));
512 : }
513 :
514 : /**
515 : * Compare two iterators for non strict decreasing order.
516 : *
517 : * @param aIter is the other iterator to be compared to
518 : * @return TRUE if this object points to the same element, or
519 : * an element after the element pointed to by aIter.
520 : * FALSE if this and aIter are not iterating over the same deque.
521 : */
522 0 : bool nsDequeIterator::operator>=(nsDequeIterator& aIter) {
523 0 : return bool(((mIndex>=aIter.mIndex) && (&mDeque==&aIter.mDeque)));
524 : }
525 :
526 : /**
527 : * Pre-increment operator
528 : *
529 : * @return object at post-incremented index
530 : */
531 0 : void* nsDequeIterator::operator++() {
532 0 : NS_ASSERTION(mIndex<mDeque.mSize,
533 : "You have reached the end of the Internet."\
534 : "You have seen everything there is to see. Please go back. Now."
535 : );
536 : #ifndef TIMELESS_LIGHTWEIGHT
537 0 : if (mIndex>=mDeque.mSize) return 0;
538 : #endif
539 0 : return mDeque.ObjectAt(++mIndex);
540 : }
541 :
542 : /**
543 : * Post-increment operator
544 : *
545 : * @param param is ignored
546 : * @return object at pre-incremented index
547 : */
548 291 : void* nsDequeIterator::operator++(int) {
549 291 : NS_ASSERTION(mIndex<=mDeque.mSize,
550 : "You have already reached the end of the Internet."\
551 : "You have seen everything there is to see. Please go back. Now."
552 : );
553 : #ifndef TIMELESS_LIGHTWEIGHT
554 291 : if (mIndex>mDeque.mSize) return 0;
555 : #endif
556 291 : return mDeque.ObjectAt(mIndex++);
557 : }
558 :
559 : /**
560 : * Pre-decrement operator
561 : *
562 : * @return object at pre-decremented index
563 : */
564 0 : void* nsDequeIterator::operator--() {
565 0 : NS_ASSERTION(mIndex>=0,
566 : "You have reached the beginning of the Internet."\
567 : "You have seen everything there is to see. Please go forward. Now."
568 : );
569 : #ifndef TIMELESS_LIGHTWEIGHT
570 0 : if (mIndex<0) return 0;
571 : #endif
572 0 : return mDeque.ObjectAt(--mIndex);
573 : }
574 :
575 : /**
576 : * Post-decrement operator
577 : *
578 : * @param param is ignored
579 : * @return object at post-decremented index
580 : */
581 0 : void* nsDequeIterator::operator--(int) {
582 0 : NS_ASSERTION(mIndex>=0,
583 : "You have already reached the beginning of the Internet."\
584 : "You have seen everything there is to see. Please go forward. Now."
585 : );
586 : #ifndef TIMELESS_LIGHTWEIGHT
587 0 : if (mIndex<0) return 0;
588 : #endif
589 0 : return mDeque.ObjectAt(mIndex--);
590 : }
591 :
592 : /**
593 : * Dereference operator
594 : * Note that the iterator floats, so you don't need to do:
595 : * <code>++iter; aDeque.PopFront();</code>
596 : * Unless you actually want your iterator to jump 2 spaces.
597 : *
598 : * Picture: [1 2I 3 4]
599 : * PopFront()
600 : * Picture: [2 3I 4]
601 : * Note that I still happily points to object at the second index
602 : *
603 : * @return object at ith index
604 : */
605 14364 : void* nsDequeIterator::GetCurrent() {
606 14364 : NS_ASSERTION(mIndex<mDeque.mSize&&mIndex>=0,"Current is out of bounds");
607 : #ifndef TIMELESS_LIGHTWEIGHT
608 14364 : if (mIndex>=mDeque.mSize||mIndex<0) return 0;
609 : #endif
610 14364 : return mDeque.ObjectAt(mIndex);
611 : }
612 :
613 : /**
614 : * Call this method when you want to iterate all the
615 : * members of the container, passing a functor along
616 : * to call your code.
617 : *
618 : * @param aFunctor object to call for each member
619 : * @return *this
620 : */
621 0 : void nsDequeIterator::ForEach(nsDequeFunctor& aFunctor) const{
622 0 : mDeque.ForEach(aFunctor);
623 0 : }
624 :
625 : /**
626 : * Call this method when you want to iterate all the
627 : * members of the container, calling the functor you
628 : * passed with each member. This process will interrupt
629 : * if your function returns non 0 to this method.
630 : *
631 : * @param aFunctor object to call for each member
632 : * @return first nonzero result of aFunctor or 0.
633 : */
634 0 : const void* nsDequeIterator::FirstThat(nsDequeFunctor& aFunctor) const{
635 0 : return mDeque.FirstThat(aFunctor);
636 : }
|