1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is C++ array template.
17 : *
18 : * The Initial Developer of the Original Code is Google Inc.
19 : * Portions created by the Initial Developer are Copyright (C) 2005
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Darin Fisher <darin@meer.net>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #ifndef nsTArray_h__
40 : #define nsTArray_h__
41 :
42 : #include "mozilla/Assertions.h"
43 : #include "mozilla/Util.h"
44 :
45 : #include <string.h>
46 :
47 : #include "prtypes.h"
48 : #include "nsAlgorithm.h"
49 : #include "nscore.h"
50 : #include "nsQuickSort.h"
51 : #include "nsDebug.h"
52 : #include "nsTraceRefcnt.h"
53 : #include NEW_H
54 :
55 : //
56 : // NB: nsTArray assumes that your "T" can be memmove()d. This is in
57 : // contrast to STL containers, which follow C++
58 : // construction/destruction rules.
59 : //
60 : // Don't use nsTArray if your "T" can't be memmove()d correctly.
61 : //
62 :
63 : //
64 : // nsTArray*Allocators must all use the same |free()|, to allow
65 : // swapping between fallible and infallible variants. (NS_Free() and
66 : // moz_free() end up calling the same underlying free()).
67 : //
68 :
69 : #if defined(MOZALLOC_HAVE_XMALLOC)
70 : struct nsTArrayFallibleAllocator
71 : {
72 8498 : static void* Malloc(size_t size) {
73 8498 : return moz_malloc(size);
74 : }
75 :
76 246 : static void* Realloc(void* ptr, size_t size) {
77 246 : return moz_realloc(ptr, size);
78 : }
79 :
80 8497 : static void Free(void* ptr) {
81 8497 : moz_free(ptr);
82 8497 : }
83 : };
84 :
85 : struct nsTArrayInfallibleAllocator
86 : {
87 597002 : static void* Malloc(size_t size) {
88 597002 : return moz_xmalloc(size);
89 : }
90 :
91 233708 : static void* Realloc(void* ptr, size_t size) {
92 233708 : return moz_xrealloc(ptr, size);
93 : }
94 :
95 596697 : static void Free(void* ptr) {
96 596697 : moz_free(ptr);
97 596697 : }
98 : };
99 :
100 : #else
101 :
102 : #include <stdlib.h>
103 : struct nsTArrayFallibleAllocator
104 : {
105 : static void* Malloc(size_t size) {
106 : return malloc(size);
107 : }
108 :
109 : static void* Realloc(void* ptr, size_t size) {
110 : return realloc(ptr, size);
111 : }
112 :
113 : static void Free(void* ptr) {
114 : free(ptr);
115 : }
116 : };
117 :
118 : #endif
119 :
120 : #if defined(MOZALLOC_HAVE_XMALLOC)
121 : struct nsTArrayDefaultAllocator : public nsTArrayInfallibleAllocator { };
122 : #else
123 : struct nsTArrayDefaultAllocator : public nsTArrayFallibleAllocator { };
124 : #endif
125 :
126 : // nsTArray_base stores elements into the space allocated beyond
127 : // sizeof(*this). This is done to minimize the size of the nsTArray
128 : // object when it is empty.
129 : struct NS_COM_GLUE nsTArrayHeader
130 : {
131 : static nsTArrayHeader sEmptyHdr;
132 :
133 : PRUint32 mLength;
134 : PRUint32 mCapacity : 31;
135 : PRUint32 mIsAutoArray : 1;
136 : };
137 :
138 : // This class provides a SafeElementAt method to nsTArray<T*> which does
139 : // not take a second default value parameter.
140 : template <class E, class Derived>
141 : struct nsTArray_SafeElementAtHelper
142 7784202 : {
143 : typedef E* elem_type;
144 : typedef PRUint32 index_type;
145 :
146 : // No implementation is provided for these two methods, and that is on
147 : // purpose, since we don't support these functions on non-pointer type
148 : // instantiations.
149 : elem_type& SafeElementAt(index_type i);
150 : const elem_type& SafeElementAt(index_type i) const;
151 : };
152 :
153 : template <class E, class Derived>
154 : struct nsTArray_SafeElementAtHelper<E*, Derived>
155 : {
156 : typedef E* elem_type;
157 : typedef PRUint32 index_type;
158 :
159 91 : elem_type SafeElementAt(index_type i) {
160 91 : return static_cast<Derived*> (this)->SafeElementAt(i, nsnull);
161 : }
162 :
163 0 : const elem_type SafeElementAt(index_type i) const {
164 0 : return static_cast<const Derived*> (this)->SafeElementAt(i, nsnull);
165 : }
166 : };
167 :
168 : // E is the base type that the smart pointer is templated over; the
169 : // smart pointer can act as E*.
170 : template <class E, class Derived>
171 : struct nsTArray_SafeElementAtSmartPtrHelper
172 200827 : {
173 : typedef E* elem_type;
174 : typedef PRUint32 index_type;
175 :
176 4240 : elem_type SafeElementAt(index_type i) {
177 4240 : return static_cast<Derived*> (this)->SafeElementAt(i, nsnull);
178 : }
179 :
180 : const elem_type SafeElementAt(index_type i) const {
181 : return static_cast<const Derived*> (this)->SafeElementAt(i, nsnull);
182 : }
183 : };
184 :
185 : template <class T> class nsCOMPtr;
186 :
187 : template <class E, class Derived>
188 : struct nsTArray_SafeElementAtHelper<nsCOMPtr<E>, Derived> :
189 : public nsTArray_SafeElementAtSmartPtrHelper<E, Derived>
190 : {
191 : };
192 :
193 : template <class T> class nsRefPtr;
194 :
195 : template <class E, class Derived>
196 : struct nsTArray_SafeElementAtHelper<nsRefPtr<E>, Derived> :
197 : public nsTArray_SafeElementAtSmartPtrHelper<E, Derived>
198 : {
199 : };
200 :
201 : //
202 : // This class serves as a base class for nsTArray. It shouldn't be used
203 : // directly. It holds common implementation code that does not depend on the
204 : // element type of the nsTArray.
205 : //
206 : template<class Alloc>
207 : class nsTArray_base
208 : {
209 : // Allow swapping elements with |nsTArray_base|s created using a
210 : // different allocator. This is kosher because all allocators use
211 : // the same free().
212 : template<class Allocator>
213 : friend class nsTArray_base;
214 :
215 : protected:
216 : typedef nsTArrayHeader Header;
217 :
218 : public:
219 : typedef PRUint32 size_type;
220 : typedef PRUint32 index_type;
221 :
222 : // @return The number of elements in the array.
223 200754760 : size_type Length() const {
224 200754760 : return mHdr->mLength;
225 : }
226 :
227 : // @return True if the array is empty or false otherwise.
228 22373487 : bool IsEmpty() const {
229 22373487 : return Length() == 0;
230 : }
231 :
232 : // @return The number of elements that can fit in the array without forcing
233 : // the array to be re-allocated. The length of an array is always less
234 : // than or equal to its capacity.
235 4830 : size_type Capacity() const {
236 4830 : return mHdr->mCapacity;
237 : }
238 :
239 : #ifdef DEBUG
240 11 : void* DebugGetHeader() const {
241 11 : return mHdr;
242 : }
243 : #endif
244 :
245 : protected:
246 7774036 : nsTArray_base();
247 :
248 7772559 : ~nsTArray_base();
249 :
250 : // Resize the storage if necessary to achieve the requested capacity.
251 : // @param capacity The requested number of array elements.
252 : // @param elemSize The size of an array element.
253 : // @return False if insufficient memory is available; true otherwise.
254 16033847 : bool EnsureCapacity(size_type capacity, size_type elemSize);
255 :
256 : // Resize the storage to the minimum required amount.
257 : // @param elemSize The size of an array element.
258 : // @param elemAlign The alignment in bytes of an array element.
259 7210310 : void ShrinkCapacity(size_type elemSize, size_t elemAlign);
260 :
261 : // This method may be called to resize a "gap" in the array by shifting
262 : // elements around. It updates mLength appropriately. If the resulting
263 : // array has zero elements, then the array's memory is free'd.
264 : // @param start The starting index of the gap.
265 : // @param oldLen The current length of the gap.
266 : // @param newLen The desired length of the gap.
267 : // @param elemSize The size of an array element.
268 : // @param elemAlign The alignment in bytes of an array element.
269 10942457 : void ShiftData(index_type start, size_type oldLen, size_type newLen,
270 : size_type elemSize, size_t elemAlign);
271 :
272 : // This method increments the length member of the array's header.
273 : // Note that mHdr may actually be sEmptyHdr in the case where a
274 : // zero-length array is inserted into our array. But then n should
275 : // always be 0.
276 16282224 : void IncrementLength(PRUint32 n) {
277 16282224 : MOZ_ASSERT(mHdr != EmptyHdr() || n == 0, "bad data pointer");
278 16282224 : mHdr->mLength += n;
279 16282224 : }
280 :
281 : // This method inserts blank slots into the array.
282 : // @param index the place to insert the new elements. This must be no
283 : // greater than the current length of the array.
284 : // @param count the number of slots to insert
285 : // @param elementSize the size of an array element.
286 : // @param elemAlign the alignment in bytes of an array element.
287 373 : bool InsertSlotsAt(index_type index, size_type count,
288 : size_type elementSize, size_t elemAlign);
289 :
290 : protected:
291 : template<class Allocator>
292 : bool SwapArrayElements(nsTArray_base<Allocator>& other,
293 : size_type elemSize,
294 : size_t elemAlign);
295 :
296 : // This is an RAII class used in SwapArrayElements.
297 : class IsAutoArrayRestorer {
298 : public:
299 : IsAutoArrayRestorer(nsTArray_base<Alloc> &array, size_t elemAlign);
300 : ~IsAutoArrayRestorer();
301 :
302 : private:
303 : nsTArray_base<Alloc> &mArray;
304 : size_t mElemAlign;
305 : bool mIsAuto;
306 : };
307 :
308 : // Helper function for SwapArrayElements. Ensures that if the array
309 : // is an nsAutoTArray that it doesn't use the built-in buffer.
310 242676 : bool EnsureNotUsingAutoArrayBuffer(size_type elemSize);
311 :
312 : // Returns true if this nsTArray is an nsAutoTArray with a built-in buffer.
313 61876570 : bool IsAutoArray() const {
314 61876570 : return mHdr->mIsAutoArray;
315 : }
316 :
317 : // Returns a Header for the built-in buffer of this nsAutoTArray.
318 6812587 : Header* GetAutoArrayBuffer(size_t elemAlign) {
319 6812587 : MOZ_ASSERT(IsAutoArray(), "Should be an auto array to call this");
320 6812587 : return GetAutoArrayBufferUnsafe(elemAlign);
321 : }
322 53607115 : const Header* GetAutoArrayBuffer(size_t elemAlign) const {
323 53607115 : MOZ_ASSERT(IsAutoArray(), "Should be an auto array to call this");
324 53607116 : return GetAutoArrayBufferUnsafe(elemAlign);
325 : }
326 :
327 : // Returns a Header for the built-in buffer of this nsAutoTArray, but doesn't
328 : // assert that we are an nsAutoTArray.
329 6812603 : Header* GetAutoArrayBufferUnsafe(size_t elemAlign) {
330 : return const_cast<Header*>(static_cast<const nsTArray_base<Alloc>*>(this)->
331 6812603 : GetAutoArrayBufferUnsafe(elemAlign));
332 : }
333 60333590 : const Header* GetAutoArrayBufferUnsafe(size_t elemAlign) const;
334 :
335 : // Returns true if this is an nsAutoTArray and it currently uses the
336 : // built-in buffer to store its elements.
337 14709953 : bool UsesAutoArrayBuffer() const;
338 :
339 : // The array's elements (prefixed with a Header). This pointer is never
340 : // null. If the array is empty, then this will point to sEmptyHdr.
341 : Header *mHdr;
342 :
343 127522036 : Header* Hdr() const {
344 127522036 : return mHdr;
345 : }
346 :
347 6801755 : Header** PtrToHdr() {
348 6801755 : return &mHdr;
349 : }
350 :
351 40547033 : static Header* EmptyHdr() {
352 40547033 : return &Header::sEmptyHdr;
353 : }
354 : };
355 :
356 : //
357 : // This class defines convenience functions for element specific operations.
358 : // Specialize this template if necessary.
359 : //
360 : template<class E>
361 : class nsTArrayElementTraits
362 : {
363 : public:
364 : // Invoke the default constructor in place.
365 11949180 : static inline void Construct(E *e) {
366 : // Do NOT call "E()"! That triggers C++ "default initialization"
367 : // which zeroes out POD ("plain old data") types such as regular
368 : // ints. We don't want that because it can be a performance issue
369 : // and people don't expect it; nsTArray should work like a regular
370 : // C/C++ array in this respect.
371 11949180 : new (static_cast<void *>(e)) E;
372 11949180 : }
373 : // Invoke the copy-constructor in place.
374 : template<class A>
375 4944033 : static inline void Construct(E *e, const A &arg) {
376 4944033 : new (static_cast<void *>(e)) E(arg);
377 4944033 : }
378 : // Invoke the destructor in place.
379 16891320 : static inline void Destruct(E *e) {
380 12863148 : e->~E();
381 16891320 : }
382 : };
383 :
384 : // This class exists because VC6 cannot handle static template functions.
385 : // Otherwise, the Compare method would be defined directly on nsTArray.
386 : template <class E, class Comparator>
387 : class nsQuickSortComparator
388 : {
389 : public:
390 : typedef E elem_type;
391 : // This function is meant to be used with the NS_QuickSort function. It
392 : // maps the callback API expected by NS_QuickSort to the Comparator API
393 : // used by nsTArray. See nsTArray::Sort.
394 50413 : static int Compare(const void* e1, const void* e2, void *data) {
395 50413 : const Comparator* c = reinterpret_cast<const Comparator*>(data);
396 50413 : const elem_type* a = static_cast<const elem_type*>(e1);
397 50413 : const elem_type* b = static_cast<const elem_type*>(e2);
398 50413 : return c->LessThan(*a, *b) ? -1 : (c->Equals(*a, *b) ? 0 : 1);
399 : }
400 : };
401 :
402 : // The default comparator used by nsTArray
403 : template<class A, class B>
404 : class nsDefaultComparator
405 : {
406 : public:
407 4641889 : bool Equals(const A& a, const B& b) const {
408 4641889 : return a == b;
409 : }
410 2792300 : bool LessThan(const A& a, const B& b) const {
411 2792300 : return a < b;
412 : }
413 : };
414 :
415 : //
416 : // The templatized array class that dynamically resizes its storage as
417 : // elements are added. This class is designed to behave a bit like
418 : // std::vector, though note that unlike std::vector, nsTArray doesn't
419 : // follow C++ construction/destruction rules.
420 : //
421 : // The template parameter specifies the type of the elements (elem_type), and
422 : // has the following requirements:
423 : //
424 : // elem_type MUST define a copy-constructor.
425 : // elem_type MAY define operator< for sorting.
426 : // elem_type MAY define operator== for searching.
427 : //
428 : // For methods taking a Comparator instance, the Comparator must be a class
429 : // defining the following methods:
430 : //
431 : // class Comparator {
432 : // public:
433 : // /** @return True if the elements are equals; false otherwise. */
434 : // bool Equals(const elem_type& a, const Item& b) const;
435 : //
436 : // /** @return True if (a < b); false otherwise. */
437 : // bool LessThan(const elem_type& a, const Item& b) const;
438 : // };
439 : //
440 : // The Equals method is used for searching, and the LessThan method is used
441 : // for sorting. The |Item| type above can be arbitrary, but must match the
442 : // Item type passed to the sort or search function.
443 : //
444 : // The Alloc template parameter can be used to choose between
445 : // "fallible" and "infallible" nsTArray (if available), defaulting to
446 : // fallible. If the *fallible* allocator is used, the return value of
447 : // methods that might allocate needs to be checked; Append() is
448 : // one such method. These return values don't need to be checked if
449 : // the *in*fallible allocator is chosen. When in doubt, choose the
450 : // infallible allocator.
451 : //
452 : template<class E, class Alloc=nsTArrayDefaultAllocator>
453 : class nsTArray : public nsTArray_base<Alloc>,
454 : public nsTArray_SafeElementAtHelper<E, nsTArray<E, Alloc> >
455 : {
456 : public:
457 : typedef nsTArray_base<Alloc> base_type;
458 : typedef typename base_type::size_type size_type;
459 : typedef typename base_type::index_type index_type;
460 : typedef E elem_type;
461 : typedef nsTArray<E, Alloc> self_type;
462 : typedef nsTArrayElementTraits<E> elem_traits;
463 : typedef nsTArray_SafeElementAtHelper<E, self_type> safeelementat_helper_type;
464 :
465 : using safeelementat_helper_type::SafeElementAt;
466 : using base_type::EmptyHdr;
467 :
468 : // A special value that is used to indicate an invalid or unknown index
469 : // into the array.
470 : enum {
471 : NoIndex = index_type(-1)
472 : };
473 :
474 : using base_type::Length;
475 :
476 : //
477 : // Finalization method
478 : //
479 :
480 7782711 : ~nsTArray() { Clear(); }
481 :
482 : //
483 : // Initialization methods
484 : //
485 :
486 7658175 : nsTArray() {}
487 :
488 : // Initialize this array and pre-allocate some number of elements.
489 52481 : explicit nsTArray(size_type capacity) {
490 52481 : SetCapacity(capacity);
491 52481 : }
492 :
493 : // The array's copy-constructor performs a 'deep' copy of the given array.
494 : // @param other The array object to copy.
495 73544 : nsTArray(const self_type& other) {
496 73544 : AppendElements(other);
497 73544 : }
498 :
499 : template<typename Allocator>
500 0 : nsTArray(const nsTArray<E, Allocator>& other) {
501 0 : AppendElements(other);
502 0 : }
503 :
504 : // The array's assignment operator performs a 'deep' copy of the given
505 : // array. It is optimized to reuse existing storage if possible.
506 : // @param other The array object to copy.
507 1003 : nsTArray& operator=(const self_type& other) {
508 1003 : ReplaceElementsAt(0, Length(), other.Elements(), other.Length());
509 1003 : return *this;
510 : }
511 :
512 : // Return true if this array has the same length and the same
513 : // elements as |other|.
514 54 : bool operator==(const self_type& other) const {
515 54 : size_type len = Length();
516 54 : if (len != other.Length())
517 12 : return false;
518 :
519 : // XXX std::equal would be as fast or faster here
520 316 : for (index_type i = 0; i < len; ++i)
521 274 : if (!(operator[](i) == other[i]))
522 0 : return false;
523 :
524 42 : return true;
525 : }
526 :
527 : // Return true if this array does not have the same length and the same
528 : // elements as |other|.
529 0 : bool operator!=(const self_type& other) const {
530 0 : return !operator==(other);
531 : }
532 :
533 : template<typename Allocator>
534 0 : nsTArray& operator=(const nsTArray<E, Allocator>& other) {
535 0 : ReplaceElementsAt(0, Length(), other.Elements(), other.Length());
536 0 : return *this;
537 : }
538 :
539 : // @return The amount of memory used by this nsTArray, excluding
540 : // sizeof(*this).
541 6 : size_t SizeOfExcludingThis(nsMallocSizeOfFun mallocSizeOf) const {
542 6 : if (this->UsesAutoArrayBuffer() || Hdr() == EmptyHdr())
543 0 : return 0;
544 6 : return mallocSizeOf(this->Hdr());
545 : }
546 :
547 : // @return The amount of memory used by this nsTArray, including
548 : // sizeof(*this).
549 0 : size_t SizeOfIncludingThis(nsMallocSizeOfFun mallocSizeOf) const {
550 0 : return mallocSizeOf(this) + SizeOfExcludingThis(mallocSizeOf);
551 : }
552 :
553 : //
554 : // Accessor methods
555 : //
556 :
557 : // This method provides direct access to the array elements.
558 : // @return A pointer to the first element of the array. If the array is
559 : // empty, then this pointer must not be dereferenced.
560 93375893 : elem_type* Elements() {
561 93375893 : return reinterpret_cast<elem_type *>(Hdr() + 1);
562 : }
563 :
564 : // This method provides direct, readonly access to the array elements.
565 : // @return A pointer to the first element of the array. If the array is
566 : // empty, then this pointer must not be dereferenced.
567 13732839 : const elem_type* Elements() const {
568 13732839 : return reinterpret_cast<const elem_type *>(Hdr() + 1);
569 : }
570 :
571 : // This method provides direct access to the i'th element of the array.
572 : // The given index must be within the array bounds.
573 : // @param i The index of an element in the array.
574 : // @return A reference to the i'th element of the array.
575 54134139 : elem_type& ElementAt(index_type i) {
576 54134139 : MOZ_ASSERT(i < Length(), "invalid array index");
577 54134139 : return Elements()[i];
578 : }
579 :
580 : // This method provides direct, readonly access to the i'th element of the
581 : // array. The given index must be within the array bounds.
582 : // @param i The index of an element in the array.
583 : // @return A const reference to the i'th element of the array.
584 11837352 : const elem_type& ElementAt(index_type i) const {
585 11837352 : MOZ_ASSERT(i < Length(), "invalid array index");
586 11837352 : return Elements()[i];
587 : }
588 :
589 : // This method provides direct access to the i'th element of the array in
590 : // a bounds safe manner. If the requested index is out of bounds the
591 : // provided default value is returned.
592 : // @param i The index of an element in the array.
593 : // @param def The value to return if the index is out of bounds.
594 0 : elem_type& SafeElementAt(index_type i, elem_type& def) {
595 0 : return i < Length() ? Elements()[i] : def;
596 : }
597 :
598 : // This method provides direct access to the i'th element of the array in
599 : // a bounds safe manner. If the requested index is out of bounds the
600 : // provided default value is returned.
601 : // @param i The index of an element in the array.
602 : // @param def The value to return if the index is out of bounds.
603 4481 : const elem_type& SafeElementAt(index_type i, const elem_type& def) const {
604 4481 : return i < Length() ? Elements()[i] : def;
605 : }
606 :
607 : // Shorthand for ElementAt(i)
608 53160107 : elem_type& operator[](index_type i) {
609 53160107 : return ElementAt(i);
610 : }
611 :
612 : // Shorthand for ElementAt(i)
613 4547441 : const elem_type& operator[](index_type i) const {
614 4547441 : return ElementAt(i);
615 : }
616 :
617 : //
618 : // Search methods
619 : //
620 :
621 : // This method searches for the first element in this array that is equal
622 : // to the given element.
623 : // @param item The item to search for.
624 : // @param comp The Comparator used to determine element equality.
625 : // @return true if the element was found.
626 : template<class Item, class Comparator>
627 0 : bool Contains(const Item& item, const Comparator& comp) const {
628 0 : return IndexOf(item, 0, comp) != NoIndex;
629 : }
630 :
631 : // This method searches for the first element in this array that is equal
632 : // to the given element. This method assumes that 'operator==' is defined
633 : // for elem_type.
634 : // @param item The item to search for.
635 : // @return true if the element was found.
636 : template<class Item>
637 10776 : bool Contains(const Item& item) const {
638 10776 : return IndexOf(item) != NoIndex;
639 : }
640 :
641 : // This method searches for the offset of the first element in this
642 : // array that is equal to the given element.
643 : // @param item The item to search for.
644 : // @param start The index to start from.
645 : // @param comp The Comparator used to determine element equality.
646 : // @return The index of the found element or NoIndex if not found.
647 : template<class Item, class Comparator>
648 270742 : index_type IndexOf(const Item& item, index_type start,
649 : const Comparator& comp) const {
650 270742 : const elem_type* iter = Elements() + start, *end = Elements() + Length();
651 2275132 : for (; iter != end; ++iter) {
652 2090990 : if (comp.Equals(*iter, item))
653 86600 : return index_type(iter - Elements());
654 : }
655 184142 : return NoIndex;
656 : }
657 :
658 : // This method searches for the offset of the first element in this
659 : // array that is equal to the given element. This method assumes
660 : // that 'operator==' is defined for elem_type.
661 : // @param item The item to search for.
662 : // @param start The index to start from.
663 : // @return The index of the found element or NoIndex if not found.
664 : template<class Item>
665 39656 : index_type IndexOf(const Item& item, index_type start = 0) const {
666 39656 : return IndexOf(item, start, nsDefaultComparator<elem_type, Item>());
667 : }
668 :
669 : // This method searches for the offset of the last element in this
670 : // array that is equal to the given element.
671 : // @param item The item to search for.
672 : // @param start The index to start from. If greater than or equal to the
673 : // length of the array, then the entire array is searched.
674 : // @param comp The Comparator used to determine element equality.
675 : // @return The index of the found element or NoIndex if not found.
676 : template<class Item, class Comparator>
677 18 : index_type LastIndexOf(const Item& item, index_type start,
678 : const Comparator& comp) const {
679 18 : if (start >= Length())
680 12 : start = Length() - 1;
681 18 : const elem_type* end = Elements() - 1, *iter = end + start + 1;
682 62 : for (; iter != end; --iter) {
683 62 : if (comp.Equals(*iter, item))
684 18 : return index_type(iter - Elements());
685 : }
686 0 : return NoIndex;
687 : }
688 :
689 : // This method searches for the offset of the last element in this
690 : // array that is equal to the given element. This method assumes
691 : // that 'operator==' is defined for elem_type.
692 : // @param item The item to search for.
693 : // @param start The index to start from. If greater than or equal to the
694 : // length of the array, then the entire array is searched.
695 : // @return The index of the found element or NoIndex if not found.
696 : template<class Item>
697 18 : index_type LastIndexOf(const Item& item,
698 : index_type start = NoIndex) const {
699 18 : return LastIndexOf(item, start, nsDefaultComparator<elem_type, Item>());
700 : }
701 :
702 : // This method searches for the offset for the element in this array
703 : // that is equal to the given element. The array is assumed to be sorted.
704 : // @param item The item to search for.
705 : // @param comp The Comparator used.
706 : // @return The index of the found element or NoIndex if not found.
707 : template<class Item, class Comparator>
708 2749988 : index_type BinaryIndexOf(const Item& item, const Comparator& comp) const {
709 2749988 : index_type low = 0, high = Length();
710 8114327 : while (high > low) {
711 4180175 : index_type mid = (high + low) >> 1;
712 4180175 : if (comp.Equals(ElementAt(mid), item))
713 1565824 : return mid;
714 2614351 : if (comp.LessThan(ElementAt(mid), item))
715 602356 : low = mid + 1;
716 : else
717 2011995 : high = mid;
718 : }
719 1184164 : return NoIndex;
720 : }
721 :
722 : // This method searches for the offset for the element in this array
723 : // that is equal to the given element. The array is assumed to be sorted.
724 : // This method assumes that 'operator==' and 'operator<' are defined.
725 : // @param item The item to search for.
726 : // @return The index of the found element or NoIndex if not found.
727 : template<class Item>
728 2749988 : index_type BinaryIndexOf(const Item& item) const {
729 2749988 : return BinaryIndexOf(item, nsDefaultComparator<elem_type, Item>());
730 : }
731 :
732 : //
733 : // Mutation methods
734 : //
735 :
736 : // This method replaces a range of elements in this array.
737 : // @param start The starting index of the elements to replace.
738 : // @param count The number of elements to replace. This may be zero to
739 : // insert elements without removing any existing elements.
740 : // @param array The values to copy into this array. Must be non-null,
741 : // and these elements must not already exist in the array
742 : // being modified.
743 : // @param arrayLen The number of values to copy into this array.
744 : // @return A pointer to the new elements in the array, or null if
745 : // the operation failed due to insufficient memory.
746 : template<class Item>
747 125248 : elem_type *ReplaceElementsAt(index_type start, size_type count,
748 : const Item* array, size_type arrayLen) {
749 : // Adjust memory allocation up-front to catch errors.
750 125248 : if (!this->EnsureCapacity(Length() + arrayLen - count, sizeof(elem_type)))
751 0 : return nsnull;
752 125248 : DestructRange(start, count);
753 125248 : this->ShiftData(start, count, arrayLen, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
754 125248 : AssignRange(start, arrayLen, array);
755 125248 : return Elements() + start;
756 : }
757 :
758 : // A variation on the ReplaceElementsAt method defined above.
759 : template<class Item>
760 975 : elem_type *ReplaceElementsAt(index_type start, size_type count,
761 : const nsTArray<Item>& array) {
762 975 : return ReplaceElementsAt(start, count, array.Elements(), array.Length());
763 : }
764 :
765 : // A variation on the ReplaceElementsAt method defined above.
766 : template<class Item>
767 0 : elem_type *ReplaceElementsAt(index_type start, size_type count,
768 : const Item& item) {
769 0 : return ReplaceElementsAt(start, count, &item, 1);
770 : }
771 :
772 : // A variation on the ReplaceElementsAt method defined above.
773 : template<class Item>
774 : elem_type *ReplaceElementAt(index_type index, const Item& item) {
775 : return ReplaceElementsAt(index, 1, item, 1);
776 : }
777 :
778 : // A variation on the ReplaceElementsAt method defined above.
779 : template<class Item>
780 0 : elem_type *InsertElementsAt(index_type index, const Item* array,
781 : size_type arrayLen) {
782 0 : return ReplaceElementsAt(index, 0, array, arrayLen);
783 : }
784 :
785 : // A variation on the ReplaceElementsAt method defined above.
786 : template<class Item>
787 6 : elem_type *InsertElementsAt(index_type index, const nsTArray<Item>& array) {
788 6 : return ReplaceElementsAt(index, 0, array.Elements(), array.Length());
789 : }
790 :
791 : // A variation on the ReplaceElementsAt method defined above.
792 : template<class Item>
793 121839 : elem_type *InsertElementAt(index_type index, const Item& item) {
794 121839 : return ReplaceElementsAt(index, 0, &item, 1);
795 : }
796 :
797 : // Insert a new element without copy-constructing. This is useful to avoid
798 : // temporaries.
799 : // @return A pointer to the newly inserted element, or null on OOM.
800 1419 : elem_type* InsertElementAt(index_type index) {
801 1419 : if (!this->EnsureCapacity(Length() + 1, sizeof(elem_type)))
802 0 : return nsnull;
803 1419 : this->ShiftData(index, 0, 1, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
804 1419 : elem_type *elem = Elements() + index;
805 1419 : elem_traits::Construct(elem);
806 1419 : return elem;
807 : }
808 :
809 : // This method searches for the least index of the greatest
810 : // element less than or equal to |item|. If |item| is inserted at
811 : // this index, the array will remain sorted. True is returned iff
812 : // this index is also equal to |item|. In this case, the returned
813 : // index may point to the start of multiple copies of |item|.
814 : // @param item The item to search for.
815 : // @param comp The Comparator used.
816 : // @outparam idx The index of greatest element <= to |item|
817 : // @return True iff |item == array[*idx]|.
818 : // @precondition The array is sorted
819 : template<class Item, class Comparator>
820 : bool
821 90805 : GreatestIndexLtEq(const Item& item,
822 : const Comparator& comp,
823 : index_type* idx NS_OUTPARAM) const {
824 : // Nb: we could replace all the uses of "BinaryIndexOf" with this
825 : // function, but BinaryIndexOf will be oh-so-slightly faster so
826 : // it's not strictly desired to do.
827 :
828 : // invariant: low <= [idx] < high
829 90805 : index_type low = 0, high = Length();
830 356676 : while (high > low) {
831 175116 : index_type mid = (high + low) >> 1;
832 175116 : if (comp.Equals(ElementAt(mid), item)) {
833 : // we might have the array [..., 2, 4, 4, 4, 4, 4, 5, ...]
834 : // and be searching for "4". it's arbitrary where mid ends
835 : // up here, so we back it up to the first instance to maintain
836 : // the "least index ..." we promised above.
837 110 : do {
838 110 : --mid;
839 : } while (NoIndex != mid && comp.Equals(ElementAt(mid), item));
840 50 : *idx = ++mid;
841 50 : return true;
842 : }
843 175066 : if (comp.LessThan(ElementAt(mid), item))
844 : // invariant: low <= idx < high
845 150398 : low = mid + 1;
846 : else
847 : // invariant: low <= idx < high
848 24668 : high = mid;
849 : }
850 : // low <= idx < high, so insert at high ("shifting" high up by
851 : // 1) to maintain invariant.
852 : // (or insert at low, since low==high; just a matter of taste here.)
853 90755 : *idx = high;
854 90755 : return false;
855 : }
856 :
857 : // A variation on the GreatestIndexLtEq method defined above.
858 : template<class Item, class Comparator>
859 : bool
860 : GreatestIndexLtEq(const Item& item,
861 : index_type& idx,
862 : const Comparator& comp) const {
863 : return GreatestIndexLtEq(item, comp, &idx);
864 : }
865 :
866 : // A variation on the GreatestIndexLtEq method defined above.
867 : template<class Item>
868 : bool
869 56 : GreatestIndexLtEq(const Item& item,
870 : index_type& idx) const {
871 56 : return GreatestIndexLtEq(item, nsDefaultComparator<elem_type, Item>(), &idx);
872 : }
873 :
874 : // Inserts |item| at such an index to guarantee that if the array
875 : // was previously sorted, it will remain sorted after this
876 : // insertion.
877 : template<class Item, class Comparator>
878 90749 : elem_type *InsertElementSorted(const Item& item, const Comparator& comp) {
879 : index_type index;
880 90749 : GreatestIndexLtEq(item, comp, &index);
881 90749 : return InsertElementAt(index, item);
882 : }
883 :
884 : // A variation on the InsertElementSorted metod defined above.
885 : template<class Item>
886 90749 : elem_type *InsertElementSorted(const Item& item) {
887 90749 : return InsertElementSorted(item, nsDefaultComparator<elem_type, Item>());
888 : }
889 :
890 : // This method appends elements to the end of this array.
891 : // @param array The elements to append to this array.
892 : // @param arrayLen The number of elements to append to this array.
893 : // @return A pointer to the new elements in the array, or null if
894 : // the operation failed due to insufficient memory.
895 : template<class Item>
896 4630356 : elem_type *AppendElements(const Item* array, size_type arrayLen) {
897 4630356 : if (!this->EnsureCapacity(Length() + arrayLen, sizeof(elem_type)))
898 0 : return nsnull;
899 4630356 : index_type len = Length();
900 4630356 : AssignRange(len, arrayLen, array);
901 4630356 : this->IncrementLength(arrayLen);
902 4630356 : return Elements() + len;
903 : }
904 :
905 : // A variation on the AppendElements method defined above.
906 : template<class Item, class Allocator>
907 76904 : elem_type *AppendElements(const nsTArray<Item, Allocator>& array) {
908 76904 : return AppendElements(array.Elements(), array.Length());
909 : }
910 :
911 : // A variation on the AppendElements method defined above.
912 : template<class Item>
913 4545308 : elem_type *AppendElement(const Item& item) {
914 4545308 : return AppendElements(&item, 1);
915 : }
916 :
917 : // Append new elements without copy-constructing. This is useful to avoid
918 : // temporaries.
919 : // @return A pointer to the newly appended elements, or null on OOM.
920 11651868 : elem_type *AppendElements(size_type count) {
921 11651868 : if (!this->EnsureCapacity(Length() + count, sizeof(elem_type)))
922 0 : return nsnull;
923 11651868 : elem_type *elems = Elements() + Length();
924 : size_type i;
925 23598830 : for (i = 0; i < count; ++i) {
926 11946962 : elem_traits::Construct(elems + i);
927 : }
928 11651868 : this->IncrementLength(count);
929 11651868 : return elems;
930 : }
931 :
932 : // Append a new element without copy-constructing. This is useful to avoid
933 : // temporaries.
934 : // @return A pointer to the newly appended element, or null on OOM.
935 11651296 : elem_type *AppendElement() {
936 11651296 : return AppendElements(1);
937 : }
938 :
939 : // Move all elements from another array to the end of this array without
940 : // calling copy constructors or destructors.
941 : // @return A pointer to the newly appended elements, or null on OOM.
942 : template<class Item, class Allocator>
943 0 : elem_type *MoveElementsFrom(nsTArray<Item, Allocator>& array) {
944 0 : MOZ_ASSERT(&array != this, "argument must be different array");
945 0 : index_type len = Length();
946 0 : index_type otherLen = array.Length();
947 0 : if (!this->EnsureCapacity(len + otherLen, sizeof(elem_type)))
948 0 : return nsnull;
949 0 : memcpy(Elements() + len, array.Elements(), otherLen * sizeof(elem_type));
950 0 : this->IncrementLength(otherLen);
951 0 : array.ShiftData(0, otherLen, 0, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
952 0 : return Elements() + len;
953 : }
954 :
955 : // This method removes a range of elements from this array.
956 : // @param start The starting index of the elements to remove.
957 : // @param count The number of elements to remove.
958 11261058 : void RemoveElementsAt(index_type start, size_type count) {
959 11261058 : MOZ_ASSERT(count == 0 || start < Length(), "Invalid start index");
960 11261058 : MOZ_ASSERT(start + count <= Length(), "Invalid length");
961 11261058 : DestructRange(start, count);
962 11261058 : this->ShiftData(start, count, 0, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
963 11261058 : }
964 :
965 : // A variation on the RemoveElementsAt method defined above.
966 3079949 : void RemoveElementAt(index_type index) {
967 3079949 : RemoveElementsAt(index, 1);
968 3079949 : }
969 :
970 : // A variation on the RemoveElementsAt method defined above.
971 7920143 : void Clear() {
972 7920143 : RemoveElementsAt(0, Length());
973 7920143 : }
974 :
975 : // This helper function combines IndexOf with RemoveElementAt to "search
976 : // and destroy" the first element that is equal to the given element.
977 : // @param item The item to search for.
978 : // @param comp The Comparator used to determine element equality.
979 : // @return true if the element was found
980 : template<class Item, class Comparator>
981 64302 : bool RemoveElement(const Item& item, const Comparator& comp) {
982 64302 : index_type i = IndexOf(item, 0, comp);
983 64302 : if (i == NoIndex)
984 4601 : return false;
985 :
986 59701 : RemoveElementAt(i);
987 59701 : return true;
988 : }
989 :
990 : // A variation on the RemoveElement method defined above that assumes
991 : // that 'operator==' is defined for elem_type.
992 : template<class Item>
993 64068 : bool RemoveElement(const Item& item) {
994 64068 : return RemoveElement(item, nsDefaultComparator<elem_type, Item>());
995 : }
996 :
997 : // This helper function combines GreatestIndexLtEq with
998 : // RemoveElementAt to "search and destroy" the first element that
999 : // is equal to the given element.
1000 : // @param item The item to search for.
1001 : // @param comp The Comparator used to determine element equality.
1002 : // @return true if the element was found
1003 : template<class Item, class Comparator>
1004 0 : bool RemoveElementSorted(const Item& item, const Comparator& comp) {
1005 : index_type index;
1006 0 : bool found = GreatestIndexLtEq(item, comp, &index);
1007 0 : if (found)
1008 0 : RemoveElementAt(index);
1009 0 : return found;
1010 : }
1011 :
1012 : // A variation on the RemoveElementSorted method defined above.
1013 : template<class Item>
1014 0 : bool RemoveElementSorted(const Item& item) {
1015 0 : return RemoveElementSorted(item, nsDefaultComparator<elem_type, Item>());
1016 : }
1017 :
1018 : // This method causes the elements contained in this array and the given
1019 : // array to be swapped.
1020 : template<class Allocator>
1021 126015 : bool SwapElements(nsTArray<E, Allocator>& other) {
1022 126015 : return this->SwapArrayElements(other, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
1023 : }
1024 :
1025 : //
1026 : // Allocation
1027 : //
1028 :
1029 : // This method may increase the capacity of this array object by the
1030 : // specified amount. This method may be called in advance of several
1031 : // AppendElement operations to minimize heap re-allocations. This method
1032 : // will not reduce the number of elements in this array.
1033 : // @param capacity The desired capacity of this array.
1034 : // @return True if the operation succeeded; false if we ran out of memory
1035 70525 : bool SetCapacity(size_type capacity) {
1036 70525 : return this->EnsureCapacity(capacity, sizeof(elem_type));
1037 : }
1038 :
1039 : // This method modifies the length of the array. If the new length is
1040 : // larger than the existing length of the array, then new elements will be
1041 : // constructed using elem_type's default constructor. Otherwise, this call
1042 : // removes elements from the array (see also RemoveElementsAt).
1043 : // @param newLen The desired length of this array.
1044 : // @return True if the operation succeeded; false otherwise.
1045 : // See also TruncateLength if the new length is guaranteed to be
1046 : // smaller than the old.
1047 374 : bool SetLength(size_type newLen) {
1048 374 : size_type oldLen = Length();
1049 374 : if (newLen > oldLen) {
1050 372 : return InsertElementsAt(oldLen, newLen - oldLen) != nsnull;
1051 : }
1052 :
1053 2 : TruncateLength(newLen);
1054 2 : return true;
1055 : }
1056 :
1057 : // This method modifies the length of the array, but may only be
1058 : // called when the new length is shorter than the old. It can
1059 : // therefore be called when elem_type has no default constructor,
1060 : // unlike SetLength. It removes elements from the array (see also
1061 : // RemoveElementsAt).
1062 : // @param newLen The desired length of this array.
1063 1726 : void TruncateLength(size_type newLen) {
1064 1726 : size_type oldLen = Length();
1065 1726 : NS_ABORT_IF_FALSE(newLen <= oldLen,
1066 : "caller should use SetLength instead");
1067 1726 : RemoveElementsAt(newLen, oldLen - newLen);
1068 1726 : }
1069 :
1070 : // This method ensures that the array has length at least the given
1071 : // length. If the current length is shorter than the given length,
1072 : // then new elements will be constructed using elem_type's default
1073 : // constructor.
1074 : // @param minLen The desired minimum length of this array.
1075 : // @return True if the operation succeeded; false otherwise.
1076 0 : bool EnsureLengthAtLeast(size_type minLen) {
1077 0 : size_type oldLen = Length();
1078 0 : if (minLen > oldLen) {
1079 0 : return InsertElementsAt(oldLen, minLen - oldLen) != nsnull;
1080 : }
1081 0 : return true;
1082 : }
1083 :
1084 : // This method inserts elements into the array, constructing
1085 : // them using elem_type's default constructor.
1086 : // @param index the place to insert the new elements. This must be no
1087 : // greater than the current length of the array.
1088 : // @param count the number of elements to insert
1089 372 : elem_type *InsertElementsAt(index_type index, size_type count) {
1090 372 : if (!base_type::InsertSlotsAt(index, count, sizeof(elem_type), MOZ_ALIGNOF(elem_type))) {
1091 0 : return nsnull;
1092 : }
1093 :
1094 : // Initialize the extra array elements
1095 372 : elem_type *iter = Elements() + index, *end = iter + count;
1096 1171 : for (; iter != end; ++iter) {
1097 799 : elem_traits::Construct(iter);
1098 : }
1099 :
1100 372 : return Elements() + index;
1101 : }
1102 :
1103 : // This method inserts elements into the array, constructing them
1104 : // elem_type's copy constructor (or whatever one-arg constructor
1105 : // happens to match the Item type).
1106 : // @param index the place to insert the new elements. This must be no
1107 : // greater than the current length of the array.
1108 : // @param count the number of elements to insert.
1109 : // @param item the value to use when constructing the new elements.
1110 : template<class Item>
1111 0 : elem_type *InsertElementsAt(index_type index, size_type count,
1112 : const Item& item) {
1113 0 : if (!base_type::InsertSlotsAt(index, count, sizeof(elem_type), MOZ_ALIGNOF(elem_type))) {
1114 0 : return nsnull;
1115 : }
1116 :
1117 : // Initialize the extra array elements
1118 0 : elem_type *iter = Elements() + index, *end = iter + count;
1119 0 : for (; iter != end; ++iter) {
1120 0 : elem_traits::Construct(iter, item);
1121 : }
1122 :
1123 0 : return Elements() + index;
1124 : }
1125 :
1126 : // This method may be called to minimize the memory used by this array.
1127 34149 : void Compact() {
1128 34149 : ShrinkCapacity(sizeof(elem_type), MOZ_ALIGNOF(elem_type));
1129 34149 : }
1130 :
1131 : //
1132 : // Sorting
1133 : //
1134 :
1135 : // This method sorts the elements of the array. It uses the LessThan
1136 : // method defined on the given Comparator object to collate elements.
1137 : // @param comp The Comparator used to collate elements.
1138 : template<class Comparator>
1139 812 : void Sort(const Comparator& comp) {
1140 812 : NS_QuickSort(Elements(), Length(), sizeof(elem_type),
1141 : nsQuickSortComparator<elem_type, Comparator>::Compare,
1142 : const_cast<Comparator*>(&comp));
1143 812 : }
1144 :
1145 : // A variation on the Sort method defined above that assumes that
1146 : // 'operator<' is defined for elem_type.
1147 746 : void Sort() {
1148 746 : Sort(nsDefaultComparator<elem_type, elem_type>());
1149 746 : }
1150 :
1151 : //
1152 : // Binary Heap
1153 : //
1154 :
1155 : // Sorts the array into a binary heap.
1156 : // @param comp The Comparator used to create the heap
1157 : template<class Comparator>
1158 1 : void MakeHeap(const Comparator& comp) {
1159 1 : if (!Length()) {
1160 0 : return;
1161 : }
1162 1 : index_type index = (Length() - 1) / 2;
1163 5 : do {
1164 5 : SiftDown(index, comp);
1165 : } while (index--);
1166 : }
1167 :
1168 : // A variation on the MakeHeap method defined above.
1169 1 : void MakeHeap() {
1170 1 : MakeHeap(nsDefaultComparator<elem_type, elem_type>());
1171 1 : }
1172 :
1173 : // Adds an element to the heap
1174 : // @param item The item to add
1175 : // @param comp The Comparator used to sift-up the item
1176 : template<class Item, class Comparator>
1177 1 : elem_type *PushHeap(const Item& item, const Comparator& comp) {
1178 1 : if (!base_type::InsertSlotsAt(Length(), 1, sizeof(elem_type), MOZ_ALIGNOF(elem_type))) {
1179 0 : return nsnull;
1180 : }
1181 : // Sift up the new node
1182 1 : elem_type *elem = Elements();
1183 1 : index_type index = Length() - 1;
1184 1 : index_type parent_index = (index - 1) / 2;
1185 5 : while (index && comp.LessThan(elem[parent_index], item)) {
1186 3 : elem[index] = elem[parent_index];
1187 3 : index = parent_index;
1188 3 : parent_index = (index - 1) / 2;
1189 : }
1190 1 : elem[index] = item;
1191 1 : return &elem[index];
1192 : }
1193 :
1194 : // A variation on the PushHeap method defined above.
1195 : template<class Item>
1196 1 : elem_type *PushHeap(const Item& item) {
1197 1 : return PushHeap(item, nsDefaultComparator<elem_type, Item>());
1198 : }
1199 :
1200 : // Delete the root of the heap and restore the heap
1201 : // @param comp The Comparator used to restore the heap
1202 : template<class Comparator>
1203 1 : void PopHeap(const Comparator& comp) {
1204 1 : if (!Length()) {
1205 0 : return;
1206 : }
1207 1 : index_type last_index = Length() - 1;
1208 1 : elem_type *elem = Elements();
1209 1 : elem[0] = elem[last_index];
1210 1 : TruncateLength(last_index);
1211 1 : if (Length()) {
1212 1 : SiftDown(0, comp);
1213 : }
1214 : }
1215 :
1216 : // A variation on the PopHeap method defined above.
1217 1 : void PopHeap() {
1218 1 : PopHeap(nsDefaultComparator<elem_type, elem_type>());
1219 1 : }
1220 :
1221 : protected:
1222 : using base_type::Hdr;
1223 : using base_type::ShrinkCapacity;
1224 :
1225 : // This method invokes elem_type's destructor on a range of elements.
1226 : // @param start The index of the first element to destroy.
1227 : // @param count The number of elements to destroy.
1228 11386306 : void DestructRange(index_type start, size_type count) {
1229 11386306 : elem_type *iter = Elements() + start, *end = iter + count;
1230 28277626 : for (; iter != end; ++iter) {
1231 16891320 : elem_traits::Destruct(iter);
1232 : }
1233 11386306 : }
1234 :
1235 : // This method invokes elem_type's copy-constructor on a range of elements.
1236 : // @param start The index of the first element to construct.
1237 : // @param count The number of elements to construct.
1238 : // @param values The array of elements to copy.
1239 : template<class Item>
1240 4755603 : void AssignRange(index_type start, size_type count,
1241 : const Item *values) {
1242 4755603 : elem_type *iter = Elements() + start, *end = iter + count;
1243 9699637 : for (; iter != end; ++iter, ++values) {
1244 4944033 : elem_traits::Construct(iter, *values);
1245 : }
1246 4755604 : }
1247 :
1248 : // This method sifts an item down to its proper place in a binary heap
1249 : // @param index The index of the node to start sifting down from
1250 : // @param comp The Comparator used to sift down
1251 : template<class Comparator>
1252 6 : void SiftDown(index_type index, const Comparator& comp) {
1253 6 : elem_type *elem = Elements();
1254 6 : elem_type item = elem[index];
1255 6 : index_type end = Length() - 1;
1256 18 : while ((index * 2) < end) {
1257 9 : const index_type left = (index * 2) + 1;
1258 9 : const index_type right = (index * 2) + 2;
1259 9 : const index_type parent_index = index;
1260 9 : if (comp.LessThan(item, elem[left])) {
1261 5 : if (left < end &&
1262 : comp.LessThan(elem[left], elem[right])) {
1263 1 : index = right;
1264 : } else {
1265 4 : index = left;
1266 : }
1267 4 : } else if (left < end &&
1268 : comp.LessThan(item, elem[right])) {
1269 1 : index = right;
1270 : } else {
1271 3 : break;
1272 : }
1273 6 : elem[parent_index] = elem[index];
1274 : }
1275 6 : elem[index] = item;
1276 6 : }
1277 : };
1278 :
1279 : //
1280 : // Convenience subtypes of nsTArray.
1281 : //
1282 : template<class E>
1283 : class FallibleTArray : public nsTArray<E, nsTArrayFallibleAllocator>
1284 8731 : {
1285 : public:
1286 : typedef nsTArray<E, nsTArrayFallibleAllocator> base_type;
1287 : typedef typename base_type::size_type size_type;
1288 :
1289 656 : FallibleTArray() {}
1290 8075 : explicit FallibleTArray(size_type capacity) : base_type(capacity) {}
1291 0 : FallibleTArray(const FallibleTArray& other) : base_type(other) {}
1292 : };
1293 :
1294 : #ifdef MOZALLOC_HAVE_XMALLOC
1295 : template<class E>
1296 : class InfallibleTArray : public nsTArray<E, nsTArrayInfallibleAllocator>
1297 1418 : {
1298 : public:
1299 : typedef nsTArray<E, nsTArrayInfallibleAllocator> base_type;
1300 : typedef typename base_type::size_type size_type;
1301 :
1302 1430 : InfallibleTArray() {}
1303 0 : explicit InfallibleTArray(size_type capacity) : base_type(capacity) {}
1304 0 : InfallibleTArray(const InfallibleTArray& other) : base_type(other) {}
1305 : };
1306 : #endif
1307 :
1308 : template<class TArrayBase, PRUint32 N>
1309 : class nsAutoArrayBase : public TArrayBase
1310 6801733 : {
1311 : public:
1312 : typedef TArrayBase base_type;
1313 : typedef typename base_type::Header Header;
1314 : typedef typename base_type::elem_type elem_type;
1315 :
1316 : protected:
1317 6801755 : nsAutoArrayBase() {
1318 6801755 : Init();
1319 6801755 : }
1320 :
1321 : // We need this constructor because nsAutoTArray and friends all have
1322 : // implicit copy-constructors. If we don't have this method, those
1323 : // copy-constructors will call nsAutoArrayBase's implicit copy-constructor,
1324 : // which won't call Init() and set up the auto buffer!
1325 : nsAutoArrayBase(const TArrayBase &aOther) {
1326 : Init();
1327 : AppendElements(aOther);
1328 : }
1329 :
1330 : private:
1331 : // nsTArray_base casts itself as an nsAutoArrayBase in order to get a pointer
1332 : // to mAutoBuf.
1333 : template<class Allocator>
1334 : friend class nsTArray_base;
1335 :
1336 6801755 : void Init() {
1337 : MOZ_STATIC_ASSERT(MOZ_ALIGNOF(elem_type) <= 8,
1338 : "can't handle alignments greater than 8, "
1339 : "see nsTArray_base::UsesAutoArrayBuffer()");
1340 :
1341 6801755 : *base_type::PtrToHdr() = reinterpret_cast<Header*>(&mAutoBuf);
1342 6801755 : base_type::Hdr()->mLength = 0;
1343 6801755 : base_type::Hdr()->mCapacity = N;
1344 6801755 : base_type::Hdr()->mIsAutoArray = 1;
1345 :
1346 6801755 : MOZ_ASSERT(base_type::GetAutoArrayBuffer(MOZ_ALIGNOF(elem_type)) ==
1347 : reinterpret_cast<Header*>(&mAutoBuf),
1348 : "GetAutoArrayBuffer needs to be fixed");
1349 6801755 : }
1350 :
1351 : // Declare mAutoBuf aligned to the maximum of the header's alignment and
1352 : // elem_type's alignment. We need to use a union rather than
1353 : // MOZ_ALIGNED_DECL because GCC is picky about what goes into
1354 : // __attribute__((aligned(foo))).
1355 : union {
1356 : char mAutoBuf[sizeof(nsTArrayHeader) + N * sizeof(elem_type)];
1357 : mozilla::AlignedElem<PR_MAX(MOZ_ALIGNOF(Header), MOZ_ALIGNOF(elem_type))> mAlign;
1358 : };
1359 : };
1360 :
1361 : template<class E, PRUint32 N, class Alloc=nsTArrayDefaultAllocator>
1362 : class nsAutoTArray : public nsAutoArrayBase<nsTArray<E, Alloc>, N>
1363 6800327 : {
1364 : typedef nsAutoArrayBase<nsTArray<E, Alloc>, N> Base;
1365 :
1366 : public:
1367 6793172 : nsAutoTArray() {}
1368 :
1369 : template<typename Allocator>
1370 0 : nsAutoTArray(const nsTArray<E, Allocator>& other) {
1371 0 : Base::AppendElements(other);
1372 0 : }
1373 : };
1374 :
1375 : // Assert that nsAutoTArray doesn't have any extra padding inside.
1376 : //
1377 : // It's important that the data stored in this auto array takes up a multiple of
1378 : // 8 bytes; e.g. nsAutoTArray<PRUint32, 1> wouldn't work. Since nsAutoTArray
1379 : // contains a pointer, its size must be a multiple of alignof(void*). (This is
1380 : // because any type may be placed into an array, and there's no padding between
1381 : // elements of an array.) The compiler pads the end of the structure to
1382 : // enforce this rule.
1383 : //
1384 : // If we used nsAutoTArray<PRUint32, 1> below, this assertion would fail on a
1385 : // 64-bit system, where the compiler inserts 4 bytes of padding at the end of
1386 : // the auto array to make its size a multiple of alignof(void*) == 8 bytes.
1387 :
1388 : MOZ_STATIC_ASSERT(sizeof(nsAutoTArray<PRUint32, 2>) ==
1389 : sizeof(void*) + sizeof(nsTArrayHeader) + sizeof(PRUint32) * 2,
1390 : "nsAutoTArray shouldn't contain any extra padding, "
1391 : "see the comment");
1392 :
1393 : template<class E, PRUint32 N>
1394 : class AutoFallibleTArray : public nsAutoArrayBase<FallibleTArray<E>, N>
1395 0 : {
1396 : typedef nsAutoArrayBase<FallibleTArray<E>, N> Base;
1397 :
1398 : public:
1399 0 : AutoFallibleTArray() {}
1400 :
1401 : template<typename Allocator>
1402 : AutoFallibleTArray(const nsTArray<E, Allocator>& other) {
1403 : Base::AppendElements(other);
1404 : }
1405 : };
1406 :
1407 : #if defined(MOZALLOC_HAVE_XMALLOC)
1408 : template<class E, PRUint32 N>
1409 : class AutoInfallibleTArray : public nsAutoArrayBase<InfallibleTArray<E>, N>
1410 1406 : {
1411 : typedef nsAutoArrayBase<InfallibleTArray<E>, N> Base;
1412 :
1413 : public:
1414 1407 : AutoInfallibleTArray() {}
1415 :
1416 : template<typename Allocator>
1417 0 : AutoInfallibleTArray(const nsTArray<E, Allocator>& other) {
1418 0 : Base::AppendElements(other);
1419 0 : }
1420 : };
1421 : #endif
1422 :
1423 : // specializations for N = 0. this makes the inheritance model easier for
1424 : // templated users of nsAutoTArray.
1425 : template<class E>
1426 : class nsAutoTArray<E, 0, nsTArrayDefaultAllocator> :
1427 : public nsAutoArrayBase< nsTArray<E, nsTArrayDefaultAllocator>, 0>
1428 : {
1429 : public:
1430 7176 : nsAutoTArray() {}
1431 : };
1432 :
1433 : template<class E>
1434 : class AutoFallibleTArray<E, 0> :
1435 : public nsAutoArrayBase< FallibleTArray<E>, 0>
1436 : {
1437 : public:
1438 : AutoFallibleTArray() {}
1439 : };
1440 :
1441 : #if defined(MOZALLOC_HAVE_XMALLOC)
1442 : template<class E>
1443 : class AutoInfallibleTArray<E, 0> :
1444 : public nsAutoArrayBase< InfallibleTArray<E>, 0>
1445 : {
1446 : public:
1447 : AutoInfallibleTArray() {}
1448 : };
1449 : #endif
1450 :
1451 : // Definitions of nsTArray methods
1452 : #include "nsTArray-inl.h"
1453 :
1454 : #endif // nsTArray_h__
|