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
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/
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
15 * The Original Code is mozilla.org code.
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.
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.
36 * ***** END LICENSE BLOCK ***** */
40 #include "nsVoidArray.h"
41 #include "nsQuickSort.h"
43 #include "nsISupportsImpl.h" // for nsTraceRefcnt
44 #include "nsCRTGlue.h"
47 * Grow the array by at least this many elements at a time.
49 static const PRInt32 kMinGrowArrayBy
= 8;
50 static const PRInt32 kMaxGrowArrayBy
= 1024;
51 static const PRInt32 kAutoClearCompactSizeFactor
= 4;
54 * This is the threshold (in bytes) of the mImpl struct, past which
55 * we'll force the array to grow geometrically
57 static const PRInt32 kLinearThreshold
= 24 * sizeof(void *);
60 * Compute the number of bytes requires for the mImpl struct that will
63 #define SIZEOF_IMPL(n_) (sizeof(Impl) + sizeof(void *) * ((n_) - 1))
67 * Compute the number of elements that an mImpl struct of |n| bytes
70 #define CAPACITYOF_IMPL(n_) ((((n_) - sizeof(Impl)) / sizeof(void *)) + 1)
82 static int sizesUsed
; // number of the elements of the arrays used
83 static int sizesAlloced
[MAXVOID
]; // sizes of the allocations. sorted
84 static int NumberOfSize
[MAXVOID
]; // number of this allocation size (1 per array)
85 static int AllocedOfSize
[MAXVOID
]; // number of this allocation size (each size for array used)
86 static int MaxAuto
[MAXVOID
]; // AutoArrays that maxed out at this size
87 static int GrowInPlace
[MAXVOID
]; // arrays this size that grew in-place via realloc
89 // these are per-allocation
90 static int MaxElements
[2000]; // # of arrays that maxed out at each size.
93 #define ADD_TO_STATS(x,size) do {int i; for (i = 0; i < sizesUsed; i++) \
95 if (sizesAlloced[i] == (int)(size)) \
96 { ((x)[i])++; break; } \
98 if (i >= sizesUsed && sizesUsed < MAXVOID) \
99 { sizesAlloced[sizesUsed] = (size); \
100 ((x)[sizesUsed++])++; break; \
104 #define SUB_FROM_STATS(x,size) do {int i; for (i = 0; i < sizesUsed; i++) \
106 if (sizesAlloced[i] == (int)(size)) \
107 { ((x)[i])--; break; } \
112 VoidStats::VoidStats()
118 VoidStats::~VoidStats()
121 for (i
= 0; i
< sizesUsed
; i
++)
123 printf("Size %d:\n",sizesAlloced
[i
]);
124 printf("\tNumber of VoidArrays this size (max): %d\n",NumberOfSize
[i
]-MaxAuto
[i
]);
125 printf("\tNumber of AutoVoidArrays this size (max): %d\n",MaxAuto
[i
]);
126 printf("\tNumber of allocations this size (total): %d\n",AllocedOfSize
[i
]);
127 printf("\tNumber of GrowsInPlace this size (total): %d\n",GrowInPlace
[i
]);
129 printf("Max Size of VoidArray:\n");
130 for (i
= 0; i
< (int)(sizeof(MaxElements
)/sizeof(MaxElements
[0])); i
++)
133 printf("\t%d: %d\n",i
,MaxElements
[i
]);
137 // Just so constructor/destructor's get called
138 VoidStats gVoidStats
;
142 nsVoidArray::SetArray(Impl
*newImpl
, PRInt32 aSize
, PRInt32 aCount
,
143 PRBool aOwner
, PRBool aHasAuto
)
145 // old mImpl has been realloced and so we don't free/delete it
146 NS_PRECONDITION(newImpl
, "can't set size");
148 mImpl
->mCount
= aCount
;
149 mImpl
->mBits
= static_cast<PRUint32
>(aSize
& kArraySizeMask
) |
150 (aOwner
? kArrayOwnerMask
: 0) |
151 (aHasAuto
? kArrayHasAutoBufferMask
: 0);
154 // This does all allocation/reallocation of the array.
155 // It also will compact down to N - good for things that might grow a lot
156 // at times, but usually are smaller, like JS deferred GC releases.
157 PRBool
nsVoidArray::SizeTo(PRInt32 aSize
)
159 PRUint32 oldsize
= GetArraySize();
160 PRBool isOwner
= IsArrayOwner();
161 PRBool hasAuto
= HasAutoBuffer();
163 if (aSize
== (PRInt32
) oldsize
)
164 return PR_TRUE
; // no change
168 // free the array if allocated
173 free(reinterpret_cast<char *>(mImpl
));
175 static_cast<nsAutoVoidArray
*>(this)->ResetToAutoBuffer();
183 mImpl
->mCount
= 0; // nsAutoVoidArray
189 if (mImpl
&& isOwner
)
191 // We currently own an array impl. Resize it appropriately.
192 if (aSize
< mImpl
->mCount
)
194 // XXX Note: we could also just resize to mCount
195 return PR_TRUE
; // can't make it that small, ignore request
198 char* bytes
= (char *) realloc(mImpl
,SIZEOF_IMPL(aSize
));
199 Impl
* newImpl
= reinterpret_cast<Impl
*>(bytes
);
204 if (mImpl
== newImpl
)
205 ADD_TO_STATS(GrowInPlace
,oldsize
);
206 ADD_TO_STATS(AllocedOfSize
,SIZEOF_IMPL(aSize
));
207 if (aSize
> mMaxSize
)
209 ADD_TO_STATS(NumberOfSize
,SIZEOF_IMPL(aSize
));
211 SUB_FROM_STATS(NumberOfSize
,oldsize
);
215 ADD_TO_STATS(MaxAuto
,SIZEOF_IMPL(aSize
));
216 SUB_FROM_STATS(MaxAuto
,oldsize
);
220 SetArray(newImpl
, aSize
, newImpl
->mCount
, PR_TRUE
, hasAuto
);
224 if ((PRUint32
) aSize
< oldsize
) {
225 // No point in allocating if it won't free the current Impl anyway.
229 // just allocate an array
230 // allocate the exact size requested
231 char* bytes
= (char *) malloc(SIZEOF_IMPL(aSize
));
232 Impl
* newImpl
= reinterpret_cast<Impl
*>(bytes
);
237 ADD_TO_STATS(AllocedOfSize
,SIZEOF_IMPL(aSize
));
238 if (aSize
> mMaxSize
)
240 ADD_TO_STATS(NumberOfSize
,SIZEOF_IMPL(aSize
));
241 if (oldsize
&& !mImpl
)
242 SUB_FROM_STATS(NumberOfSize
,oldsize
);
249 ADD_TO_STATS(MaxAuto
,SIZEOF_IMPL(aSize
));
250 SUB_FROM_STATS(MaxAuto
,0);
251 SUB_FROM_STATS(NumberOfSize
,0);
254 // We must be growing an nsAutoVoidArray - copy since we didn't
256 memcpy(newImpl
->mArray
, mImpl
->mArray
,
257 mImpl
->mCount
* sizeof(mImpl
->mArray
[0]));
260 SetArray(newImpl
, aSize
, mImpl
? mImpl
->mCount
: 0, PR_TRUE
, hasAuto
);
261 // no memset; handled later in ReplaceElementAt if needed
265 PRBool
nsVoidArray::GrowArrayBy(PRInt32 aGrowBy
)
267 // We have to grow the array. Grow by kMinGrowArrayBy slots if we're
268 // smaller than kLinearThreshold bytes, or a power of two if we're
269 // larger. This is much more efficient with most memory allocators,
270 // especially if it's very large, or of the allocator is binned.
271 if (aGrowBy
< kMinGrowArrayBy
)
272 aGrowBy
= kMinGrowArrayBy
;
274 PRUint32 newCapacity
= GetArraySize() + aGrowBy
; // Minimum increase
275 PRUint32 newSize
= SIZEOF_IMPL(newCapacity
);
277 if (newSize
>= (PRUint32
) kLinearThreshold
)
279 // newCount includes enough space for at least kMinGrowArrayBy new
280 // slots. Select the next power-of-two size in bytes above or
282 // Also, limit the increase in size to about a VM page or two.
283 if (GetArraySize() >= kMaxGrowArrayBy
)
285 newCapacity
= GetArraySize() + PR_MAX(kMaxGrowArrayBy
,aGrowBy
);
286 newSize
= SIZEOF_IMPL(newCapacity
);
290 PR_CEILING_LOG2(newSize
, newSize
);
291 newCapacity
= CAPACITYOF_IMPL(PR_BIT(newSize
));
294 // frees old mImpl IF this succeeds
295 if (!SizeTo(newCapacity
))
301 nsVoidArray::nsVoidArray()
304 MOZ_COUNT_CTOR(nsVoidArray
);
309 ADD_TO_STATS(NumberOfSize
,0);
314 nsVoidArray::nsVoidArray(PRInt32 aCount
)
317 MOZ_COUNT_CTOR(nsVoidArray
);
327 nsVoidArray
& nsVoidArray::operator=(const nsVoidArray
& other
)
329 PRInt32 otherCount
= other
.Count();
330 PRInt32 maxCount
= GetArraySize();
333 if (otherCount
> maxCount
)
335 // frees old mImpl IF this succeeds
336 if (!GrowArrayBy(otherCount
-maxCount
))
337 return *this; // XXX The allocation failed - don't do anything
339 memcpy(mImpl
->mArray
, other
.mImpl
->mArray
, otherCount
* sizeof(mImpl
->mArray
[0]));
340 mImpl
->mCount
= otherCount
;
344 // the old array can hold the new array
345 memcpy(mImpl
->mArray
, other
.mImpl
->mArray
, otherCount
* sizeof(mImpl
->mArray
[0]));
346 mImpl
->mCount
= otherCount
;
347 // if it shrank a lot, compact it anyways
348 if ((otherCount
*2) < maxCount
&& maxCount
> 100)
350 Compact(); // shrank by at least 50 entries
354 if (mImpl
->mCount
> mMaxCount
&&
355 mImpl
->mCount
< (PRInt32
)(sizeof(MaxElements
)/sizeof(MaxElements
[0])))
357 MaxElements
[mImpl
->mCount
]++;
358 MaxElements
[mMaxCount
]--;
359 mMaxCount
= mImpl
->mCount
;
365 // Why do we drop the buffer here when we don't in Clear()?
372 nsVoidArray::~nsVoidArray()
374 MOZ_COUNT_DTOR(nsVoidArray
);
375 if (mImpl
&& IsArrayOwner())
376 free(reinterpret_cast<char*>(mImpl
));
379 PRInt32
nsVoidArray::IndexOf(void* aPossibleElement
) const
383 void** ap
= mImpl
->mArray
;
384 void** end
= ap
+ mImpl
->mCount
;
387 if (*ap
== aPossibleElement
)
389 return ap
- mImpl
->mArray
;
397 PRBool
nsVoidArray::InsertElementAt(void* aElement
, PRInt32 aIndex
)
399 PRInt32 oldCount
= Count();
400 NS_ASSERTION(aIndex
>= 0,"InsertElementAt(negative index)");
401 if (PRUint32(aIndex
) > PRUint32(oldCount
))
403 // An invalid index causes the insertion to fail
404 // Invalid indexes are ones that add more than one entry to the
405 // array (i.e., they can append).
409 if (oldCount
>= GetArraySize())
414 // else the array is already large enough
416 PRInt32 slide
= oldCount
- aIndex
;
419 // Slide data over to make room for the insertion
420 memmove(mImpl
->mArray
+ aIndex
+ 1, mImpl
->mArray
+ aIndex
,
421 slide
* sizeof(mImpl
->mArray
[0]));
424 mImpl
->mArray
[aIndex
] = aElement
;
428 if (mImpl
->mCount
> mMaxCount
&&
429 mImpl
->mCount
< (PRInt32
)(sizeof(MaxElements
)/sizeof(MaxElements
[0])))
431 MaxElements
[mImpl
->mCount
]++;
432 MaxElements
[mMaxCount
]--;
433 mMaxCount
= mImpl
->mCount
;
440 PRBool
nsVoidArray::InsertElementsAt(const nsVoidArray
& other
, PRInt32 aIndex
)
442 PRInt32 oldCount
= Count();
443 PRInt32 otherCount
= other
.Count();
445 NS_ASSERTION(aIndex
>= 0,"InsertElementsAt(negative index)");
446 if (PRUint32(aIndex
) > PRUint32(oldCount
))
448 // An invalid index causes the insertion to fail
449 // Invalid indexes are ones that are more than one entry past the end of
450 // the array (i.e., they can append).
454 if (oldCount
+ otherCount
> GetArraySize())
456 if (!GrowArrayBy(otherCount
))
459 // else the array is already large enough
461 PRInt32 slide
= oldCount
- aIndex
;
464 // Slide data over to make room for the insertion
465 memmove(mImpl
->mArray
+ aIndex
+ otherCount
, mImpl
->mArray
+ aIndex
,
466 slide
* sizeof(mImpl
->mArray
[0]));
469 for (PRInt32 i
= 0; i
< otherCount
; i
++)
471 // copy all the elements (destroys aIndex)
472 mImpl
->mArray
[aIndex
++] = other
.mImpl
->mArray
[i
];
477 if (mImpl
->mCount
> mMaxCount
&&
478 mImpl
->mCount
< (PRInt32
)(sizeof(MaxElements
)/sizeof(MaxElements
[0])))
480 MaxElements
[mImpl
->mCount
]++;
481 MaxElements
[mMaxCount
]--;
482 mMaxCount
= mImpl
->mCount
;
489 PRBool
nsVoidArray::ReplaceElementAt(void* aElement
, PRInt32 aIndex
)
491 NS_ASSERTION(aIndex
>= 0,"ReplaceElementAt(negative index)");
495 // Unlike InsertElementAt, ReplaceElementAt can implicitly add more
496 // than just the one element to the array.
497 if (PRUint32(aIndex
) >= PRUint32(GetArraySize()))
499 PRInt32 oldCount
= Count();
500 PRInt32 requestedCount
= aIndex
+ 1;
501 PRInt32 growDelta
= requestedCount
- oldCount
;
503 // frees old mImpl IF this succeeds
504 if (!GrowArrayBy(growDelta
))
508 mImpl
->mArray
[aIndex
] = aElement
;
509 if (aIndex
>= mImpl
->mCount
)
511 // Make sure that any entries implicitly added to the array by this
512 // ReplaceElementAt are cleared to 0. Some users of this assume that.
513 // This code means we don't have to memset when we allocate an array.
514 if (aIndex
> mImpl
->mCount
) // note: not >=
516 // For example, if mCount is 2, and we do a ReplaceElementAt for
517 // element[5], then we need to set three entries ([2], [3], and [4])
519 memset(&mImpl
->mArray
[mImpl
->mCount
], 0,
520 (aIndex
- mImpl
->mCount
) * sizeof(mImpl
->mArray
[0]));
523 mImpl
->mCount
= aIndex
+ 1;
526 if (mImpl
->mCount
> mMaxCount
&&
527 mImpl
->mCount
< (PRInt32
)(sizeof(MaxElements
)/sizeof(MaxElements
[0])))
529 MaxElements
[mImpl
->mCount
]++;
530 MaxElements
[mMaxCount
]--;
531 mMaxCount
= mImpl
->mCount
;
539 // useful for doing LRU arrays
540 PRBool
nsVoidArray::MoveElement(PRInt32 aFrom
, PRInt32 aTo
)
547 NS_ASSERTION(aTo
>= 0 && aFrom
>= 0,"MoveElement(negative index)");
548 if (aTo
>= Count() || aFrom
>= Count())
550 // can't extend the array when moving an element. Also catches mImpl = null
553 tempElement
= mImpl
->mArray
[aFrom
];
557 // Moving one element closer to the head; the elements inbetween move down
558 memmove(mImpl
->mArray
+ aTo
+ 1, mImpl
->mArray
+ aTo
,
559 (aFrom
-aTo
) * sizeof(mImpl
->mArray
[0]));
560 mImpl
->mArray
[aTo
] = tempElement
;
562 else // already handled aFrom == aTo
564 // Moving one element closer to the tail; the elements inbetween move up
565 memmove(mImpl
->mArray
+ aFrom
, mImpl
->mArray
+ aFrom
+ 1,
566 (aTo
-aFrom
) * sizeof(mImpl
->mArray
[0]));
567 mImpl
->mArray
[aTo
] = tempElement
;
573 PRBool
nsVoidArray::RemoveElementsAt(PRInt32 aIndex
, PRInt32 aCount
)
575 PRInt32 oldCount
= Count();
576 NS_ASSERTION(aIndex
>= 0,"RemoveElementsAt(negative index)");
577 if (PRUint32(aIndex
) >= PRUint32(oldCount
))
579 // An invalid index causes the replace to fail
582 // Limit to available entries starting at aIndex
583 if (aCount
+ aIndex
> oldCount
)
584 aCount
= oldCount
- aIndex
;
586 // We don't need to move any elements if we're removing the
587 // last element in the array
588 if (aIndex
< (oldCount
- aCount
))
590 memmove(mImpl
->mArray
+ aIndex
, mImpl
->mArray
+ aIndex
+ aCount
,
591 (oldCount
- (aIndex
+ aCount
)) * sizeof(mImpl
->mArray
[0]));
594 mImpl
->mCount
-= aCount
;
598 PRBool
nsVoidArray::RemoveElement(void* aElement
)
600 PRInt32 theIndex
= IndexOf(aElement
);
602 return RemoveElementAt(theIndex
);
607 void nsVoidArray::Clear()
612 // We don't have to free on Clear, but if we have a built-in buffer,
613 // it's worth considering.
614 if (HasAutoBuffer() && IsArrayOwner() &&
615 GetArraySize() > kAutoClearCompactSizeFactor
* kAutoBufSize
) {
621 void nsVoidArray::Compact()
625 // XXX NOTE: this is quite inefficient in many cases if we're only
626 // compacting by a little, but some callers care more about memory use.
627 PRInt32 count
= Count();
628 if (HasAutoBuffer() && count
<= kAutoBufSize
)
630 Impl
* oldImpl
= mImpl
;
631 static_cast<nsAutoVoidArray
*>(this)->ResetToAutoBuffer();
632 memcpy(mImpl
->mArray
, oldImpl
->mArray
,
633 count
* sizeof(mImpl
->mArray
[0]));
634 free(reinterpret_cast<char *>(oldImpl
));
636 else if (GetArraySize() > count
)
643 // Needed because we want to pass the pointer to the item in the array
644 // to the comparator function, not a pointer to the pointer in the array.
645 struct VoidArrayComparatorContext
{
646 nsVoidArrayComparatorFunc mComparatorFunc
;
650 PR_STATIC_CALLBACK(int)
651 VoidArrayComparator(const void* aElement1
, const void* aElement2
, void* aData
)
653 VoidArrayComparatorContext
* ctx
= static_cast<VoidArrayComparatorContext
*>(aData
);
654 return (*ctx
->mComparatorFunc
)(*static_cast<void* const*>(aElement1
),
655 *static_cast<void* const*>(aElement2
),
659 void nsVoidArray::Sort(nsVoidArrayComparatorFunc aFunc
, void* aData
)
661 if (mImpl
&& mImpl
->mCount
> 1)
663 VoidArrayComparatorContext ctx
= {aFunc
, aData
};
664 NS_QuickSort(mImpl
->mArray
, mImpl
->mCount
, sizeof(mImpl
->mArray
[0]),
665 VoidArrayComparator
, &ctx
);
669 PRBool
nsVoidArray::EnumerateForwards(nsVoidArrayEnumFunc aFunc
, void* aData
)
672 PRBool running
= PR_TRUE
;
676 while (running
&& (++index
< mImpl
->mCount
))
678 running
= (*aFunc
)(mImpl
->mArray
[index
], aData
);
684 PRBool
nsVoidArray::EnumerateBackwards(nsVoidArrayEnumFunc aFunc
, void* aData
)
686 PRBool running
= PR_TRUE
;
690 PRInt32 index
= Count();
691 while (running
&& (0 <= --index
))
693 running
= (*aFunc
)(mImpl
->mArray
[index
], aData
);
699 //----------------------------------------------------------------
702 nsAutoVoidArray::nsAutoVoidArray()
705 // Don't need to clear it. Some users just call ReplaceElementAt(),
706 // but we'll clear it at that time if needed to save CPU cycles.
709 ADD_TO_STATS(MaxAuto
,0);
714 //----------------------------------------------------------------
717 nsStringArray::nsStringArray(void)
722 nsStringArray::nsStringArray(PRInt32 aCount
)
723 : nsVoidArray(aCount
)
727 nsStringArray::~nsStringArray(void)
733 nsStringArray::operator=(const nsStringArray
& other
)
736 nsVoidArray::operator=(other
);
738 // Now copy the strings
739 PRInt32 count
= Count();
740 for (PRInt32 i
= 0; i
< count
; ++i
)
742 nsString
* oldString
= static_cast<nsString
*>(other
.ElementAt(i
));
743 nsString
* newString
= new nsString(*oldString
);
749 mImpl
->mArray
[i
] = newString
;
756 nsStringArray::StringAt(PRInt32 aIndex
, nsAString
& aString
) const
758 nsString
* string
= static_cast<nsString
*>(nsVoidArray::ElementAt(aIndex
));
759 if (nsnull
!= string
)
761 aString
.Assign(*string
);
770 nsStringArray::StringAt(PRInt32 aIndex
) const
772 return static_cast<nsString
*>(nsVoidArray::ElementAt(aIndex
));
776 nsStringArray::IndexOf(const nsAString
& aPossibleString
) const
780 void** ap
= mImpl
->mArray
;
781 void** end
= ap
+ mImpl
->mCount
;
784 nsString
* string
= static_cast<nsString
*>(*ap
);
785 if (string
->Equals(aPossibleString
))
787 return ap
- mImpl
->mArray
;
796 nsStringArray::InsertStringAt(const nsAString
& aString
, PRInt32 aIndex
)
798 nsString
* string
= new nsString(aString
);
801 if (nsVoidArray::InsertElementAt(string
, aIndex
))
809 nsStringArray::ReplaceStringAt(const nsAString
& aString
,
812 nsString
* string
= static_cast<nsString
*>(nsVoidArray::ElementAt(aIndex
));
813 if (nsnull
!= string
)
822 nsStringArray::RemoveString(const nsAString
& aString
)
824 PRInt32 index
= IndexOf(aString
);
827 return RemoveStringAt(index
);
832 PRBool
nsStringArray::RemoveStringAt(PRInt32 aIndex
)
834 nsString
* string
= StringAt(aIndex
);
835 if (nsnull
!= string
)
837 nsVoidArray::RemoveElementAt(aIndex
);
845 nsStringArray::Clear(void)
847 PRInt32 index
= Count();
850 nsString
* string
= static_cast<nsString
*>(mImpl
->mArray
[index
]);
853 nsVoidArray::Clear();
856 PR_STATIC_CALLBACK(int)
857 CompareString(const nsString
* aString1
, const nsString
* aString2
, void*)
859 #ifdef MOZILLA_INTERNAL_API
860 return Compare(*aString1
, *aString2
);
864 PRUint32 len1
= NS_StringGetData(*aString1
, &s1
);
865 PRUint32 len2
= NS_StringGetData(*aString2
, &s2
);
866 int r
= memcmp(s1
, s2
, sizeof(PRUnichar
) * PR_MIN(len1
, len2
));
880 void nsStringArray::Sort(void)
882 Sort(CompareString
, nsnull
);
885 void nsStringArray::Sort(nsStringArrayComparatorFunc aFunc
, void* aData
)
887 nsVoidArray::Sort(reinterpret_cast<nsVoidArrayComparatorFunc
>(aFunc
), aData
);
891 nsStringArray::EnumerateForwards(nsStringArrayEnumFunc aFunc
, void* aData
)
894 PRBool running
= PR_TRUE
;
898 while (running
&& (++index
< mImpl
->mCount
))
900 running
= (*aFunc
)(*static_cast<nsString
*>(mImpl
->mArray
[index
]), aData
);
907 nsStringArray::EnumerateBackwards(nsStringArrayEnumFunc aFunc
, void* aData
)
909 PRInt32 index
= Count();
910 PRBool running
= PR_TRUE
;
914 while (running
&& (0 <= --index
))
916 running
= (*aFunc
)(*static_cast<nsString
*>(mImpl
->mArray
[index
]), aData
);
924 //----------------------------------------------------------------
927 nsCStringArray::nsCStringArray(void)
932 // Parses a given string using the delimiter passed in and appends items
933 // parsed to the array.
935 nsCStringArray::ParseString(const char* string
, const char* delimiter
)
937 if (string
&& *string
&& delimiter
&& *delimiter
) {
938 char *rest
= strdup(string
);
942 char *token
= NS_strtok(delimiter
, &newStr
);
944 PRInt32 count
= Count();
947 /* calling AppendElement(void*) to avoid extra nsCString copy */
948 nsCString
*cstring
= new nsCString(token
);
949 if (cstring
&& !AppendElement(cstring
)) {
950 // AppendElement failed, release and null cstring so we fall
951 // through to the case below.
956 // We've run out of memory. Remove all newly appended elements from
957 // our array so we don't leave ourselves in a partially added state.
958 // When we return, the array will be precisely as it was when this
959 // function was called.
960 RemoveElementsAt(count
, Count() - count
);
965 token
= NS_strtok(delimiter
, &newStr
);
972 nsCStringArray::nsCStringArray(PRInt32 aCount
)
973 : nsVoidArray(aCount
)
977 nsCStringArray::~nsCStringArray(void)
983 nsCStringArray::operator=(const nsCStringArray
& other
)
986 nsVoidArray::operator=(other
);
988 // Now copy the strings
989 PRInt32 count
= Count();
990 for (PRInt32 i
= 0; i
< count
; ++i
)
992 nsCString
* oldString
= static_cast<nsCString
*>(other
.ElementAt(i
));
993 nsCString
* newString
= new nsCString(*oldString
);
999 mImpl
->mArray
[i
] = newString
;
1006 nsCStringArray::CStringAt(PRInt32 aIndex
, nsACString
& aCString
) const
1008 nsCString
* string
= static_cast<nsCString
*>(nsVoidArray::ElementAt(aIndex
));
1009 if (nsnull
!= string
)
1015 aCString
.Truncate();
1020 nsCStringArray::CStringAt(PRInt32 aIndex
) const
1022 return static_cast<nsCString
*>(nsVoidArray::ElementAt(aIndex
));
1026 nsCStringArray::IndexOf(const nsACString
& aPossibleString
) const
1030 void** ap
= mImpl
->mArray
;
1031 void** end
= ap
+ mImpl
->mCount
;
1034 nsCString
* string
= static_cast<nsCString
*>(*ap
);
1035 if (string
->Equals(aPossibleString
))
1037 return ap
- mImpl
->mArray
;
1045 #ifdef MOZILLA_INTERNAL_API
1047 nsCStringArray::IndexOfIgnoreCase(const nsACString
& aPossibleString
) const
1051 void** ap
= mImpl
->mArray
;
1052 void** end
= ap
+ mImpl
->mCount
;
1055 nsCString
* string
= static_cast<nsCString
*>(*ap
);
1056 if (string
->Equals(aPossibleString
, nsCaseInsensitiveCStringComparator()))
1058 return ap
- mImpl
->mArray
;
1068 nsCStringArray::InsertCStringAt(const nsACString
& aCString
, PRInt32 aIndex
)
1070 nsCString
* string
= new nsCString(aCString
);
1073 if (nsVoidArray::InsertElementAt(string
, aIndex
))
1081 nsCStringArray::ReplaceCStringAt(const nsACString
& aCString
, PRInt32 aIndex
)
1083 nsCString
* string
= static_cast<nsCString
*>(nsVoidArray::ElementAt(aIndex
));
1084 if (nsnull
!= string
)
1093 nsCStringArray::RemoveCString(const nsACString
& aCString
)
1095 PRInt32 index
= IndexOf(aCString
);
1098 return RemoveCStringAt(index
);
1103 #ifdef MOZILLA_INTERNAL_API
1105 nsCStringArray::RemoveCStringIgnoreCase(const nsACString
& aCString
)
1107 PRInt32 index
= IndexOfIgnoreCase(aCString
);
1110 return RemoveCStringAt(index
);
1116 PRBool
nsCStringArray::RemoveCStringAt(PRInt32 aIndex
)
1118 nsCString
* string
= CStringAt(aIndex
);
1119 if (nsnull
!= string
)
1121 nsVoidArray::RemoveElementAt(aIndex
);
1129 nsCStringArray::Clear(void)
1131 PRInt32 index
= Count();
1132 while (0 <= --index
)
1134 nsCString
* string
= static_cast<nsCString
*>(mImpl
->mArray
[index
]);
1137 nsVoidArray::Clear();
1140 PR_STATIC_CALLBACK(int)
1141 CompareCString(const nsCString
* aCString1
, const nsCString
* aCString2
, void*)
1143 #ifdef MOZILLA_INTERNAL_API
1144 return Compare(*aCString1
, *aCString2
);
1148 PRUint32 len1
= NS_CStringGetData(*aCString1
, &s1
);
1149 PRUint32 len2
= NS_CStringGetData(*aCString2
, &s2
);
1150 int r
= memcmp(s1
, s2
, PR_MIN(len1
, len2
));
1164 #ifdef MOZILLA_INTERNAL_API
1165 PR_STATIC_CALLBACK(int)
1166 CompareCStringIgnoreCase(const nsCString
* aCString1
, const nsCString
* aCString2
, void*)
1168 return Compare(*aCString1
, *aCString2
, nsCaseInsensitiveCStringComparator());
1172 void nsCStringArray::Sort(void)
1174 Sort(CompareCString
, nsnull
);
1177 #ifdef MOZILLA_INTERNAL_API
1178 void nsCStringArray::SortIgnoreCase(void)
1180 Sort(CompareCStringIgnoreCase
, nsnull
);
1184 void nsCStringArray::Sort(nsCStringArrayComparatorFunc aFunc
, void* aData
)
1186 nsVoidArray::Sort(reinterpret_cast<nsVoidArrayComparatorFunc
>(aFunc
), aData
);
1190 nsCStringArray::EnumerateForwards(nsCStringArrayEnumFunc aFunc
, void* aData
)
1192 PRBool running
= PR_TRUE
;
1197 while (running
&& (++index
< mImpl
->mCount
))
1199 running
= (*aFunc
)(*static_cast<nsCString
*>(mImpl
->mArray
[index
]), aData
);
1206 nsCStringArray::EnumerateBackwards(nsCStringArrayEnumFunc aFunc
, void* aData
)
1208 PRBool running
= PR_TRUE
;
1212 PRInt32 index
= Count();
1213 while (running
&& (0 <= --index
))
1215 running
= (*aFunc
)(*static_cast<nsCString
*>(mImpl
->mArray
[index
]), aData
);
1222 //----------------------------------------------------------------------
1223 // NOTE: nsSmallVoidArray elements MUST all have the low bit as 0.
1224 // This means that normally it's only used for pointers, and in particular
1225 // structures or objects.
1226 nsSmallVoidArray::~nsSmallVoidArray()
1230 // Have to null out mImpl before the nsVoidArray dtor runs.
1236 nsSmallVoidArray::operator=(nsSmallVoidArray
& other
)
1238 PRInt32 count
= other
.Count();
1245 AppendElement(other
.ElementAt(0));
1248 if (GetArraySize() >= count
|| SizeTo(count
)) {
1249 *AsArray() = *other
.AsArray();
1257 nsSmallVoidArray::GetArraySize() const
1263 return AsArray()->GetArraySize();
1267 nsSmallVoidArray::Count() const
1273 return AsArray()->Count();
1277 nsSmallVoidArray::FastElementAt(PRInt32 aIndex
) const
1279 NS_ASSERTION(0 <= aIndex
&& aIndex
< Count(), "nsSmallVoidArray::FastElementAt: index out of range");
1285 return AsArray()->FastElementAt(aIndex
);
1289 nsSmallVoidArray::IndexOf(void* aPossibleElement
) const
1292 return aPossibleElement
== GetSingle() ? 0 : -1;
1295 return AsArray()->IndexOf(aPossibleElement
);
1299 nsSmallVoidArray::InsertElementAt(void* aElement
, PRInt32 aIndex
)
1301 NS_ASSERTION(!(NS_PTR_TO_INT32(aElement
) & 0x1),
1302 "Attempt to add element with 0x1 bit set to nsSmallVoidArray");
1304 if (aIndex
== 0 && IsEmpty()) {
1305 SetSingle(aElement
);
1310 if (!EnsureArray()) {
1314 return AsArray()->InsertElementAt(aElement
, aIndex
);
1317 PRBool
nsSmallVoidArray::InsertElementsAt(const nsVoidArray
&aOther
, PRInt32 aIndex
)
1320 for (int i
= 0; i
< aOther
.Count(); i
++) {
1321 NS_ASSERTION(!(NS_PTR_TO_INT32(aOther
.ElementAt(i
)) & 0x1),
1322 "Attempt to add element with 0x1 bit set to nsSmallVoidArray");
1326 if (aIndex
== 0 && IsEmpty() && aOther
.Count() == 1) {
1327 SetSingle(aOther
.FastElementAt(0));
1332 if (!EnsureArray()) {
1336 return AsArray()->InsertElementsAt(aOther
, aIndex
);
1340 nsSmallVoidArray::ReplaceElementAt(void* aElement
, PRInt32 aIndex
)
1342 NS_ASSERTION(!(NS_PTR_TO_INT32(aElement
) & 0x1),
1343 "Attempt to add element with 0x1 bit set to nsSmallVoidArray");
1345 if (aIndex
== 0 && (IsEmpty() || HasSingle())) {
1346 SetSingle(aElement
);
1351 if (!EnsureArray()) {
1355 return AsArray()->ReplaceElementAt(aElement
, aIndex
);
1359 nsSmallVoidArray::AppendElement(void* aElement
)
1361 NS_ASSERTION(!(NS_PTR_TO_INT32(aElement
) & 0x1),
1362 "Attempt to add element with 0x1 bit set to nsSmallVoidArray");
1365 SetSingle(aElement
);
1370 if (!EnsureArray()) {
1374 return AsArray()->AppendElement(aElement
);
1378 nsSmallVoidArray::RemoveElement(void* aElement
)
1381 if (aElement
== GetSingle()) {
1389 return AsArray()->RemoveElement(aElement
);
1393 nsSmallVoidArray::RemoveElementAt(PRInt32 aIndex
)
1405 return AsArray()->RemoveElementAt(aIndex
);
1409 nsSmallVoidArray::RemoveElementsAt(PRInt32 aIndex
, PRInt32 aCount
)
1423 return AsArray()->RemoveElementsAt(aIndex
, aCount
);
1427 nsSmallVoidArray::Clear()
1438 nsSmallVoidArray::SizeTo(PRInt32 aMin
)
1441 return AsArray()->SizeTo(aMin
);
1454 void* single
= GetSingle();
1456 if (!AsArray()->SizeTo(aMin
)) {
1462 AsArray()->AppendElement(single
);
1468 nsSmallVoidArray::Compact()
1471 AsArray()->Compact();
1476 nsSmallVoidArray::Sort(nsVoidArrayComparatorFunc aFunc
, void* aData
)
1479 AsArray()->Sort(aFunc
,aData
);
1484 nsSmallVoidArray::EnumerateForwards(nsVoidArrayEnumFunc aFunc
, void* aData
)
1487 return (*aFunc
)(GetSingle(), aData
);
1489 return AsArray()->EnumerateForwards(aFunc
,aData
);
1493 nsSmallVoidArray::EnumerateBackwards(nsVoidArrayEnumFunc aFunc
, void* aData
)
1496 return (*aFunc
)(GetSingle(), aData
);
1498 return AsArray()->EnumerateBackwards(aFunc
,aData
);
1502 nsSmallVoidArray::EnsureArray()
1508 void* single
= GetSingle();
1510 if (!AsArray()->AppendElement(single
)) {