VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/xpcom/ds/nsDeque.cpp@ 4837

Last change on this file since 4837 was 1, checked in by vboxsync, 54 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.9 KB
Line 
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
76MOZ_DECL_CTOR_COUNTER(nsDeque)
77
78/**
79 * Standard constructor
80 * @param deallocator, called by Erase and ~nsDeque
81 */
82nsDeque::nsDeque(nsDequeFunctor* aDeallocator) {
83 MOZ_COUNT_CTOR(nsDeque);
84 mDeallocator=aDeallocator;
85 mOrigin=mSize=0;
86 mData=mBuffer; // don't allocate space until you must
87 mCapacity=sizeof(mBuffer)/sizeof(mBuffer[0]);
88 memset(mData, 0, mCapacity*sizeof(mBuffer[0]));
89}
90
91/**
92 * Destructor
93 */
94nsDeque::~nsDeque() {
95 MOZ_COUNT_DTOR(nsDeque);
96
97#ifdef DEBUG_rickg
98 char buffer[30];
99 printf("Capacity: %i\n", mCapacity);
100
101 static int mCaps[15] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
102 switch(mCapacity) {
103 case 4: mCaps[0]++; break;
104 case 8: mCaps[1]++; break;
105 case 16: mCaps[2]++; break;
106 case 32: mCaps[3]++; break;
107 case 64: mCaps[4]++; break;
108 case 128: mCaps[5]++; break;
109 case 256: mCaps[6]++; break;
110 case 512: mCaps[7]++; break;
111 case 1024: mCaps[8]++; break;
112 case 2048: mCaps[9]++; break;
113 case 4096: mCaps[10]++; break;
114 default:
115 break;
116 }
117#endif
118
119 Erase();
120 if (mData && (mData!=mBuffer)) {
121 delete [] mData;
122 }
123 mData=0;
124 SetDeallocator(0);
125}
126
127/**
128 * Set the functor to be called by Erase()
129 * The deque owns the functor.
130 *
131 * @param aDeallocator functor object for use by Erase()
132 */
133void nsDeque::SetDeallocator(nsDequeFunctor* aDeallocator){
134 if (mDeallocator) {
135 delete mDeallocator;
136 }
137 mDeallocator=aDeallocator;
138}
139
140/**
141 * Remove all items from container without destroying them.
142 *
143 * @return *this
144 */
145nsDeque& nsDeque::Empty() {
146 if (mSize && mData) {
147 memset(mData, 0, mCapacity*sizeof(mData));
148 }
149 mSize=0;
150 mOrigin=0;
151 return *this;
152}
153
154/**
155 * Remove and delete all items from container
156 *
157 * @return *this
158 */
159nsDeque& nsDeque::Erase() {
160 if (mDeallocator && mSize) {
161 ForEach(*mDeallocator);
162 }
163 return Empty();
164}
165
166/**
167 * This method quadruples the size of the deque
168 * Elements in the deque are resequenced so that elements
169 * in the deque are stored sequentially
170 *
171 * If the deque actually overflows, there's very little we can do.
172 * Perhaps this function should return PRBool/nsresult indicating success/failure.
173 *
174 * @return capacity of the deque
175 * If the deque did not grow,
176 * and you knew its capacity beforehand,
177 * then this would be a way to indicate the failure.
178 */
179PRInt32 nsDeque::GrowCapacity() {
180 PRInt32 theNewSize=mCapacity<<2;
181 NS_ASSERTION(theNewSize>mCapacity, "Overflow");
182 if (theNewSize<=mCapacity)
183 return mCapacity;
184 void** temp=new void*[theNewSize];
185
186 //Here's the interesting part: You can't just move the elements
187 //directly (in situ) from the old buffer to the new one.
188 //Since capacity has changed, the old origin doesn't make
189 //sense anymore. It's better to resequence the elements now.
190
191 if (temp) {
192 PRInt32 tempi=0;
193 PRInt32 i=0;
194 PRInt32 j=0;
195 for (i=mOrigin; i<mCapacity; i++) {
196 temp[tempi++]=mData[i]; //copy the leading elements...
197 }
198 for (j=0;j<mOrigin;j++) {
199 temp[tempi++]=mData[j]; //copy the trailing elements...
200 }
201 if (mData != mBuffer) {
202 delete [] mData;
203 }
204 mCapacity=theNewSize;
205 mOrigin=0; //now realign the origin...
206 mData=temp;
207 }
208 return mCapacity;
209}
210
211/**
212 * This method adds an item to the end of the deque.
213 * This operation has the potential to cause the
214 * underlying buffer to resize.
215 *
216 * @param aItem: new item to be added to deque
217 * @return *this
218 */
219nsDeque& nsDeque::Push(void* aItem) {
220 if (mSize==mCapacity) {
221 GrowCapacity();
222 }
223 mData[modulus(mOrigin + mSize, mCapacity)]=aItem;
224 mSize++;
225 return *this;
226}
227
228/**
229 * This method adds an item to the front of the deque.
230 * This operation has the potential to cause the
231 * underlying buffer to resize.
232 *
233 * --Commments for GrowCapacity() case
234 * We've grown and shifted which means that the old
235 * final element in the deque is now the first element
236 * in the deque. This is temporary.
237 * We haven't inserted the new element at the front.
238 *
239 * To continue with the idea of having the front at zero
240 * after a grow, we move the old final item (which through
241 * the voodoo of mOrigin-- is now the first) to its final
242 * position which is conveniently the old length.
243 *
244 * Note that this case only happens when the deque is full.
245 * [And that pieces of this magic only work if the deque is full.]
246 * picture:
247 * [ABCDEFGH] @[mOrigin:3]:D.
248 * Task: PushFront("Z")
249 * shift mOrigin so, @[mOrigin:2]:C
250 * stretch and rearrange: (mOrigin:0)
251 * [CDEFGHAB ________ ________ ________]
252 * copy: (The second C is currently out of bounds)
253 * [CDEFGHAB C_______ ________ ________]
254 * later we will insert Z:
255 * [ZDEFGHAB C_______ ________ ________]
256 * and increment size: 9. (C is no longer out of bounds)
257 * --
258 * @param aItem: new item to be added to deque
259 * @return *this
260 */
261nsDeque& nsDeque::PushFront(void* aItem) {
262 mOrigin--;
263 modasgn(mOrigin,mCapacity);
264 if (mSize==mCapacity) {
265 GrowCapacity();
266 /* Comments explaining this are above*/
267 mData[mSize]=mData[mOrigin];
268 }
269 mData[mOrigin]=aItem;
270 mSize++;
271 return *this;
272}
273
274/**
275 * Remove and return the last item in the container.
276 *
277 * @return ptr to last item in container
278 */
279void* nsDeque::Pop() {
280 void* result=0;
281 if (mSize>0) {
282 --mSize;
283 PRInt32 offset=modulus(mSize + mOrigin, mCapacity);
284 result=mData[offset];
285 mData[offset]=0;
286 if (!mSize) {
287 mOrigin=0;
288 }
289 }
290 return result;
291}
292
293/**
294 * This method gets called you want to remove and return
295 * the first member in the container.
296 *
297 * @return last item in container
298 */
299void* nsDeque::PopFront() {
300 void* result=0;
301 if (mSize>0) {
302 NS_ASSERTION(mOrigin < mCapacity, "Error: Bad origin");
303 result=mData[mOrigin];
304 mData[mOrigin++]=0; //zero it out for debugging purposes.
305 mSize--;
306 // Cycle around if we pop off the end
307 // and reset origin if when we pop the last element
308 if (mCapacity==mOrigin || !mSize) {
309 mOrigin=0;
310 }
311 }
312 return result;
313}
314
315/**
316 * This method gets called you want to peek at the bottom
317 * member without removing it.
318 *
319 * @return last item in container
320 */
321void* nsDeque::Peek() {
322 void* result=0;
323 if (mSize>0) {
324 result = mData[modulus(mSize - 1 + mOrigin, mCapacity)];
325 }
326 return result;
327}
328
329/**
330 * This method gets called you want to peek at the topmost
331 * member without removing it.
332 *
333 * @return last item in container
334 */
335void* nsDeque::PeekFront() {
336 void* result=0;
337 if (mSize>0) {
338 result=mData[mOrigin];
339 }
340 return result;
341}
342
343/**
344 * Call this to retrieve the ith element from this container.
345 * Keep in mind that accessing the underlying elements is
346 * done in a relative fashion. Object 0 is not necessarily
347 * the first element (the first element is at mOrigin).
348 *
349 * @param aIndex : 0 relative offset of item you want
350 * @return void* or null
351 */
352void* nsDeque::ObjectAt(PRInt32 aIndex) const {
353 void* result=0;
354 if ((aIndex>=0) && (aIndex<mSize)) {
355 result=mData[modulus(mOrigin + aIndex, mCapacity)];
356 }
357 return result;
358}
359
360/**
361 * Create and return an iterator pointing to
362 * the beginning of the queue. Note that this
363 * takes the circular buffer semantics into account.
364 *
365 * @return new deque iterator, init'ed to 1st item
366 */
367nsDequeIterator nsDeque::Begin() const{
368 return nsDequeIterator(*this, 0);
369}
370
371/**
372 * Create and return an iterator pointing to
373 * the last item in the deque.
374 * Note that this takes the circular buffer semantics
375 * into account.
376 *
377 * @return new deque iterator, init'ed to the last item
378 */
379nsDequeIterator nsDeque::End() const{
380 return nsDequeIterator(*this, mSize - 1);
381}
382
383void* nsDeque::Last() const {
384 return End().GetCurrent();
385}
386
387/**
388 * Call this method when you want to iterate all the
389 * members of the container, passing a functor along
390 * to call your code.
391 *
392 * @param aFunctor object to call for each member
393 * @return *this
394 */
395void nsDeque::ForEach(nsDequeFunctor& aFunctor) const{
396 for (PRInt32 i=0; i<mSize; i++) {
397 aFunctor(ObjectAt(i));
398 }
399}
400
401/**
402 * Call this method when you want to iterate all the
403 * members of the container, calling the functor you
404 * passed with each member. This process will interrupt
405 * if your function returns non 0 to this method.
406 *
407 * @param aFunctor object to call for each member
408 * @return first nonzero result of aFunctor or 0.
409 */
410const void* nsDeque::FirstThat(nsDequeFunctor& aFunctor) const{
411 for (PRInt32 i=0; i<mSize; i++) {
412 void* obj=aFunctor(ObjectAt(i));
413 if (obj) {
414 return obj;
415 }
416 }
417 return 0;
418}
419
420/******************************************************
421 * Here comes the nsDequeIterator class...
422 ******************************************************/
423
424/**
425 * DequeIterator is an object that knows how to iterate (forward and backward)
426 * through a Deque. Normally, you don't need to do this, but there are some special
427 * cases where it is pretty handy, so here you go.
428 *
429 * This is a standard dequeiterator constructor
430 *
431 * @param aQueue is the deque object to be iterated
432 * @param aIndex is the starting position for your iteration
433 */
434nsDequeIterator::nsDequeIterator(const nsDeque& aQueue, int aIndex)
435: mIndex(aIndex),
436 mDeque(aQueue)
437{
438}
439
440/**
441 * Create a copy of a DequeIterator
442 *
443 * @param aCopy is another iterator to copy from
444 */
445nsDequeIterator::nsDequeIterator(const nsDequeIterator& aCopy)
446: mIndex(aCopy.mIndex),
447 mDeque(aCopy.mDeque)
448{
449}
450
451/**
452 * Moves iterator to first element in deque
453 * @return *this
454 */
455nsDequeIterator& nsDequeIterator::First(){
456 mIndex=0;
457 return *this;
458}
459
460/**
461 * Standard assignment operator for dequeiterator
462 *
463 * @param aCopy is an iterator to be copied from
464 * @return *this
465 */
466nsDequeIterator& nsDequeIterator::operator=(const nsDequeIterator& aCopy) {
467 NS_ASSERTION(&mDeque==&aCopy.mDeque,"you can't change the deque that an interator is iterating over, sorry.");
468 mIndex=aCopy.mIndex;
469 return *this;
470}
471
472/**
473 * preform ! operation against to iterators to test for equivalence
474 * (or lack thereof)!
475 *
476 * @param aIter is the object to be compared to
477 * @return TRUE if NOT equal.
478 */
479PRBool nsDequeIterator::operator!=(nsDequeIterator& aIter) {
480 return PRBool(!this->operator==(aIter));
481}
482
483/**
484 * Compare two iterators for increasing order.
485 *
486 * @param aIter is the other iterator to be compared to
487 * @return TRUE if this object points to an element before
488 * the element pointed to by aIter.
489 * FALSE if this and aIter are not iterating over the same deque.
490 */
491PRBool nsDequeIterator::operator<(nsDequeIterator& aIter) {
492 return PRBool(((mIndex<aIter.mIndex) && (&mDeque==&aIter.mDeque)));
493}
494
495/**
496 * Compare two iterators for equivalence.
497 *
498 * @param aIter is the other iterator to be compared to
499 * @return TRUE if EQUAL
500 */
501PRBool nsDequeIterator::operator==(nsDequeIterator& aIter) {
502 return PRBool(((mIndex==aIter.mIndex) && (&mDeque==&aIter.mDeque)));
503}
504
505/**
506 * Compare two iterators for non strict decreasing order.
507 *
508 * @param aIter is the other iterator to be compared to
509 * @return TRUE if this object points to the same element, or
510 * an element after the element pointed to by aIter.
511 * FALSE if this and aIter are not iterating over the same deque.
512 */
513PRBool nsDequeIterator::operator>=(nsDequeIterator& aIter) {
514 return PRBool(((mIndex>=aIter.mIndex) && (&mDeque==&aIter.mDeque)));
515}
516
517/**
518 * Pre-increment operator
519 *
520 * @return object at post-incremented index
521 */
522void* nsDequeIterator::operator++() {
523 NS_ASSERTION(mIndex<mDeque.mSize,
524 "You have reached the end of the Internet."\
525 "You have seen everything there is to see. Please go back. Now."
526 );
527#ifndef TIMELESS_LIGHTWEIGHT
528 if (mIndex>=mDeque.mSize) return 0;
529#endif
530 return mDeque.ObjectAt(++mIndex);
531}
532
533/**
534 * Post-increment operator
535 *
536 * @param param is ignored
537 * @return object at pre-incremented index
538 */
539void* nsDequeIterator::operator++(int) {
540 NS_ASSERTION(mIndex<=mDeque.mSize,
541 "You have already reached the end of the Internet."\
542 "You have seen everything there is to see. Please go back. Now."
543 );
544#ifndef TIMELESS_LIGHTWEIGHT
545 if (mIndex>mDeque.mSize) return 0;
546#endif
547 return mDeque.ObjectAt(mIndex++);
548}
549
550/**
551 * Pre-decrement operator
552 *
553 * @return object at pre-decremented index
554 */
555void* nsDequeIterator::operator--() {
556 NS_ASSERTION(mIndex>=0,
557 "You have reached the beginning of the Internet."\
558 "You have seen everything there is to see. Please go forward. Now."
559 );
560#ifndef TIMELESS_LIGHTWEIGHT
561 if (mIndex<0) return 0;
562#endif
563 return mDeque.ObjectAt(--mIndex);
564}
565
566/**
567 * Post-decrement operator
568 *
569 * @param param is ignored
570 * @return object at post-decremented index
571 */
572void* nsDequeIterator::operator--(int) {
573 NS_ASSERTION(mIndex>=0,
574 "You have already reached the beginning of the Internet."\
575 "You have seen everything there is to see. Please go forward. Now."
576 );
577#ifndef TIMELESS_LIGHTWEIGHT
578 if (mIndex<0) return 0;
579#endif
580 return mDeque.ObjectAt(mIndex--);
581}
582
583/**
584 * Dereference operator
585 * Note that the iterator floats, so you don't need to do:
586 * <code>++iter; aDeque.PopFront();</code>
587 * Unless you actually want your iterator to jump 2 spaces.
588 *
589 * Picture: [1 2I 3 4]
590 * PopFront()
591 * Picture: [2 3I 4]
592 * Note that I still happily points to object at the second index
593 *
594 * @return object at ith index
595 */
596void* nsDequeIterator::GetCurrent() {
597 NS_ASSERTION(mIndex<mDeque.mSize&&mIndex>=0,"Current is out of bounds");
598#ifndef TIMELESS_LIGHTWEIGHT
599 if (mIndex>=mDeque.mSize||mIndex<0) return 0;
600#endif
601 return mDeque.ObjectAt(mIndex);
602}
603
604/**
605 * Call this method when you want to iterate all the
606 * members of the container, passing a functor along
607 * to call your code.
608 *
609 * @param aFunctor object to call for each member
610 * @return *this
611 */
612void nsDequeIterator::ForEach(nsDequeFunctor& aFunctor) const{
613 mDeque.ForEach(aFunctor);
614}
615
616/**
617 * Call this method when you want to iterate all the
618 * members of the container, calling the functor you
619 * passed with each member. This process will interrupt
620 * if your function returns non 0 to this method.
621 *
622 * @param aFunctor object to call for each member
623 * @return first nonzero result of aFunctor or 0.
624 */
625const void* nsDequeIterator::FirstThat(nsDequeFunctor& aFunctor) const{
626 return mDeque.FirstThat(aFunctor);
627}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use