VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/xpcom/ds/nsVoidArray.cpp@ 44770

最後變更 在這個檔案從44770是 1,由 vboxsync 提交於 55 年 前

import

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 35.8 KB
 
1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; c-file-offsets: ((substatement-open . 0)) -*- */
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#include "nsVoidArray.h"
38#include "nsQuickSort.h"
39#include "prmem.h"
40#include "nsCRT.h"
41#include "nsString.h"
42#include "prbit.h"
43
44/**
45 * Grow the array by at least this many elements at a time.
46 */
47static const PRInt32 kMinGrowArrayBy = 8;
48static const PRInt32 kMaxGrowArrayBy = 1024;
49
50/**
51 * This is the threshold (in bytes) of the mImpl struct, past which
52 * we'll force the array to grow geometrically
53 */
54static const PRInt32 kLinearThreshold = 24 * sizeof(void *);
55
56/**
57 * Compute the number of bytes requires for the mImpl struct that will
58 * hold |n| elements.
59 */
60#define SIZEOF_IMPL(n_) (sizeof(Impl) + sizeof(void *) * ((n_) - 1))
61
62
63/**
64 * Compute the number of elements that an mImpl struct of |n| bytes
65 * will hold.
66 */
67#define CAPACITYOF_IMPL(n_) ((((n_) - sizeof(Impl)) / sizeof(void *)) + 1)
68
69#if DEBUG_VOIDARRAY
70#define MAXVOID 10
71
72class VoidStats {
73public:
74 VoidStats();
75 ~VoidStats();
76
77};
78
79static int sizesUsed; // number of the elements of the arrays used
80static int sizesAlloced[MAXVOID]; // sizes of the allocations. sorted
81static int NumberOfSize[MAXVOID]; // number of this allocation size (1 per array)
82static int AllocedOfSize[MAXVOID]; // number of this allocation size (each size for array used)
83static int MaxAuto[MAXVOID]; // AutoArrays that maxed out at this size
84static int GrowInPlace[MAXVOID]; // arrays this size that grew in-place via realloc
85
86// these are per-allocation
87static int MaxElements[2000]; // # of arrays that maxed out at each size.
88
89// statistics macros
90#define ADD_TO_STATS(x,size) do {int i; for (i = 0; i < sizesUsed; i++) \
91 { \
92 if (sizesAlloced[i] == (int)(size)) \
93 { ((x)[i])++; break; } \
94 } \
95 if (i >= sizesUsed && sizesUsed < MAXVOID) \
96 { sizesAlloced[sizesUsed] = (size); \
97 ((x)[sizesUsed++])++; break; \
98 } \
99 } while (0)
100
101#define SUB_FROM_STATS(x,size) do {int i; for (i = 0; i < sizesUsed; i++) \
102 { \
103 if (sizesAlloced[i] == (int)(size)) \
104 { ((x)[i])--; break; } \
105 } \
106 } while (0)
107
108
109VoidStats::VoidStats()
110{
111 sizesUsed = 1;
112 sizesAlloced[0] = 0;
113}
114
115VoidStats::~VoidStats()
116{
117 int i;
118 for (i = 0; i < sizesUsed; i++)
119 {
120 printf("Size %d:\n",sizesAlloced[i]);
121 printf("\tNumber of VoidArrays this size (max): %d\n",NumberOfSize[i]-MaxAuto[i]);
122 printf("\tNumber of AutoVoidArrays this size (max): %d\n",MaxAuto[i]);
123 printf("\tNumber of allocations this size (total): %d\n",AllocedOfSize[i]);
124 printf("\tNumber of GrowsInPlace this size (total): %d\n",GrowInPlace[i]);
125 }
126 printf("Max Size of VoidArray:\n");
127 for (i = 0; i < (int)(sizeof(MaxElements)/sizeof(MaxElements[0])); i++)
128 {
129 if (MaxElements[i])
130 printf("\t%d: %d\n",i,MaxElements[i]);
131 }
132}
133
134// Just so constructor/destructor's get called
135VoidStats gVoidStats;
136#endif
137
138inline void
139nsVoidArray::SetArray(Impl *newImpl, PRInt32 aSize, PRInt32 aCount, PRBool owner)
140{
141 // old mImpl has been realloced and so we don't free/delete it
142 NS_PRECONDITION(newImpl, "can't set size");
143 mImpl = newImpl;
144 mImpl->mCount = aCount;
145 mImpl->mBits = PRUint32(aSize & kArraySizeMask) |
146 (owner ? kArrayOwnerMask : 0);
147}
148
149// This does all allocation/reallocation of the array.
150// It also will compact down to N - good for things that might grow a lot
151// at times, but usually are smaller, like JS deferred GC releases.
152PRBool nsVoidArray::SizeTo(PRInt32 aSize)
153{
154 PRUint32 oldsize = GetArraySize();
155
156 if (aSize == (PRInt32) oldsize)
157 return PR_TRUE; // no change
158
159 if (aSize <= 0)
160 {
161 // free the array if allocated
162 if (mImpl)
163 {
164 if (IsArrayOwner())
165 {
166 PR_Free(NS_REINTERPRET_CAST(char *, mImpl));
167 mImpl = nsnull;
168 }
169 else
170 {
171 mImpl->mCount = 0; // nsAutoVoidArray
172 }
173 }
174 return PR_TRUE;
175 }
176
177 if (mImpl && IsArrayOwner())
178 {
179 // We currently own an array impl. Resize it appropriately.
180 if (aSize < mImpl->mCount)
181 {
182 // XXX Note: we could also just resize to mCount
183 return PR_TRUE; // can't make it that small, ignore request
184 }
185
186 char* bytes = (char *) PR_Realloc(mImpl,SIZEOF_IMPL(aSize));
187 Impl* newImpl = NS_REINTERPRET_CAST(Impl*, bytes);
188 if (!newImpl)
189 return PR_FALSE;
190
191#if DEBUG_VOIDARRAY
192 if (mImpl == newImpl)
193 ADD_TO_STATS(GrowInPlace,oldsize);
194 ADD_TO_STATS(AllocedOfSize,SIZEOF_IMPL(aSize));
195 if (aSize > mMaxSize)
196 {
197 ADD_TO_STATS(NumberOfSize,SIZEOF_IMPL(aSize));
198 if (oldsize)
199 SUB_FROM_STATS(NumberOfSize,oldsize);
200 mMaxSize = aSize;
201 if (mIsAuto)
202 {
203 ADD_TO_STATS(MaxAuto,SIZEOF_IMPL(aSize));
204 SUB_FROM_STATS(MaxAuto,oldsize);
205 }
206 }
207#endif
208 SetArray(newImpl,aSize,newImpl->mCount,PR_TRUE);
209 return PR_TRUE;
210 }
211
212 // just allocate an array
213 // allocate the exact size requested
214 char* bytes = (char *) PR_Malloc(SIZEOF_IMPL(aSize));
215 Impl* newImpl = NS_REINTERPRET_CAST(Impl*, bytes);
216 if (!newImpl)
217 return PR_FALSE;
218
219#if DEBUG_VOIDARRAY
220 ADD_TO_STATS(AllocedOfSize,SIZEOF_IMPL(aSize));
221 if (aSize > mMaxSize)
222 {
223 ADD_TO_STATS(NumberOfSize,SIZEOF_IMPL(aSize));
224 if (oldsize && !mImpl)
225 SUB_FROM_STATS(NumberOfSize,oldsize);
226 mMaxSize = aSize;
227 }
228#endif
229 if (mImpl)
230 {
231#if DEBUG_VOIDARRAY
232 ADD_TO_STATS(MaxAuto,SIZEOF_IMPL(aSize));
233 SUB_FROM_STATS(MaxAuto,0);
234 SUB_FROM_STATS(NumberOfSize,0);
235 mIsAuto = PR_TRUE;
236#endif
237 // We must be growing an nsAutoVoidArray - copy since we didn't
238 // realloc.
239 memcpy(newImpl->mArray, mImpl->mArray,
240 mImpl->mCount * sizeof(mImpl->mArray[0]));
241 }
242
243 SetArray(newImpl,aSize,mImpl ? mImpl->mCount : 0,PR_TRUE);
244 // no memset; handled later in ReplaceElementAt if needed
245 return PR_TRUE;
246}
247
248PRBool nsVoidArray::GrowArrayBy(PRInt32 aGrowBy)
249{
250 // We have to grow the array. Grow by kMinGrowArrayBy slots if we're
251 // smaller than kLinearThreshold bytes, or a power of two if we're
252 // larger. This is much more efficient with most memory allocators,
253 // especially if it's very large, or of the allocator is binned.
254 if (aGrowBy < kMinGrowArrayBy)
255 aGrowBy = kMinGrowArrayBy;
256
257 PRUint32 newCapacity = GetArraySize() + aGrowBy; // Minimum increase
258 PRUint32 newSize = SIZEOF_IMPL(newCapacity);
259
260 if (newSize >= (PRUint32) kLinearThreshold)
261 {
262 // newCount includes enough space for at least kMinGrowArrayBy new
263 // slots. Select the next power-of-two size in bytes above or
264 // equal to that.
265 // Also, limit the increase in size to about a VM page or two.
266 if (GetArraySize() >= kMaxGrowArrayBy)
267 {
268 newCapacity = GetArraySize() + PR_MAX(kMaxGrowArrayBy,aGrowBy);
269 newSize = SIZEOF_IMPL(newCapacity);
270 }
271 else
272 {
273 newSize = PR_BIT(PR_CeilingLog2(newSize));
274 newCapacity = CAPACITYOF_IMPL(newSize);
275 }
276 }
277 // frees old mImpl IF this succeeds
278 if (!SizeTo(newCapacity))
279 return PR_FALSE;
280
281 return PR_TRUE;
282}
283
284nsVoidArray::nsVoidArray()
285 : mImpl(nsnull)
286{
287 MOZ_COUNT_CTOR(nsVoidArray);
288#if DEBUG_VOIDARRAY
289 mMaxCount = 0;
290 mMaxSize = 0;
291 mIsAuto = PR_FALSE;
292 ADD_TO_STATS(NumberOfSize,0);
293 MaxElements[0]++;
294#endif
295}
296
297nsVoidArray::nsVoidArray(PRInt32 aCount)
298 : mImpl(nsnull)
299{
300 MOZ_COUNT_CTOR(nsVoidArray);
301#if DEBUG_VOIDARRAY
302 mMaxCount = 0;
303 mMaxSize = 0;
304 mIsAuto = PR_FALSE;
305 MaxElements[0]++;
306#endif
307 SizeTo(aCount);
308}
309
310nsVoidArray& nsVoidArray::operator=(const nsVoidArray& other)
311{
312 PRInt32 otherCount = other.Count();
313 PRInt32 maxCount = GetArraySize();
314 if (otherCount)
315 {
316 if (otherCount > maxCount)
317 {
318 // frees old mImpl IF this succeeds
319 if (!GrowArrayBy(otherCount-maxCount))
320 return *this; // XXX The allocation failed - don't do anything
321
322 memcpy(mImpl->mArray, other.mImpl->mArray, otherCount * sizeof(mImpl->mArray[0]));
323 mImpl->mCount = otherCount;
324 }
325 else
326 {
327 // the old array can hold the new array
328 memcpy(mImpl->mArray, other.mImpl->mArray, otherCount * sizeof(mImpl->mArray[0]));
329 mImpl->mCount = otherCount;
330 // if it shrank a lot, compact it anyways
331 if ((otherCount*2) < maxCount && maxCount > 100)
332 {
333 Compact(); // shrank by at least 50 entries
334 }
335 }
336#if DEBUG_VOIDARRAY
337 if (mImpl->mCount > mMaxCount &&
338 mImpl->mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0])))
339 {
340 MaxElements[mImpl->mCount]++;
341 MaxElements[mMaxCount]--;
342 mMaxCount = mImpl->mCount;
343 }
344#endif
345 }
346 else
347 {
348 if (mImpl && IsArrayOwner())
349 PR_Free(NS_REINTERPRET_CAST(char*, mImpl));
350
351 mImpl = nsnull;
352 }
353
354 return *this;
355}
356
357nsVoidArray::~nsVoidArray()
358{
359 MOZ_COUNT_DTOR(nsVoidArray);
360 if (mImpl && IsArrayOwner())
361 PR_Free(NS_REINTERPRET_CAST(char*, mImpl));
362}
363
364PRInt32 nsVoidArray::IndexOf(void* aPossibleElement) const
365{
366 if (mImpl)
367 {
368 void** ap = mImpl->mArray;
369 void** end = ap + mImpl->mCount;
370 while (ap < end)
371 {
372 if (*ap == aPossibleElement)
373 {
374 return ap - mImpl->mArray;
375 }
376 ap++;
377 }
378 }
379 return -1;
380}
381
382PRBool nsVoidArray::InsertElementAt(void* aElement, PRInt32 aIndex)
383{
384 PRInt32 oldCount = Count();
385 NS_ASSERTION(aIndex >= 0,"InsertElementAt(negative index)");
386 if (PRUint32(aIndex) > PRUint32(oldCount))
387 {
388 // An invalid index causes the insertion to fail
389 // Invalid indexes are ones that add more than one entry to the
390 // array (i.e., they can append).
391 return PR_FALSE;
392 }
393
394 if (oldCount >= GetArraySize())
395 {
396 if (!GrowArrayBy(1))
397 return PR_FALSE;
398 }
399 // else the array is already large enough
400
401 PRInt32 slide = oldCount - aIndex;
402 if (0 != slide)
403 {
404 // Slide data over to make room for the insertion
405 memmove(mImpl->mArray + aIndex + 1, mImpl->mArray + aIndex,
406 slide * sizeof(mImpl->mArray[0]));
407 }
408
409 mImpl->mArray[aIndex] = aElement;
410 mImpl->mCount++;
411
412#if DEBUG_VOIDARRAY
413 if (mImpl->mCount > mMaxCount &&
414 mImpl->mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0])))
415 {
416 MaxElements[mImpl->mCount]++;
417 MaxElements[mMaxCount]--;
418 mMaxCount = mImpl->mCount;
419 }
420#endif
421
422 return PR_TRUE;
423}
424
425PRBool nsVoidArray::InsertElementsAt(const nsVoidArray& other, PRInt32 aIndex)
426{
427 PRInt32 oldCount = Count();
428 PRInt32 otherCount = other.Count();
429
430 NS_ASSERTION(aIndex >= 0,"InsertElementsAt(negative index)");
431 if (PRUint32(aIndex) > PRUint32(oldCount))
432 {
433 // An invalid index causes the insertion to fail
434 // Invalid indexes are ones that are more than one entry past the end of
435 // the array (i.e., they can append).
436 return PR_FALSE;
437 }
438
439 if (oldCount + otherCount > GetArraySize())
440 {
441 if (!GrowArrayBy(otherCount))
442 return PR_FALSE;;
443 }
444 // else the array is already large enough
445
446 PRInt32 slide = oldCount - aIndex;
447 if (0 != slide)
448 {
449 // Slide data over to make room for the insertion
450 memmove(mImpl->mArray + aIndex + otherCount, mImpl->mArray + aIndex,
451 slide * sizeof(mImpl->mArray[0]));
452 }
453
454 for (PRInt32 i = 0; i < otherCount; i++)
455 {
456 // copy all the elements (destroys aIndex)
457 mImpl->mArray[aIndex++] = other.mImpl->mArray[i];
458 mImpl->mCount++;
459 }
460
461#if DEBUG_VOIDARRAY
462 if (mImpl->mCount > mMaxCount &&
463 mImpl->mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0])))
464 {
465 MaxElements[mImpl->mCount]++;
466 MaxElements[mMaxCount]--;
467 mMaxCount = mImpl->mCount;
468 }
469#endif
470
471 return PR_TRUE;
472}
473
474PRBool nsVoidArray::ReplaceElementAt(void* aElement, PRInt32 aIndex)
475{
476 NS_ASSERTION(aIndex >= 0,"ReplaceElementAt(negative index)");
477 if (aIndex < 0)
478 return PR_FALSE;
479
480 // Unlike InsertElementAt, ReplaceElementAt can implicitly add more
481 // than just the one element to the array.
482 if (PRUint32(aIndex) >= PRUint32(GetArraySize()))
483 {
484 PRInt32 oldCount = Count();
485 PRInt32 requestedCount = aIndex + 1;
486 PRInt32 growDelta = requestedCount - oldCount;
487
488 // frees old mImpl IF this succeeds
489 if (!GrowArrayBy(growDelta))
490 return PR_FALSE;
491 }
492
493 mImpl->mArray[aIndex] = aElement;
494 if (aIndex >= mImpl->mCount)
495 {
496 // Make sure that any entries implicitly added to the array by this
497 // ReplaceElementAt are cleared to 0. Some users of this assume that.
498 // This code means we don't have to memset when we allocate an array.
499 if (aIndex > mImpl->mCount) // note: not >=
500 {
501 // For example, if mCount is 2, and we do a ReplaceElementAt for
502 // element[5], then we need to set three entries ([2], [3], and [4])
503 // to 0.
504 memset(&mImpl->mArray[mImpl->mCount], 0,
505 (aIndex - mImpl->mCount) * sizeof(mImpl->mArray[0]));
506 }
507
508 mImpl->mCount = aIndex + 1;
509
510#if DEBUG_VOIDARRAY
511 if (mImpl->mCount > mMaxCount &&
512 mImpl->mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0])))
513 {
514 MaxElements[mImpl->mCount]++;
515 MaxElements[mMaxCount]--;
516 mMaxCount = mImpl->mCount;
517 }
518#endif
519 }
520
521 return PR_TRUE;
522}
523
524// useful for doing LRU arrays
525PRBool nsVoidArray::MoveElement(PRInt32 aFrom, PRInt32 aTo)
526{
527 void *tempElement;
528
529 if (aTo == aFrom)
530 return PR_TRUE;
531
532 NS_ASSERTION(aTo >= 0 && aFrom >= 0,"MoveElement(negative index)");
533 if (aTo >= Count() || aFrom >= Count())
534 {
535 // can't extend the array when moving an element. Also catches mImpl = null
536 return PR_FALSE;
537 }
538 tempElement = mImpl->mArray[aFrom];
539
540 if (aTo < aFrom)
541 {
542 // Moving one element closer to the head; the elements inbetween move down
543 memmove(mImpl->mArray + aTo + 1, mImpl->mArray + aTo,
544 (aFrom-aTo) * sizeof(mImpl->mArray[0]));
545 mImpl->mArray[aTo] = tempElement;
546 }
547 else // already handled aFrom == aTo
548 {
549 // Moving one element closer to the tail; the elements inbetween move up
550 memmove(mImpl->mArray + aFrom, mImpl->mArray + aFrom + 1,
551 (aTo-aFrom) * sizeof(mImpl->mArray[0]));
552 mImpl->mArray[aTo] = tempElement;
553 }
554
555 return PR_TRUE;
556}
557
558PRBool nsVoidArray::RemoveElementsAt(PRInt32 aIndex, PRInt32 aCount)
559{
560 PRInt32 oldCount = Count();
561 NS_ASSERTION(aIndex >= 0,"RemoveElementsAt(negative index)");
562 if (PRUint32(aIndex) >= PRUint32(oldCount))
563 {
564 // An invalid index causes the replace to fail
565 return PR_FALSE;
566 }
567 // Limit to available entries starting at aIndex
568 if (aCount + aIndex > oldCount)
569 aCount = oldCount - aIndex;
570
571 // We don't need to move any elements if we're removing the
572 // last element in the array
573 if (aIndex < (oldCount - aCount))
574 {
575 memmove(mImpl->mArray + aIndex, mImpl->mArray + aIndex + aCount,
576 (oldCount - (aIndex + aCount)) * sizeof(mImpl->mArray[0]));
577 }
578
579 mImpl->mCount -= aCount;
580 return PR_TRUE;
581}
582
583PRBool nsVoidArray::RemoveElement(void* aElement)
584{
585 PRInt32 theIndex = IndexOf(aElement);
586 if (theIndex != -1)
587 return RemoveElementAt(theIndex);
588
589 return PR_FALSE;
590}
591
592void nsVoidArray::Clear()
593{
594 if (mImpl)
595 {
596 mImpl->mCount = 0;
597 }
598}
599
600void nsVoidArray::Compact()
601{
602 if (mImpl)
603 {
604 // XXX NOTE: this is quite inefficient in many cases if we're only
605 // compacting by a little, but some callers care more about memory use.
606 if (GetArraySize() > Count())
607 {
608 SizeTo(Count());
609 }
610 }
611}
612
613// Needed because we want to pass the pointer to the item in the array
614// to the comparator function, not a pointer to the pointer in the array.
615struct VoidArrayComparatorContext {
616 nsVoidArrayComparatorFunc mComparatorFunc;
617 void* mData;
618};
619
620PR_STATIC_CALLBACK(int)
621VoidArrayComparator(const void* aElement1, const void* aElement2, void* aData)
622{
623 VoidArrayComparatorContext* ctx = NS_STATIC_CAST(VoidArrayComparatorContext*, aData);
624 return (*ctx->mComparatorFunc)(*NS_STATIC_CAST(void* const*, aElement1),
625 *NS_STATIC_CAST(void* const*, aElement2),
626 ctx->mData);
627}
628
629void nsVoidArray::Sort(nsVoidArrayComparatorFunc aFunc, void* aData)
630{
631 if (mImpl && mImpl->mCount > 1)
632 {
633 VoidArrayComparatorContext ctx = {aFunc, aData};
634 NS_QuickSort(mImpl->mArray, mImpl->mCount, sizeof(mImpl->mArray[0]),
635 VoidArrayComparator, &ctx);
636 }
637}
638
639PRBool nsVoidArray::EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData)
640{
641 PRInt32 index = -1;
642 PRBool running = PR_TRUE;
643
644 if (mImpl)
645 {
646 while (running && (++index < mImpl->mCount))
647 {
648 running = (*aFunc)(mImpl->mArray[index], aData);
649 }
650 }
651 return running;
652}
653
654PRBool nsVoidArray::EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData)
655{
656 PRBool running = PR_TRUE;
657
658 if (mImpl)
659 {
660 PRInt32 index = Count();
661 while (running && (0 <= --index))
662 {
663 running = (*aFunc)(mImpl->mArray[index], aData);
664 }
665 }
666 return running;
667}
668
669//----------------------------------------------------------------
670// nsAutoVoidArray
671
672nsAutoVoidArray::nsAutoVoidArray()
673 : nsVoidArray()
674{
675 // Don't need to clear it. Some users just call ReplaceElementAt(),
676 // but we'll clear it at that time if needed to save CPU cycles.
677#if DEBUG_VOIDARRAY
678 mIsAuto = PR_TRUE;
679 ADD_TO_STATS(MaxAuto,0);
680#endif
681 SetArray(NS_REINTERPRET_CAST(Impl*, mAutoBuf),kAutoBufSize,0,PR_FALSE);
682}
683
684void nsAutoVoidArray::Clear()
685{
686 // We don't have to free on Clear, but since we have a built-in buffer,
687 // it's worth considering.
688 nsVoidArray::Clear();
689 if (IsArrayOwner() && GetArraySize() > 4*kAutoBufSize)
690 SizeTo(0); // we override CompactTo - delete and repoint at auto array
691}
692
693PRBool nsAutoVoidArray::SizeTo(PRInt32 aSize)
694{
695 if (!nsVoidArray::SizeTo(aSize))
696 return PR_FALSE;
697
698 if (!mImpl)
699 {
700 // reset the array to point to our autobuf
701 SetArray(NS_REINTERPRET_CAST(Impl*, mAutoBuf),kAutoBufSize,0,PR_FALSE);
702 }
703 return PR_TRUE;
704}
705
706void nsAutoVoidArray::Compact()
707{
708 nsVoidArray::Compact();
709 if (!mImpl)
710 {
711 // reset the array to point to our autobuf
712 SetArray(NS_REINTERPRET_CAST(Impl*, mAutoBuf),kAutoBufSize,0,PR_FALSE);
713 }
714}
715
716//----------------------------------------------------------------
717// nsStringArray
718
719nsStringArray::nsStringArray(void)
720 : nsVoidArray()
721{
722}
723
724nsStringArray::nsStringArray(PRInt32 aCount)
725 : nsVoidArray(aCount)
726{
727}
728
729nsStringArray::~nsStringArray(void)
730{
731 Clear();
732}
733
734nsStringArray&
735nsStringArray::operator=(const nsStringArray& other)
736{
737 // Copy the pointers
738 nsVoidArray::operator=(other);
739
740 // Now copy the strings
741 for (PRInt32 i = Count() - 1; i >= 0; --i)
742 {
743 nsString* oldString = NS_STATIC_CAST(nsString*, other.ElementAt(i));
744 mImpl->mArray[i] = new nsString(*oldString);
745 }
746
747 return *this;
748}
749
750void
751nsStringArray::StringAt(PRInt32 aIndex, nsAString& aString) const
752{
753 nsString* string = NS_STATIC_CAST(nsString*, nsVoidArray::ElementAt(aIndex));
754 if (nsnull != string)
755 {
756 aString.Assign(*string);
757 }
758 else
759 {
760 aString.Truncate();
761 }
762}
763
764nsString*
765nsStringArray::StringAt(PRInt32 aIndex) const
766{
767 return NS_STATIC_CAST(nsString*, nsVoidArray::ElementAt(aIndex));
768}
769
770PRInt32
771nsStringArray::IndexOf(const nsAString& aPossibleString) const
772{
773 if (mImpl)
774 {
775 void** ap = mImpl->mArray;
776 void** end = ap + mImpl->mCount;
777 while (ap < end)
778 {
779 nsString* string = NS_STATIC_CAST(nsString*, *ap);
780 if (string->Equals(aPossibleString))
781 {
782 return ap - mImpl->mArray;
783 }
784 ap++;
785 }
786 }
787 return -1;
788}
789
790PRBool
791nsStringArray::InsertStringAt(const nsAString& aString, PRInt32 aIndex)
792{
793 nsString* string = new nsString(aString);
794 if (nsVoidArray::InsertElementAt(string, aIndex))
795 {
796 return PR_TRUE;
797 }
798 delete string;
799 return PR_FALSE;
800}
801
802PRBool
803nsStringArray::ReplaceStringAt(const nsAString& aString,
804 PRInt32 aIndex)
805{
806 nsString* string = NS_STATIC_CAST(nsString*, nsVoidArray::ElementAt(aIndex));
807 if (nsnull != string)
808 {
809 *string = aString;
810 return PR_TRUE;
811 }
812 return PR_FALSE;
813}
814
815PRBool
816nsStringArray::RemoveString(const nsAString& aString)
817{
818 PRInt32 index = IndexOf(aString);
819 if (-1 < index)
820 {
821 return RemoveStringAt(index);
822 }
823 return PR_FALSE;
824}
825
826PRBool nsStringArray::RemoveStringAt(PRInt32 aIndex)
827{
828 nsString* string = StringAt(aIndex);
829 if (nsnull != string)
830 {
831 nsVoidArray::RemoveElementAt(aIndex);
832 delete string;
833 return PR_TRUE;
834 }
835 return PR_FALSE;
836}
837
838void
839nsStringArray::Clear(void)
840{
841 PRInt32 index = Count();
842 while (0 <= --index)
843 {
844 nsString* string = NS_STATIC_CAST(nsString*, mImpl->mArray[index]);
845 delete string;
846 }
847 nsVoidArray::Clear();
848}
849
850PR_STATIC_CALLBACK(int)
851CompareString(const nsString* aString1, const nsString* aString2, void*)
852{
853 return Compare(*aString1, *aString2);
854}
855
856void nsStringArray::Sort(void)
857{
858 Sort(CompareString, nsnull);
859}
860
861void nsStringArray::Sort(nsStringArrayComparatorFunc aFunc, void* aData)
862{
863 nsVoidArray::Sort(NS_REINTERPRET_CAST(nsVoidArrayComparatorFunc, aFunc), aData);
864}
865
866PRBool
867nsStringArray::EnumerateForwards(nsStringArrayEnumFunc aFunc, void* aData)
868{
869 PRInt32 index = -1;
870 PRBool running = PR_TRUE;
871
872 if (mImpl)
873 {
874 while (running && (++index < mImpl->mCount))
875 {
876 running = (*aFunc)(*NS_STATIC_CAST(nsString*, mImpl->mArray[index]), aData);
877 }
878 }
879 return running;
880}
881
882PRBool
883nsStringArray::EnumerateBackwards(nsStringArrayEnumFunc aFunc, void* aData)
884{
885 PRInt32 index = Count();
886 PRBool running = PR_TRUE;
887
888 if (mImpl)
889 {
890 while (running && (0 <= --index))
891 {
892 running = (*aFunc)(*NS_STATIC_CAST(nsString*, mImpl->mArray[index]), aData);
893 }
894 }
895 return running;
896}
897
898
899
900//----------------------------------------------------------------
901// nsCStringArray
902
903nsCStringArray::nsCStringArray(void)
904 : nsVoidArray()
905{
906}
907
908// Parses a given string using the delimiter passed in and appends items
909// parsed to the array.
910void
911nsCStringArray::ParseString(const char* string, const char* delimiter)
912{
913 if (string && *string && delimiter && *delimiter) {
914 char *newStr;
915 char *rest = nsCRT::strdup(string);
916 char *token = nsCRT::strtok(rest, delimiter, &newStr);
917
918 while (token) {
919 if (*token) {
920 /* calling AppendElement(void*) to avoid extra nsCString copy */
921 AppendElement(new nsCString(token));
922 }
923 token = nsCRT::strtok(newStr, delimiter, &newStr);
924 }
925 PR_FREEIF(rest);
926 }
927}
928
929nsCStringArray::nsCStringArray(PRInt32 aCount)
930 : nsVoidArray(aCount)
931{
932}
933
934nsCStringArray::~nsCStringArray(void)
935{
936 Clear();
937}
938
939nsCStringArray&
940nsCStringArray::operator=(const nsCStringArray& other)
941{
942 // Copy the pointers
943 nsVoidArray::operator=(other);
944
945 // Now copy the strings
946 for (PRInt32 i = Count() - 1; i >= 0; --i)
947 {
948 nsCString* oldString = NS_STATIC_CAST(nsCString*, other.ElementAt(i));
949 mImpl->mArray[i] = new nsCString(*oldString);
950 }
951
952 return *this;
953}
954
955void
956nsCStringArray::CStringAt(PRInt32 aIndex, nsACString& aCString) const
957{
958 nsCString* string = NS_STATIC_CAST(nsCString*, nsVoidArray::ElementAt(aIndex));
959 if (nsnull != string)
960 {
961 aCString = *string;
962 }
963 else
964 {
965 aCString.Truncate();
966 }
967}
968
969nsCString*
970nsCStringArray::CStringAt(PRInt32 aIndex) const
971{
972 return NS_STATIC_CAST(nsCString*, nsVoidArray::ElementAt(aIndex));
973}
974
975PRInt32
976nsCStringArray::IndexOf(const nsACString& aPossibleString) const
977{
978 if (mImpl)
979 {
980 void** ap = mImpl->mArray;
981 void** end = ap + mImpl->mCount;
982 while (ap < end)
983 {
984 nsCString* string = NS_STATIC_CAST(nsCString*, *ap);
985 if (string->Equals(aPossibleString))
986 {
987 return ap - mImpl->mArray;
988 }
989 ap++;
990 }
991 }
992 return -1;
993}
994
995PRInt32
996nsCStringArray::IndexOfIgnoreCase(const nsACString& aPossibleString) const
997{
998 if (mImpl)
999 {
1000 void** ap = mImpl->mArray;
1001 void** end = ap + mImpl->mCount;
1002 while (ap < end)
1003 {
1004 nsCString* string = NS_STATIC_CAST(nsCString*, *ap);
1005 if (string->Equals(aPossibleString, nsCaseInsensitiveCStringComparator()))
1006 {
1007 return ap - mImpl->mArray;
1008 }
1009 ap++;
1010 }
1011 }
1012 return -1;
1013}
1014
1015PRBool
1016nsCStringArray::InsertCStringAt(const nsACString& aCString, PRInt32 aIndex)
1017{
1018 nsCString* string = new nsCString(aCString);
1019 if (nsVoidArray::InsertElementAt(string, aIndex))
1020 {
1021 return PR_TRUE;
1022 }
1023 delete string;
1024 return PR_FALSE;
1025}
1026
1027PRBool
1028nsCStringArray::ReplaceCStringAt(const nsACString& aCString, PRInt32 aIndex)
1029{
1030 nsCString* string = NS_STATIC_CAST(nsCString*, nsVoidArray::ElementAt(aIndex));
1031 if (nsnull != string)
1032 {
1033 *string = aCString;
1034 return PR_TRUE;
1035 }
1036 return PR_FALSE;
1037}
1038
1039PRBool
1040nsCStringArray::RemoveCString(const nsACString& aCString)
1041{
1042 PRInt32 index = IndexOf(aCString);
1043 if (-1 < index)
1044 {
1045 return RemoveCStringAt(index);
1046 }
1047 return PR_FALSE;
1048}
1049
1050PRBool
1051nsCStringArray::RemoveCStringIgnoreCase(const nsACString& aCString)
1052{
1053 PRInt32 index = IndexOfIgnoreCase(aCString);
1054 if (-1 < index)
1055 {
1056 return RemoveCStringAt(index);
1057 }
1058 return PR_FALSE;
1059}
1060
1061PRBool nsCStringArray::RemoveCStringAt(PRInt32 aIndex)
1062{
1063 nsCString* string = CStringAt(aIndex);
1064 if (nsnull != string)
1065 {
1066 nsVoidArray::RemoveElementAt(aIndex);
1067 delete string;
1068 return PR_TRUE;
1069 }
1070 return PR_FALSE;
1071}
1072
1073void
1074nsCStringArray::Clear(void)
1075{
1076 PRInt32 index = Count();
1077 while (0 <= --index)
1078 {
1079 nsCString* string = NS_STATIC_CAST(nsCString*, mImpl->mArray[index]);
1080 delete string;
1081 }
1082 nsVoidArray::Clear();
1083}
1084
1085PR_STATIC_CALLBACK(int)
1086CompareCString(const nsCString* aCString1, const nsCString* aCString2, void*)
1087{
1088 return Compare(*aCString1, *aCString2);
1089}
1090
1091PR_STATIC_CALLBACK(int)
1092CompareCStringIgnoreCase(const nsCString* aCString1, const nsCString* aCString2, void*)
1093{
1094 return Compare(*aCString1, *aCString2, nsCaseInsensitiveCStringComparator());
1095}
1096
1097void nsCStringArray::Sort(void)
1098{
1099 Sort(CompareCString, nsnull);
1100}
1101
1102void nsCStringArray::SortIgnoreCase(void)
1103{
1104 Sort(CompareCStringIgnoreCase, nsnull);
1105}
1106
1107void nsCStringArray::Sort(nsCStringArrayComparatorFunc aFunc, void* aData)
1108{
1109 nsVoidArray::Sort(NS_REINTERPRET_CAST(nsVoidArrayComparatorFunc, aFunc), aData);
1110}
1111
1112PRBool
1113nsCStringArray::EnumerateForwards(nsCStringArrayEnumFunc aFunc, void* aData)
1114{
1115 PRBool running = PR_TRUE;
1116
1117 if (mImpl)
1118 {
1119 PRInt32 index = -1;
1120 while (running && (++index < mImpl->mCount))
1121 {
1122 running = (*aFunc)(*NS_STATIC_CAST(nsCString*, mImpl->mArray[index]), aData);
1123 }
1124 }
1125 return running;
1126}
1127
1128PRBool
1129nsCStringArray::EnumerateBackwards(nsCStringArrayEnumFunc aFunc, void* aData)
1130{
1131 PRBool running = PR_TRUE;
1132
1133 if (mImpl)
1134 {
1135 PRInt32 index = Count();
1136 while (running && (0 <= --index))
1137 {
1138 running = (*aFunc)(*NS_STATIC_CAST(nsCString*, mImpl->mArray[index]), aData);
1139 }
1140 }
1141 return running;
1142}
1143
1144
1145//----------------------------------------------------------------------
1146// NOTE: nsSmallVoidArray elements MUST all have the low bit as 0.
1147// This means that normally it's only used for pointers, and in particular
1148// structures or objects.
1149nsSmallVoidArray::nsSmallVoidArray()
1150{
1151 mChildren = nsnull;
1152}
1153
1154nsSmallVoidArray::~nsSmallVoidArray()
1155{
1156 if (HasVector())
1157 {
1158 nsVoidArray* vector = GetChildVector();
1159 delete vector;
1160 }
1161}
1162
1163nsSmallVoidArray&
1164nsSmallVoidArray::operator=(nsSmallVoidArray& other)
1165{
1166 nsVoidArray* ourArray = GetChildVector();
1167 nsVoidArray* otherArray = other.GetChildVector();
1168
1169 if (HasVector())
1170 {
1171 if (other.HasVector())
1172 {
1173 // if both are real arrays, just use array= */
1174 *ourArray = *otherArray;
1175 }
1176 else
1177 {
1178 // we have an array, but the other doesn't.
1179 otherArray = other.SwitchToVector();
1180 if (otherArray)
1181 *ourArray = *otherArray;
1182 }
1183 }
1184 else
1185 {
1186 if (other.HasVector())
1187 {
1188 // we have no array, but other does
1189 ourArray = SwitchToVector();
1190 if (ourArray)
1191 *ourArray = *otherArray;
1192 }
1193 else
1194 {
1195 // neither has an array (either may have 0 or 1 items)
1196 SetSingleChild(other.GetSingleChild());
1197 }
1198 }
1199 return *this;
1200}
1201
1202PRInt32
1203nsSmallVoidArray::GetArraySize() const
1204{
1205 nsVoidArray* vector = GetChildVector();
1206 if (vector)
1207 return vector->GetArraySize();
1208
1209 return 1;
1210}
1211
1212PRInt32
1213nsSmallVoidArray::Count() const
1214{
1215 if (HasSingleChild())
1216 {
1217 return 1;
1218 }
1219 else {
1220 nsVoidArray* vector = GetChildVector();
1221 if (vector)
1222 return vector->Count();
1223 }
1224
1225 return 0;
1226}
1227
1228void*
1229nsSmallVoidArray::ElementAt(PRInt32 aIndex) const
1230{
1231 if (HasSingleChild())
1232 {
1233 if (0 == aIndex)
1234 return (void*)GetSingleChild();
1235 }
1236 else
1237 {
1238 nsVoidArray* vector = GetChildVector();
1239 if (vector)
1240 return vector->ElementAt(aIndex);
1241 }
1242
1243 return nsnull;
1244}
1245
1246PRInt32
1247nsSmallVoidArray::IndexOf(void* aPossibleElement) const
1248{
1249 if (HasSingleChild())
1250 {
1251 if (aPossibleElement == (void*)GetSingleChild())
1252 return 0;
1253 }
1254 else
1255 {
1256 nsVoidArray* vector = GetChildVector();
1257 if (vector)
1258 return vector->IndexOf(aPossibleElement);
1259 }
1260
1261 return -1;
1262}
1263
1264PRBool
1265nsSmallVoidArray::InsertElementAt(void* aElement, PRInt32 aIndex)
1266{
1267 nsVoidArray* vector;
1268 NS_ASSERTION(!(PtrBits(aElement) & 0x1),"Attempt to add element with 0x1 bit set to nsSmallVoidArray");
1269 NS_ASSERTION(aElement != nsnull,"Attempt to add a NULL element to an nsSmallVoidArray");
1270
1271 if (HasSingleChild())
1272 {
1273 vector = SwitchToVector();
1274 }
1275 else
1276 {
1277 vector = GetChildVector();
1278 if (!vector)
1279 {
1280 if (0 == aIndex)
1281 {
1282 SetSingleChild(aElement);
1283 return PR_TRUE;
1284 }
1285 return PR_FALSE;
1286 }
1287 }
1288
1289 return vector->InsertElementAt(aElement, aIndex);
1290}
1291
1292PRBool nsSmallVoidArray::InsertElementsAt(const nsVoidArray &other, PRInt32 aIndex)
1293{
1294 nsVoidArray* vector;
1295 PRInt32 count = other.Count();
1296 if (count == 0)
1297 return PR_TRUE;
1298
1299#ifdef DEBUG
1300 for (int i = 0; i < count; i++)
1301 {
1302 NS_ASSERTION(!(PtrBits(other.ElementAt(i)) & 0x1),"Attempt to add element with 0x1 bit set to nsSmallVoidArray");
1303 NS_ASSERTION(other.ElementAt(i) != nsnull,"Attempt to add a NULL element to an nsSmallVoidArray");
1304 }
1305#endif
1306
1307 if (!HasVector())
1308 {
1309 if (HasSingleChild() || count > 1 || aIndex > 0)
1310 {
1311 vector = SwitchToVector();
1312 }
1313 else
1314 {
1315 // count == 1, aIndex == 0, no elements already
1316 SetSingleChild(other[0]);
1317 return PR_TRUE;
1318 }
1319 }
1320 else
1321 {
1322 vector = GetChildVector();
1323 }
1324
1325 if (vector)
1326 {
1327 return vector->InsertElementsAt(other,aIndex);
1328 }
1329 return PR_TRUE;
1330}
1331
1332PRBool
1333nsSmallVoidArray::ReplaceElementAt(void* aElement, PRInt32 aIndex)
1334{
1335 NS_ASSERTION(!(PtrBits(aElement) & 0x1),"Attempt to add element with 0x1 bit set to nsSmallVoidArray");
1336 NS_ASSERTION(aElement != nsnull,"Attempt to add a NULL element to an nsSmallVoidArray");
1337
1338 if (HasSingleChild())
1339 {
1340 if (aIndex == 0)
1341 {
1342 SetSingleChild(aElement);
1343 return PR_TRUE;
1344 }
1345 return PR_FALSE;
1346 }
1347 else
1348 {
1349 nsVoidArray* vector = GetChildVector();
1350 if (vector)
1351 return vector->ReplaceElementAt(aElement, aIndex);
1352
1353 return PR_FALSE;
1354 }
1355}
1356
1357PRBool
1358nsSmallVoidArray::AppendElement(void* aElement)
1359{
1360 NS_ASSERTION(!(PtrBits(aElement) & 0x1),"Attempt to add element with 0x1 bit set to nsSmallVoidArray");
1361 NS_ASSERTION(aElement != nsnull,"Attempt to add a NULL element to an nsSmallVoidArray");
1362
1363 nsVoidArray* vector;
1364 if (HasSingleChild())
1365 {
1366 vector = SwitchToVector();
1367 }
1368 else
1369 {
1370 vector = GetChildVector();
1371 if (!vector)
1372 {
1373 SetSingleChild(aElement);
1374 return PR_TRUE;
1375 }
1376 }
1377
1378 return vector->AppendElement(aElement);
1379}
1380
1381PRBool
1382nsSmallVoidArray::RemoveElement(void* aElement)
1383{
1384 if (HasSingleChild())
1385 {
1386 if (aElement == GetSingleChild())
1387 {
1388 SetSingleChild(nsnull);
1389 return PR_TRUE;
1390 }
1391 }
1392 else
1393 {
1394 nsVoidArray* vector = GetChildVector();
1395 if (vector)
1396 return vector->RemoveElement(aElement);
1397 }
1398
1399 return PR_FALSE;
1400}
1401
1402PRBool
1403nsSmallVoidArray::RemoveElementAt(PRInt32 aIndex)
1404{
1405 if (HasSingleChild())
1406 {
1407 if (0 == aIndex)
1408 {
1409 SetSingleChild(nsnull);
1410 return PR_TRUE;
1411 }
1412 }
1413 else
1414 {
1415 nsVoidArray* vector = GetChildVector();
1416 if (vector)
1417 {
1418 return vector->RemoveElementAt(aIndex);
1419 }
1420 }
1421
1422 return PR_FALSE;
1423}
1424
1425PRBool
1426nsSmallVoidArray::RemoveElementsAt(PRInt32 aIndex, PRInt32 aCount)
1427{
1428 nsVoidArray* vector = GetChildVector();
1429
1430 if (aCount == 0)
1431 return PR_TRUE;
1432
1433 if (HasSingleChild())
1434 {
1435 if (aIndex == 0)
1436 SetSingleChild(nsnull);
1437 return PR_TRUE;
1438 }
1439
1440 if (!vector)
1441 return PR_TRUE;
1442
1443 // complex case; remove entries from an array
1444 return vector->RemoveElementsAt(aIndex,aCount);
1445}
1446
1447void
1448nsSmallVoidArray::Clear()
1449{
1450 if (HasVector())
1451 {
1452 nsVoidArray* vector = GetChildVector();
1453 vector->Clear();
1454 }
1455 else
1456 {
1457 SetSingleChild(nsnull);
1458 }
1459}
1460
1461PRBool
1462nsSmallVoidArray::SizeTo(PRInt32 aMin)
1463{
1464 nsVoidArray* vector;
1465 if (!HasVector())
1466 {
1467 if (aMin <= 1)
1468 return PR_TRUE;
1469 vector = SwitchToVector();
1470 }
1471 else
1472 {
1473 vector = GetChildVector();
1474 if (aMin <= 1)
1475 {
1476 void *prev = nsnull;
1477 if (vector->Count() == 1)
1478 {
1479 prev = vector->ElementAt(0);
1480 }
1481 delete vector;
1482 SetSingleChild(prev);
1483 return PR_TRUE;
1484 }
1485 }
1486 return vector->SizeTo(aMin);
1487}
1488
1489void
1490nsSmallVoidArray::Compact()
1491{
1492 if (!HasSingleChild())
1493 {
1494 nsVoidArray* vector = GetChildVector();
1495 if (vector)
1496 vector->Compact();
1497 }
1498}
1499
1500void
1501nsSmallVoidArray::Sort(nsVoidArrayComparatorFunc aFunc, void* aData)
1502{
1503 if (HasVector())
1504 {
1505 nsVoidArray* vector = GetChildVector();
1506 vector->Sort(aFunc,aData);
1507 }
1508}
1509
1510PRBool
1511nsSmallVoidArray::EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData)
1512{
1513 if (HasVector())
1514 {
1515 nsVoidArray* vector = GetChildVector();
1516 return vector->EnumerateForwards(aFunc,aData);
1517 }
1518 if (HasSingleChild())
1519 {
1520 return (*aFunc)(GetSingleChild(), aData);
1521 }
1522 return PR_TRUE;
1523}
1524
1525PRBool
1526nsSmallVoidArray::EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData)
1527{
1528 if (HasVector())
1529 {
1530 nsVoidArray* vector = GetChildVector();
1531 return vector->EnumerateBackwards(aFunc,aData);
1532 }
1533 if (HasSingleChild())
1534 {
1535 return (*aFunc)(GetSingleChild(), aData);
1536 }
1537 return PR_TRUE;
1538}
1539
1540void
1541nsSmallVoidArray::SetSingleChild(void* aChild)
1542{
1543 if (aChild)
1544 mChildren = (void*)(PtrBits(aChild) | 0x1);
1545 else
1546 mChildren = nsnull;
1547}
1548
1549nsVoidArray*
1550nsSmallVoidArray::SwitchToVector()
1551{
1552 void* child = GetSingleChild();
1553
1554 mChildren = (void*)new nsAutoVoidArray();
1555 nsVoidArray* vector = GetChildVector();
1556 if (vector && child)
1557 vector->AppendElement(child);
1558
1559 return vector;
1560}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette