xpcom/glue/nsTArray.h

branch
TOR_BUG_9701
changeset 8
97036ab72558
equal deleted inserted replaced
-1:000000000000 0:ee7e4894523f
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 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #ifndef nsTArray_h__
8 #define nsTArray_h__
9
10 #include "nsTArrayForwardDeclare.h"
11 #include "mozilla/Alignment.h"
12 #include "mozilla/Assertions.h"
13 #include "mozilla/MemoryReporting.h"
14 #include "mozilla/TypeTraits.h"
15
16 #include <string.h>
17
18 #include "nsCycleCollectionNoteChild.h"
19 #include "nsAlgorithm.h"
20 #include "nscore.h"
21 #include "nsQuickSort.h"
22 #include "nsDebug.h"
23 #include "nsISupportsImpl.h"
24 #include <new>
25
26 namespace JS {
27 template <class T>
28 class Heap;
29 } /* namespace JS */
30
31 class nsRegion;
32 class nsIntRegion;
33
34 //
35 // nsTArray is a resizable array class, like std::vector.
36 //
37 // Unlike std::vector, which follows C++'s construction/destruction rules,
38 // nsTArray assumes that your "T" can be memmoved()'ed safely.
39 //
40 // The public classes defined in this header are
41 //
42 // nsTArray<T>,
43 // FallibleTArray<T>,
44 // nsAutoTArray<T, N>, and
45 // AutoFallibleTArray<T, N>.
46 //
47 // nsTArray and nsAutoTArray are infallible; if one tries to make an allocation
48 // which fails, it crashes the program. In contrast, FallibleTArray and
49 // AutoFallibleTArray are fallible; if you use one of these classes, you must
50 // check the return values of methods such as Append() which may allocate. If
51 // in doubt, choose an infallible type.
52 //
53 // InfallibleTArray and AutoInfallibleTArray are aliases for nsTArray and
54 // nsAutoTArray.
55 //
56 // If you just want to declare the nsTArray types (e.g., if you're in a header
57 // file and don't need the full nsTArray definitions) consider including
58 // nsTArrayForwardDeclare.h instead of nsTArray.h.
59 //
60 // The template parameter (i.e., T in nsTArray<T>) specifies the type of the
61 // elements and has the following requirements:
62 //
63 // T MUST be safely memmove()'able.
64 // T MUST define a copy-constructor.
65 // T MAY define operator< for sorting.
66 // T MAY define operator== for searching.
67 //
68 // (Note that the memmove requirement may be relaxed for certain types - see
69 // nsTArray_CopyChooser below.)
70 //
71 // For methods taking a Comparator instance, the Comparator must be a class
72 // defining the following methods:
73 //
74 // class Comparator {
75 // public:
76 // /** @return True if the elements are equals; false otherwise. */
77 // bool Equals(const elem_type& a, const Item& b) const;
78 //
79 // /** @return True if (a < b); false otherwise. */
80 // bool LessThan(const elem_type& a, const Item& b) const;
81 // };
82 //
83 // The Equals method is used for searching, and the LessThan method is used for
84 // searching and sorting. The |Item| type above can be arbitrary, but must
85 // match the Item type passed to the sort or search function.
86 //
87
88
89 //
90 // nsTArrayFallibleResult and nsTArrayInfallibleResult types are proxy types
91 // which are used because you cannot use a templated type which is bound to
92 // void as an argument to a void function. In order to work around that, we
93 // encode either a void or a boolean inside these proxy objects, and pass them
94 // to the aforementioned function instead, and then use the type information to
95 // decide what to do in the function.
96 //
97 // Note that public nsTArray methods should never return a proxy type. Such
98 // types are only meant to be used in the internal nsTArray helper methods.
99 // Public methods returning non-proxy types cannot be called from other
100 // nsTArray members.
101 //
102 struct nsTArrayFallibleResult
103 {
104 // Note: allows implicit conversions from and to bool
105 nsTArrayFallibleResult(bool result)
106 : mResult(result)
107 {}
108
109 operator bool() {
110 return mResult;
111 }
112
113 private:
114 bool mResult;
115 };
116
117 struct nsTArrayInfallibleResult
118 {
119 };
120
121 //
122 // nsTArray*Allocators must all use the same |free()|, to allow swap()'ing
123 // between fallible and infallible variants.
124 //
125
126 struct nsTArrayFallibleAllocatorBase
127 {
128 typedef bool ResultType;
129 typedef nsTArrayFallibleResult ResultTypeProxy;
130
131 static ResultType Result(ResultTypeProxy result) {
132 return result;
133 }
134
135 static bool Successful(ResultTypeProxy result) {
136 return result;
137 }
138
139 static ResultTypeProxy SuccessResult() {
140 return true;
141 }
142
143 static ResultTypeProxy FailureResult() {
144 return false;
145 }
146
147 static ResultType ConvertBoolToResultType(bool aValue) {
148 return aValue;
149 }
150 };
151
152 struct nsTArrayInfallibleAllocatorBase
153 {
154 typedef void ResultType;
155 typedef nsTArrayInfallibleResult ResultTypeProxy;
156
157 static ResultType Result(ResultTypeProxy result) {
158 }
159
160 static bool Successful(ResultTypeProxy) {
161 return true;
162 }
163
164 static ResultTypeProxy SuccessResult() {
165 return ResultTypeProxy();
166 }
167
168 static ResultTypeProxy FailureResult() {
169 NS_RUNTIMEABORT("Infallible nsTArray should never fail");
170 return ResultTypeProxy();
171 }
172
173 static ResultType ConvertBoolToResultType(bool aValue) {
174 if (!aValue) {
175 NS_RUNTIMEABORT("infallible nsTArray should never convert false to ResultType");
176 }
177 }
178 };
179
180 #if defined(MOZALLOC_HAVE_XMALLOC)
181 #include "mozilla/mozalloc_abort.h"
182
183 struct nsTArrayFallibleAllocator : nsTArrayFallibleAllocatorBase
184 {
185 static void* Malloc(size_t size) {
186 return moz_malloc(size);
187 }
188
189 static void* Realloc(void* ptr, size_t size) {
190 return moz_realloc(ptr, size);
191 }
192
193 static void Free(void* ptr) {
194 moz_free(ptr);
195 }
196
197 static void SizeTooBig(size_t) {
198 }
199 };
200
201 struct nsTArrayInfallibleAllocator : nsTArrayInfallibleAllocatorBase
202 {
203 static void* Malloc(size_t size) {
204 return moz_xmalloc(size);
205 }
206
207 static void* Realloc(void* ptr, size_t size) {
208 return moz_xrealloc(ptr, size);
209 }
210
211 static void Free(void* ptr) {
212 moz_free(ptr);
213 }
214
215 static void SizeTooBig(size_t size) {
216 NS_ABORT_OOM(size);
217 }
218 };
219
220 #else
221 #include <stdlib.h>
222
223 struct nsTArrayFallibleAllocator : nsTArrayFallibleAllocatorBase
224 {
225 static void* Malloc(size_t size) {
226 return malloc(size);
227 }
228
229 static void* Realloc(void* ptr, size_t size) {
230 return realloc(ptr, size);
231 }
232
233 static void Free(void* ptr) {
234 free(ptr);
235 }
236
237 static void SizeTooBig(size_t) {
238 }
239 };
240
241 struct nsTArrayInfallibleAllocator : nsTArrayInfallibleAllocatorBase
242 {
243 static void* Malloc(size_t size) {
244 void* ptr = malloc(size);
245 if (MOZ_UNLIKELY(!ptr)) {
246 NS_ABORT_OOM(size);
247 }
248 return ptr;
249 }
250
251 static void* Realloc(void* ptr, size_t size) {
252 void* newptr = realloc(ptr, size);
253 if (MOZ_UNLIKELY(!ptr && size)) {
254 NS_ABORT_OOM(size);
255 }
256 return newptr;
257 }
258
259 static void Free(void* ptr) {
260 free(ptr);
261 }
262
263 static void SizeTooBig(size_t size) {
264 NS_ABORT_OOM(size);
265 }
266 };
267
268 #endif
269
270 // nsTArray_base stores elements into the space allocated beyond
271 // sizeof(*this). This is done to minimize the size of the nsTArray
272 // object when it is empty.
273 struct NS_COM_GLUE nsTArrayHeader
274 {
275 static nsTArrayHeader sEmptyHdr;
276
277 uint32_t mLength;
278 uint32_t mCapacity : 31;
279 uint32_t mIsAutoArray : 1;
280 };
281
282 // This class provides a SafeElementAt method to nsTArray<T*> which does
283 // not take a second default value parameter.
284 template <class E, class Derived>
285 struct nsTArray_SafeElementAtHelper
286 {
287 typedef E* elem_type;
288 typedef uint32_t index_type;
289
290 // No implementation is provided for these two methods, and that is on
291 // purpose, since we don't support these functions on non-pointer type
292 // instantiations.
293 elem_type& SafeElementAt(index_type i);
294 const elem_type& SafeElementAt(index_type i) const;
295 };
296
297 template <class E, class Derived>
298 struct nsTArray_SafeElementAtHelper<E*, Derived>
299 {
300 typedef E* elem_type;
301 typedef uint32_t index_type;
302
303 elem_type SafeElementAt(index_type i) {
304 return static_cast<Derived*> (this)->SafeElementAt(i, nullptr);
305 }
306
307 const elem_type SafeElementAt(index_type i) const {
308 return static_cast<const Derived*> (this)->SafeElementAt(i, nullptr);
309 }
310 };
311
312 // E is the base type that the smart pointer is templated over; the
313 // smart pointer can act as E*.
314 template <class E, class Derived>
315 struct nsTArray_SafeElementAtSmartPtrHelper
316 {
317 typedef E* elem_type;
318 typedef uint32_t index_type;
319
320 elem_type SafeElementAt(index_type i) {
321 return static_cast<Derived*> (this)->SafeElementAt(i, nullptr);
322 }
323
324 const elem_type SafeElementAt(index_type i) const {
325 return static_cast<const Derived*> (this)->SafeElementAt(i, nullptr);
326 }
327 };
328
329 template <class T> class nsCOMPtr;
330
331 template <class E, class Derived>
332 struct nsTArray_SafeElementAtHelper<nsCOMPtr<E>, Derived> :
333 public nsTArray_SafeElementAtSmartPtrHelper<E, Derived>
334 {
335 };
336
337 template <class T> class nsRefPtr;
338
339 template <class E, class Derived>
340 struct nsTArray_SafeElementAtHelper<nsRefPtr<E>, Derived> :
341 public nsTArray_SafeElementAtSmartPtrHelper<E, Derived>
342 {
343 };
344
345 //
346 // This class serves as a base class for nsTArray. It shouldn't be used
347 // directly. It holds common implementation code that does not depend on the
348 // element type of the nsTArray.
349 //
350 template<class Alloc, class Copy>
351 class nsTArray_base
352 {
353 // Allow swapping elements with |nsTArray_base|s created using a
354 // different allocator. This is kosher because all allocators use
355 // the same free().
356 template<class Allocator, class Copier>
357 friend class nsTArray_base;
358
359 protected:
360 typedef nsTArrayHeader Header;
361
362 public:
363 typedef uint32_t size_type;
364 typedef uint32_t index_type;
365
366 // @return The number of elements in the array.
367 size_type Length() const {
368 return mHdr->mLength;
369 }
370
371 // @return True if the array is empty or false otherwise.
372 bool IsEmpty() const {
373 return Length() == 0;
374 }
375
376 // @return The number of elements that can fit in the array without forcing
377 // the array to be re-allocated. The length of an array is always less
378 // than or equal to its capacity.
379 size_type Capacity() const {
380 return mHdr->mCapacity;
381 }
382
383 #ifdef DEBUG
384 void* DebugGetHeader() const {
385 return mHdr;
386 }
387 #endif
388
389 protected:
390 nsTArray_base();
391
392 ~nsTArray_base();
393
394 // Resize the storage if necessary to achieve the requested capacity.
395 // @param capacity The requested number of array elements.
396 // @param elemSize The size of an array element.
397 // @return False if insufficient memory is available; true otherwise.
398 typename Alloc::ResultTypeProxy EnsureCapacity(size_type capacity, size_type elemSize);
399
400 // Resize the storage to the minimum required amount.
401 // @param elemSize The size of an array element.
402 // @param elemAlign The alignment in bytes of an array element.
403 void ShrinkCapacity(size_type elemSize, size_t elemAlign);
404
405 // This method may be called to resize a "gap" in the array by shifting
406 // elements around. It updates mLength appropriately. If the resulting
407 // array has zero elements, then the array's memory is free'd.
408 // @param start The starting index of the gap.
409 // @param oldLen The current length of the gap.
410 // @param newLen The desired length of the gap.
411 // @param elemSize The size of an array element.
412 // @param elemAlign The alignment in bytes of an array element.
413 void ShiftData(index_type start, size_type oldLen, size_type newLen,
414 size_type elemSize, size_t elemAlign);
415
416 // This method increments the length member of the array's header.
417 // Note that mHdr may actually be sEmptyHdr in the case where a
418 // zero-length array is inserted into our array. But then n should
419 // always be 0.
420 void IncrementLength(uint32_t n) {
421 if (mHdr == EmptyHdr()) {
422 if (MOZ_UNLIKELY(n != 0)) {
423 // Writing a non-zero length to the empty header would be extremely bad.
424 MOZ_CRASH();
425 }
426 } else {
427 mHdr->mLength += n;
428 }
429 }
430
431 // This method inserts blank slots into the array.
432 // @param index the place to insert the new elements. This must be no
433 // greater than the current length of the array.
434 // @param count the number of slots to insert
435 // @param elementSize the size of an array element.
436 // @param elemAlign the alignment in bytes of an array element.
437 bool InsertSlotsAt(index_type index, size_type count,
438 size_type elementSize, size_t elemAlign);
439
440 protected:
441 template<class Allocator>
442 typename Alloc::ResultTypeProxy
443 SwapArrayElements(nsTArray_base<Allocator, Copy>& other,
444 size_type elemSize,
445 size_t elemAlign);
446
447 // This is an RAII class used in SwapArrayElements.
448 class IsAutoArrayRestorer {
449 public:
450 IsAutoArrayRestorer(nsTArray_base<Alloc, Copy> &array, size_t elemAlign);
451 ~IsAutoArrayRestorer();
452
453 private:
454 nsTArray_base<Alloc, Copy> &mArray;
455 size_t mElemAlign;
456 bool mIsAuto;
457 };
458
459 // Helper function for SwapArrayElements. Ensures that if the array
460 // is an nsAutoTArray that it doesn't use the built-in buffer.
461 bool EnsureNotUsingAutoArrayBuffer(size_type elemSize);
462
463 // Returns true if this nsTArray is an nsAutoTArray with a built-in buffer.
464 bool IsAutoArray() const {
465 return mHdr->mIsAutoArray;
466 }
467
468 // Returns a Header for the built-in buffer of this nsAutoTArray.
469 Header* GetAutoArrayBuffer(size_t elemAlign) {
470 MOZ_ASSERT(IsAutoArray(), "Should be an auto array to call this");
471 return GetAutoArrayBufferUnsafe(elemAlign);
472 }
473 const Header* GetAutoArrayBuffer(size_t elemAlign) const {
474 MOZ_ASSERT(IsAutoArray(), "Should be an auto array to call this");
475 return GetAutoArrayBufferUnsafe(elemAlign);
476 }
477
478 // Returns a Header for the built-in buffer of this nsAutoTArray, but doesn't
479 // assert that we are an nsAutoTArray.
480 Header* GetAutoArrayBufferUnsafe(size_t elemAlign) {
481 return const_cast<Header*>(static_cast<const nsTArray_base<Alloc, Copy>*>(this)->
482 GetAutoArrayBufferUnsafe(elemAlign));
483 }
484 const Header* GetAutoArrayBufferUnsafe(size_t elemAlign) const;
485
486 // Returns true if this is an nsAutoTArray and it currently uses the
487 // built-in buffer to store its elements.
488 bool UsesAutoArrayBuffer() const;
489
490 // The array's elements (prefixed with a Header). This pointer is never
491 // null. If the array is empty, then this will point to sEmptyHdr.
492 Header *mHdr;
493
494 Header* Hdr() const {
495 return mHdr;
496 }
497
498 Header** PtrToHdr() {
499 return &mHdr;
500 }
501
502 static Header* EmptyHdr() {
503 return &Header::sEmptyHdr;
504 }
505 };
506
507 //
508 // This class defines convenience functions for element specific operations.
509 // Specialize this template if necessary.
510 //
511 template<class E>
512 class nsTArrayElementTraits
513 {
514 public:
515 // Invoke the default constructor in place.
516 static inline void Construct(E *e) {
517 // Do NOT call "E()"! That triggers C++ "default initialization"
518 // which zeroes out POD ("plain old data") types such as regular
519 // ints. We don't want that because it can be a performance issue
520 // and people don't expect it; nsTArray should work like a regular
521 // C/C++ array in this respect.
522 new (static_cast<void *>(e)) E;
523 }
524 // Invoke the copy-constructor in place.
525 template<class A>
526 static inline void Construct(E *e, const A &arg) {
527 typedef typename mozilla::RemoveCV<E>::Type E_NoCV;
528 typedef typename mozilla::RemoveCV<A>::Type A_NoCV;
529 static_assert(!mozilla::IsSame<E_NoCV*, A_NoCV>::value,
530 "For safety, we disallow constructing nsTArray<E> elements "
531 "from E* pointers. See bug 960591.");
532 new (static_cast<void *>(e)) E(arg);
533 }
534 // Invoke the destructor in place.
535 static inline void Destruct(E *e) {
536 e->~E();
537 }
538 };
539
540 // The default comparator used by nsTArray
541 template<class A, class B>
542 class nsDefaultComparator
543 {
544 public:
545 bool Equals(const A& a, const B& b) const {
546 return a == b;
547 }
548 bool LessThan(const A& a, const B& b) const {
549 return a < b;
550 }
551 };
552
553 template <class E> class InfallibleTArray;
554 template <class E> class FallibleTArray;
555
556 template<bool IsPod, bool IsSameType>
557 struct AssignRangeAlgorithm {
558 template<class Item, class ElemType, class IndexType, class SizeType>
559 static void implementation(ElemType* elements, IndexType start,
560 SizeType count, const Item *values) {
561 ElemType *iter = elements + start, *end = iter + count;
562 for (; iter != end; ++iter, ++values)
563 nsTArrayElementTraits<ElemType>::Construct(iter, *values);
564 }
565 };
566
567 template<>
568 struct AssignRangeAlgorithm<true, true> {
569 template<class Item, class ElemType, class IndexType, class SizeType>
570 static void implementation(ElemType* elements, IndexType start,
571 SizeType count, const Item *values) {
572 memcpy(elements + start, values, count * sizeof(ElemType));
573 }
574 };
575
576 //
577 // Normally elements are copied with memcpy and memmove, but for some element
578 // types that is problematic. The nsTArray_CopyChooser template class can be
579 // specialized to ensure that copying calls constructors and destructors
580 // instead, as is done below for JS::Heap<E> elements.
581 //
582
583 //
584 // A class that defines how to copy elements using memcpy/memmove.
585 //
586 struct nsTArray_CopyWithMemutils
587 {
588 const static bool allowRealloc = true;
589
590 static void CopyElements(void* dest, const void* src, size_t count, size_t elemSize) {
591 memcpy(dest, src, count * elemSize);
592 }
593
594 static void CopyHeaderAndElements(void* dest, const void* src, size_t count, size_t elemSize) {
595 memcpy(dest, src, sizeof(nsTArrayHeader) + count * elemSize);
596 }
597
598 static void MoveElements(void* dest, const void* src, size_t count, size_t elemSize) {
599 memmove(dest, src, count * elemSize);
600 }
601 };
602
603 //
604 // A template class that defines how to copy elements calling their constructors
605 // and destructors appropriately.
606 //
607 template <class ElemType>
608 struct nsTArray_CopyWithConstructors
609 {
610 typedef nsTArrayElementTraits<ElemType> traits;
611
612 const static bool allowRealloc = false;
613
614 static void CopyElements(void* dest, void* src, size_t count, size_t elemSize) {
615 ElemType* destElem = static_cast<ElemType*>(dest);
616 ElemType* srcElem = static_cast<ElemType*>(src);
617 ElemType* destElemEnd = destElem + count;
618 #ifdef DEBUG
619 ElemType* srcElemEnd = srcElem + count;
620 MOZ_ASSERT(srcElemEnd <= destElem || srcElemEnd > destElemEnd);
621 #endif
622 while (destElem != destElemEnd) {
623 traits::Construct(destElem, *srcElem);
624 traits::Destruct(srcElem);
625 ++destElem;
626 ++srcElem;
627 }
628 }
629
630 static void CopyHeaderAndElements(void* dest, void* src, size_t count, size_t elemSize) {
631 nsTArrayHeader* destHeader = static_cast<nsTArrayHeader*>(dest);
632 nsTArrayHeader* srcHeader = static_cast<nsTArrayHeader*>(src);
633 *destHeader = *srcHeader;
634 CopyElements(static_cast<uint8_t*>(dest) + sizeof(nsTArrayHeader),
635 static_cast<uint8_t*>(src) + sizeof(nsTArrayHeader),
636 count, elemSize);
637 }
638
639 static void MoveElements(void* dest, void* src, size_t count, size_t elemSize) {
640 ElemType* destElem = static_cast<ElemType*>(dest);
641 ElemType* srcElem = static_cast<ElemType*>(src);
642 ElemType* destElemEnd = destElem + count;
643 ElemType* srcElemEnd = srcElem + count;
644 if (destElem == srcElem) {
645 return; // In practice, we don't do this.
646 } else if (srcElemEnd > destElem && srcElemEnd < destElemEnd) {
647 while (destElemEnd != destElem) {
648 --destElemEnd;
649 --srcElemEnd;
650 traits::Construct(destElemEnd, *srcElemEnd);
651 traits::Destruct(srcElem);
652 }
653 } else {
654 CopyElements(dest, src, count, elemSize);
655 }
656 }
657 };
658
659 //
660 // The default behaviour is to use memcpy/memmove for everything.
661 //
662 template <class E>
663 struct nsTArray_CopyChooser {
664 typedef nsTArray_CopyWithMemutils Type;
665 };
666
667 //
668 // Some classes require constructors/destructors to be called, so they are
669 // specialized here.
670 //
671 template <class E>
672 struct nsTArray_CopyChooser<JS::Heap<E> > {
673 typedef nsTArray_CopyWithConstructors<JS::Heap<E> > Type;
674 };
675
676 template<>
677 struct nsTArray_CopyChooser<nsRegion> {
678 typedef nsTArray_CopyWithConstructors<nsRegion> Type;
679 };
680
681 template<>
682 struct nsTArray_CopyChooser<nsIntRegion> {
683 typedef nsTArray_CopyWithConstructors<nsIntRegion> Type;
684 };
685
686 //
687 // Base class for nsTArray_Impl that is templated on element type and derived
688 // nsTArray_Impl class, to allow extra conversions to be added for specific
689 // types.
690 //
691 template <class E, class Derived>
692 struct nsTArray_TypedBase : public nsTArray_SafeElementAtHelper<E, Derived> {};
693
694 //
695 // Specialization of nsTArray_TypedBase for arrays containing JS::Heap<E>
696 // elements.
697 //
698 // These conversions are safe because JS::Heap<E> and E share the same
699 // representation, and since the result of the conversions are const references
700 // we won't miss any barriers.
701 //
702 // The static_cast is necessary to obtain the correct address for the derived
703 // class since we are a base class used in multiple inheritance.
704 //
705 template <class E, class Derived>
706 struct nsTArray_TypedBase<JS::Heap<E>, Derived>
707 : public nsTArray_SafeElementAtHelper<JS::Heap<E>, Derived>
708 {
709 operator const nsTArray<E>& () {
710 static_assert(sizeof(E) == sizeof(JS::Heap<E>),
711 "JS::Heap<E> must be binary compatible with E.");
712 Derived* self = static_cast<Derived*>(this);
713 return *reinterpret_cast<nsTArray<E> *>(self);
714 }
715
716 operator const FallibleTArray<E>& () {
717 Derived* self = static_cast<Derived*>(this);
718 return *reinterpret_cast<FallibleTArray<E> *>(self);
719 }
720 };
721
722
723 //
724 // nsTArray_Impl contains most of the guts supporting nsTArray, FallibleTArray,
725 // nsAutoTArray, and AutoFallibleTArray.
726 //
727 // The only situation in which you might need to use nsTArray_Impl in your code
728 // is if you're writing code which mutates a TArray which may or may not be
729 // infallible.
730 //
731 // Code which merely reads from a TArray which may or may not be infallible can
732 // simply cast the TArray to |const nsTArray&|; both fallible and infallible
733 // TArrays can be cast to |const nsTArray&|.
734 //
735 template<class E, class Alloc>
736 class nsTArray_Impl : public nsTArray_base<Alloc, typename nsTArray_CopyChooser<E>::Type>,
737 public nsTArray_TypedBase<E, nsTArray_Impl<E, Alloc> >
738 {
739 public:
740 typedef typename nsTArray_CopyChooser<E>::Type copy_type;
741 typedef nsTArray_base<Alloc, copy_type> base_type;
742 typedef typename base_type::size_type size_type;
743 typedef typename base_type::index_type index_type;
744 typedef E elem_type;
745 typedef nsTArray_Impl<E, Alloc> self_type;
746 typedef nsTArrayElementTraits<E> elem_traits;
747 typedef nsTArray_SafeElementAtHelper<E, self_type> safeelementat_helper_type;
748
749 using safeelementat_helper_type::SafeElementAt;
750 using base_type::EmptyHdr;
751
752 // A special value that is used to indicate an invalid or unknown index
753 // into the array.
754 enum {
755 NoIndex = index_type(-1)
756 };
757
758 using base_type::Length;
759
760 //
761 // Finalization method
762 //
763
764 ~nsTArray_Impl() { Clear(); }
765
766 //
767 // Initialization methods
768 //
769
770 nsTArray_Impl() {}
771
772 // Initialize this array and pre-allocate some number of elements.
773 explicit nsTArray_Impl(size_type capacity) {
774 SetCapacity(capacity);
775 }
776
777 // The array's copy-constructor performs a 'deep' copy of the given array.
778 // @param other The array object to copy.
779 //
780 // It's very important that we declare this method as taking |const
781 // self_type&| as opposed to taking |const nsTArray_Impl<E, OtherAlloc>| for
782 // an arbitrary OtherAlloc.
783 //
784 // If we don't declare a constructor taking |const self_type&|, C++ generates
785 // a copy-constructor for this class which merely copies the object's
786 // members, which is obviously wrong.
787 //
788 // You can pass an nsTArray_Impl<E, OtherAlloc> to this method because
789 // nsTArray_Impl<E, X> can be cast to const nsTArray_Impl<E, Y>&. So the
790 // effect on the API is the same as if we'd declared this method as taking
791 // |const nsTArray_Impl<E, OtherAlloc>&|.
792 explicit nsTArray_Impl(const self_type& other) {
793 AppendElements(other);
794 }
795
796 // Allow converting to a const array with a different kind of allocator,
797 // Since the allocator doesn't matter for const arrays
798 template<typename Allocator>
799 operator const nsTArray_Impl<E, Allocator>&() const {
800 return *reinterpret_cast<const nsTArray_Impl<E, Allocator>*>(this);
801 }
802 // And we have to do this for our subclasses too
803 operator const nsTArray<E>&() const {
804 return *reinterpret_cast<const InfallibleTArray<E>*>(this);
805 }
806 operator const FallibleTArray<E>&() const {
807 return *reinterpret_cast<const FallibleTArray<E>*>(this);
808 }
809
810 // The array's assignment operator performs a 'deep' copy of the given
811 // array. It is optimized to reuse existing storage if possible.
812 // @param other The array object to copy.
813 self_type& operator=(const self_type& other) {
814 ReplaceElementsAt(0, Length(), other.Elements(), other.Length());
815 return *this;
816 }
817
818 // Return true if this array has the same length and the same
819 // elements as |other|.
820 template<typename Allocator>
821 bool operator==(const nsTArray_Impl<E, Allocator>& other) const {
822 size_type len = Length();
823 if (len != other.Length())
824 return false;
825
826 // XXX std::equal would be as fast or faster here
827 for (index_type i = 0; i < len; ++i)
828 if (!(operator[](i) == other[i]))
829 return false;
830
831 return true;
832 }
833
834 // Return true if this array does not have the same length and the same
835 // elements as |other|.
836 bool operator!=(const self_type& other) const {
837 return !operator==(other);
838 }
839
840 template<typename Allocator>
841 self_type& operator=(const nsTArray_Impl<E, Allocator>& other) {
842 ReplaceElementsAt(0, Length(), other.Elements(), other.Length());
843 return *this;
844 }
845
846 // @return The amount of memory used by this nsTArray_Impl, excluding
847 // sizeof(*this).
848 size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
849 if (this->UsesAutoArrayBuffer() || Hdr() == EmptyHdr())
850 return 0;
851 return mallocSizeOf(this->Hdr());
852 }
853
854 // @return The amount of memory used by this nsTArray_Impl, including
855 // sizeof(*this).
856 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
857 return mallocSizeOf(this) + SizeOfExcludingThis(mallocSizeOf);
858 }
859
860 //
861 // Accessor methods
862 //
863
864 // This method provides direct access to the array elements.
865 // @return A pointer to the first element of the array. If the array is
866 // empty, then this pointer must not be dereferenced.
867 elem_type* Elements() {
868 return reinterpret_cast<elem_type *>(Hdr() + 1);
869 }
870
871 // This method provides direct, readonly access to the array elements.
872 // @return A pointer to the first element of the array. If the array is
873 // empty, then this pointer must not be dereferenced.
874 const elem_type* Elements() const {
875 return reinterpret_cast<const elem_type *>(Hdr() + 1);
876 }
877
878 // This method provides direct access to the i'th element of the array.
879 // The given index must be within the array bounds.
880 // @param i The index of an element in the array.
881 // @return A reference to the i'th element of the array.
882 elem_type& ElementAt(index_type i) {
883 MOZ_ASSERT(i < Length(), "invalid array index");
884 return Elements()[i];
885 }
886
887 // This method provides direct, readonly access to the i'th element of the
888 // array. The given index must be within the array bounds.
889 // @param i The index of an element in the array.
890 // @return A const reference to the i'th element of the array.
891 const elem_type& ElementAt(index_type i) const {
892 MOZ_ASSERT(i < Length(), "invalid array index");
893 return Elements()[i];
894 }
895
896 // This method provides direct access to the i'th element of the array in
897 // a bounds safe manner. If the requested index is out of bounds the
898 // provided default value is returned.
899 // @param i The index of an element in the array.
900 // @param def The value to return if the index is out of bounds.
901 elem_type& SafeElementAt(index_type i, elem_type& def) {
902 return i < Length() ? Elements()[i] : def;
903 }
904
905 // This method provides direct access to the i'th element of the array in
906 // a bounds safe manner. If the requested index is out of bounds the
907 // provided default value is returned.
908 // @param i The index of an element in the array.
909 // @param def The value to return if the index is out of bounds.
910 const elem_type& SafeElementAt(index_type i, const elem_type& def) const {
911 return i < Length() ? Elements()[i] : def;
912 }
913
914 // Shorthand for ElementAt(i)
915 elem_type& operator[](index_type i) {
916 return ElementAt(i);
917 }
918
919 // Shorthand for ElementAt(i)
920 const elem_type& operator[](index_type i) const {
921 return ElementAt(i);
922 }
923
924 // Shorthand for ElementAt(length - 1)
925 elem_type& LastElement() {
926 return ElementAt(Length() - 1);
927 }
928
929 // Shorthand for ElementAt(length - 1)
930 const elem_type& LastElement() const {
931 return ElementAt(Length() - 1);
932 }
933
934 // Shorthand for SafeElementAt(length - 1, def)
935 elem_type& SafeLastElement(elem_type& def) {
936 return SafeElementAt(Length() - 1, def);
937 }
938
939 // Shorthand for SafeElementAt(length - 1, def)
940 const elem_type& SafeLastElement(const elem_type& def) const {
941 return SafeElementAt(Length() - 1, def);
942 }
943
944 //
945 // Search methods
946 //
947
948 // This method searches for the first element in this array that is equal
949 // to the given element.
950 // @param item The item to search for.
951 // @param comp The Comparator used to determine element equality.
952 // @return true if the element was found.
953 template<class Item, class Comparator>
954 bool Contains(const Item& item, const Comparator& comp) const {
955 return IndexOf(item, 0, comp) != NoIndex;
956 }
957
958 // This method searches for the first element in this array that is equal
959 // to the given element. This method assumes that 'operator==' is defined
960 // for elem_type.
961 // @param item The item to search for.
962 // @return true if the element was found.
963 template<class Item>
964 bool Contains(const Item& item) const {
965 return IndexOf(item) != NoIndex;
966 }
967
968 // This method searches for the offset of the first element in this
969 // array that is equal to the given element.
970 // @param item The item to search for.
971 // @param start The index to start from.
972 // @param comp The Comparator used to determine element equality.
973 // @return The index of the found element or NoIndex if not found.
974 template<class Item, class Comparator>
975 index_type IndexOf(const Item& item, index_type start,
976 const Comparator& comp) const {
977 const elem_type* iter = Elements() + start, *end = Elements() + Length();
978 for (; iter != end; ++iter) {
979 if (comp.Equals(*iter, item))
980 return index_type(iter - Elements());
981 }
982 return NoIndex;
983 }
984
985 // This method searches for the offset of the first element in this
986 // array that is equal to the given element. This method assumes
987 // that 'operator==' is defined for elem_type.
988 // @param item The item to search for.
989 // @param start The index to start from.
990 // @return The index of the found element or NoIndex if not found.
991 template<class Item>
992 index_type IndexOf(const Item& item, index_type start = 0) const {
993 return IndexOf(item, start, nsDefaultComparator<elem_type, Item>());
994 }
995
996 // This method searches for the offset of the last element in this
997 // array that is equal to the given element.
998 // @param item The item to search for.
999 // @param start The index to start from. If greater than or equal to the
1000 // length of the array, then the entire array is searched.
1001 // @param comp The Comparator used to determine element equality.
1002 // @return The index of the found element or NoIndex if not found.
1003 template<class Item, class Comparator>
1004 index_type LastIndexOf(const Item& item, index_type start,
1005 const Comparator& comp) const {
1006 size_type endOffset = start >= Length() ? Length() : start + 1;
1007 const elem_type* end = Elements() - 1, *iter = end + endOffset;
1008 for (; iter != end; --iter) {
1009 if (comp.Equals(*iter, item))
1010 return index_type(iter - Elements());
1011 }
1012 return NoIndex;
1013 }
1014
1015 // This method searches for the offset of the last element in this
1016 // array that is equal to the given element. This method assumes
1017 // that 'operator==' is defined for elem_type.
1018 // @param item The item to search for.
1019 // @param start The index to start from. If greater than or equal to the
1020 // length of the array, then the entire array is searched.
1021 // @return The index of the found element or NoIndex if not found.
1022 template<class Item>
1023 index_type LastIndexOf(const Item& item,
1024 index_type start = NoIndex) const {
1025 return LastIndexOf(item, start, nsDefaultComparator<elem_type, Item>());
1026 }
1027
1028 // This method searches for the offset for the element in this array
1029 // that is equal to the given element. The array is assumed to be sorted.
1030 // @param item The item to search for.
1031 // @param comp The Comparator used.
1032 // @return The index of the found element or NoIndex if not found.
1033 template<class Item, class Comparator>
1034 index_type BinaryIndexOf(const Item& item, const Comparator& comp) const {
1035 index_type low = 0, high = Length();
1036 while (high > low) {
1037 index_type mid = (high + low) >> 1;
1038 if (comp.Equals(ElementAt(mid), item))
1039 return mid;
1040 if (comp.LessThan(ElementAt(mid), item))
1041 low = mid + 1;
1042 else
1043 high = mid;
1044 }
1045 return NoIndex;
1046 }
1047
1048 // This method searches for the offset for the element in this array
1049 // that is equal to the given element. The array is assumed to be sorted.
1050 // This method assumes that 'operator==' and 'operator<' are defined.
1051 // @param item The item to search for.
1052 // @return The index of the found element or NoIndex if not found.
1053 template<class Item>
1054 index_type BinaryIndexOf(const Item& item) const {
1055 return BinaryIndexOf(item, nsDefaultComparator<elem_type, Item>());
1056 }
1057
1058 //
1059 // Mutation methods
1060 //
1061 // This method call the destructor on each element of the array, empties it,
1062 // but does not shrink the array's capacity.
1063 // See also SetLengthAndRetainStorage.
1064 // Make sure to call Compact() if needed to avoid keeping a huge array
1065 // around.
1066 void ClearAndRetainStorage() {
1067 if (base_type::mHdr == EmptyHdr()) {
1068 return;
1069 }
1070
1071 DestructRange(0, Length());
1072 base_type::mHdr->mLength = 0;
1073 }
1074
1075 // This method modifies the length of the array, but unlike SetLength
1076 // it doesn't deallocate/reallocate the current internal storage.
1077 // The new length MUST be shorter than or equal to the current capacity.
1078 // If the new length is larger than the existing length of the array,
1079 // then new elements will be constructed using elem_type's default
1080 // constructor. If shorter, elements will be destructed and removed.
1081 // See also ClearAndRetainStorage.
1082 // @param newLen The desired length of this array.
1083 void SetLengthAndRetainStorage(size_type newLen) {
1084 MOZ_ASSERT(newLen <= base_type::Capacity());
1085 size_type oldLen = Length();
1086 if (newLen > oldLen) {
1087 InsertElementsAt(oldLen, newLen - oldLen);
1088 return;
1089 }
1090 if (newLen < oldLen) {
1091 DestructRange(newLen, oldLen - newLen);
1092 base_type::mHdr->mLength = newLen;
1093 }
1094 }
1095
1096 // This method replaces a range of elements in this array.
1097 // @param start The starting index of the elements to replace.
1098 // @param count The number of elements to replace. This may be zero to
1099 // insert elements without removing any existing elements.
1100 // @param array The values to copy into this array. Must be non-null,
1101 // and these elements must not already exist in the array
1102 // being modified.
1103 // @param arrayLen The number of values to copy into this array.
1104 // @return A pointer to the new elements in the array, or null if
1105 // the operation failed due to insufficient memory.
1106 template<class Item>
1107 elem_type *ReplaceElementsAt(index_type start, size_type count,
1108 const Item* array, size_type arrayLen) {
1109 // Adjust memory allocation up-front to catch errors.
1110 if (!Alloc::Successful(this->EnsureCapacity(Length() + arrayLen - count, sizeof(elem_type))))
1111 return nullptr;
1112 DestructRange(start, count);
1113 this->ShiftData(start, count, arrayLen, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
1114 AssignRange(start, arrayLen, array);
1115 return Elements() + start;
1116 }
1117
1118 // A variation on the ReplaceElementsAt method defined above.
1119 template<class Item>
1120 elem_type *ReplaceElementsAt(index_type start, size_type count,
1121 const nsTArray<Item>& array) {
1122 return ReplaceElementsAt(start, count, array.Elements(), array.Length());
1123 }
1124
1125 // A variation on the ReplaceElementsAt method defined above.
1126 template<class Item>
1127 elem_type *ReplaceElementsAt(index_type start, size_type count,
1128 const Item& item) {
1129 return ReplaceElementsAt(start, count, &item, 1);
1130 }
1131
1132 // A variation on the ReplaceElementsAt method defined above.
1133 template<class Item>
1134 elem_type *ReplaceElementAt(index_type index, const Item& item) {
1135 return ReplaceElementsAt(index, 1, &item, 1);
1136 }
1137
1138 // A variation on the ReplaceElementsAt method defined above.
1139 template<class Item>
1140 elem_type *InsertElementsAt(index_type index, const Item* array,
1141 size_type arrayLen) {
1142 return ReplaceElementsAt(index, 0, array, arrayLen);
1143 }
1144
1145 // A variation on the ReplaceElementsAt method defined above.
1146 template<class Item, class Allocator>
1147 elem_type *InsertElementsAt(index_type index, const nsTArray_Impl<Item, Allocator>& array) {
1148 return ReplaceElementsAt(index, 0, array.Elements(), array.Length());
1149 }
1150
1151 // A variation on the ReplaceElementsAt method defined above.
1152 template<class Item>
1153 elem_type *InsertElementAt(index_type index, const Item& item) {
1154 return ReplaceElementsAt(index, 0, &item, 1);
1155 }
1156
1157 // Insert a new element without copy-constructing. This is useful to avoid
1158 // temporaries.
1159 // @return A pointer to the newly inserted element, or null on OOM.
1160 elem_type* InsertElementAt(index_type index) {
1161 if (!Alloc::Successful(this->EnsureCapacity(Length() + 1, sizeof(elem_type))))
1162 return nullptr;
1163 this->ShiftData(index, 0, 1, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
1164 elem_type *elem = Elements() + index;
1165 elem_traits::Construct(elem);
1166 return elem;
1167 }
1168
1169 // This method searches for the smallest index of an element that is strictly
1170 // greater than |item|. If |item| is inserted at this index, the array will
1171 // remain sorted and |item| would come after all elements that are equal to
1172 // it. If |item| is greater than or equal to all elements in the array, the
1173 // array length is returned.
1174 //
1175 // Note that consumers who want to know whether there are existing items equal
1176 // to |item| in the array can just check that the return value here is > 0 and
1177 // indexing into the previous slot gives something equal to |item|.
1178 //
1179 //
1180 // @param item The item to search for.
1181 // @param comp The Comparator used.
1182 // @return The index of greatest element <= to |item|
1183 // @precondition The array is sorted
1184 template<class Item, class Comparator>
1185 index_type
1186 IndexOfFirstElementGt(const Item& item,
1187 const Comparator& comp) const {
1188 // invariant: low <= [idx] <= high
1189 index_type low = 0, high = Length();
1190 while (high > low) {
1191 index_type mid = (high + low) >> 1;
1192 // Comparators are not required to provide a LessThan(Item&, elem_type),
1193 // so we can't do comp.LessThan(item, ElementAt(mid)).
1194 if (comp.LessThan(ElementAt(mid), item) ||
1195 comp.Equals(ElementAt(mid), item)) {
1196 // item >= ElementAt(mid), so our desired index is at least mid+1.
1197 low = mid + 1;
1198 } else {
1199 // item < ElementAt(mid). Our desired index is therefore at most mid.
1200 high = mid;
1201 }
1202 }
1203 MOZ_ASSERT(high == low);
1204 return low;
1205 }
1206
1207 // A variation on the IndexOfFirstElementGt method defined above.
1208 template<class Item>
1209 index_type
1210 IndexOfFirstElementGt(const Item& item) const {
1211 return IndexOfFirstElementGt(item, nsDefaultComparator<elem_type, Item>());
1212 }
1213
1214 // Inserts |item| at such an index to guarantee that if the array
1215 // was previously sorted, it will remain sorted after this
1216 // insertion.
1217 template<class Item, class Comparator>
1218 elem_type *InsertElementSorted(const Item& item, const Comparator& comp) {
1219 index_type index = IndexOfFirstElementGt(item, comp);
1220 return InsertElementAt(index, item);
1221 }
1222
1223 // A variation on the InsertElementSorted method defined above.
1224 template<class Item>
1225 elem_type *InsertElementSorted(const Item& item) {
1226 return InsertElementSorted(item, nsDefaultComparator<elem_type, Item>());
1227 }
1228
1229 // This method appends elements to the end of this array.
1230 // @param array The elements to append to this array.
1231 // @param arrayLen The number of elements to append to this array.
1232 // @return A pointer to the new elements in the array, or null if
1233 // the operation failed due to insufficient memory.
1234 template<class Item>
1235 elem_type *AppendElements(const Item* array, size_type arrayLen) {
1236 if (!Alloc::Successful(this->EnsureCapacity(Length() + arrayLen, sizeof(elem_type))))
1237 return nullptr;
1238 index_type len = Length();
1239 AssignRange(len, arrayLen, array);
1240 this->IncrementLength(arrayLen);
1241 return Elements() + len;
1242 }
1243
1244 // A variation on the AppendElements method defined above.
1245 template<class Item, class Allocator>
1246 elem_type *AppendElements(const nsTArray_Impl<Item, Allocator>& array) {
1247 return AppendElements(array.Elements(), array.Length());
1248 }
1249
1250 // A variation on the AppendElements method defined above.
1251 template<class Item>
1252 elem_type *AppendElement(const Item& item) {
1253 return AppendElements(&item, 1);
1254 }
1255
1256 // Append new elements without copy-constructing. This is useful to avoid
1257 // temporaries.
1258 // @return A pointer to the newly appended elements, or null on OOM.
1259 elem_type *AppendElements(size_type count) {
1260 if (!Alloc::Successful(this->EnsureCapacity(Length() + count, sizeof(elem_type))))
1261 return nullptr;
1262 elem_type *elems = Elements() + Length();
1263 size_type i;
1264 for (i = 0; i < count; ++i) {
1265 elem_traits::Construct(elems + i);
1266 }
1267 this->IncrementLength(count);
1268 return elems;
1269 }
1270
1271 // Append a new element without copy-constructing. This is useful to avoid
1272 // temporaries.
1273 // @return A pointer to the newly appended element, or null on OOM.
1274 elem_type *AppendElement() {
1275 return AppendElements(1);
1276 }
1277
1278 // Move all elements from another array to the end of this array without
1279 // calling copy constructors or destructors.
1280 // @return A pointer to the newly appended elements, or null on OOM.
1281 template<class Item, class Allocator>
1282 elem_type *MoveElementsFrom(nsTArray_Impl<Item, Allocator>& array) {
1283 MOZ_ASSERT(&array != this, "argument must be different array");
1284 index_type len = Length();
1285 index_type otherLen = array.Length();
1286 if (!Alloc::Successful(this->EnsureCapacity(len + otherLen, sizeof(elem_type))))
1287 return nullptr;
1288 copy_type::CopyElements(Elements() + len, array.Elements(), otherLen, sizeof(elem_type));
1289 this->IncrementLength(otherLen);
1290 array.ShiftData(0, otherLen, 0, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
1291 return Elements() + len;
1292 }
1293
1294 // This method removes a range of elements from this array.
1295 // @param start The starting index of the elements to remove.
1296 // @param count The number of elements to remove.
1297 void RemoveElementsAt(index_type start, size_type count) {
1298 MOZ_ASSERT(count == 0 || start < Length(), "Invalid start index");
1299 MOZ_ASSERT(start + count <= Length(), "Invalid length");
1300 // Check that the previous assert didn't overflow
1301 MOZ_ASSERT(start <= start + count, "Start index plus length overflows");
1302 DestructRange(start, count);
1303 this->ShiftData(start, count, 0, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
1304 }
1305
1306 // A variation on the RemoveElementsAt method defined above.
1307 void RemoveElementAt(index_type index) {
1308 RemoveElementsAt(index, 1);
1309 }
1310
1311 // A variation on the RemoveElementsAt method defined above.
1312 void Clear() {
1313 RemoveElementsAt(0, Length());
1314 }
1315
1316 // This helper function combines IndexOf with RemoveElementAt to "search
1317 // and destroy" the first element that is equal to the given element.
1318 // @param item The item to search for.
1319 // @param comp The Comparator used to determine element equality.
1320 // @return true if the element was found
1321 template<class Item, class Comparator>
1322 bool RemoveElement(const Item& item, const Comparator& comp) {
1323 index_type i = IndexOf(item, 0, comp);
1324 if (i == NoIndex)
1325 return false;
1326
1327 RemoveElementAt(i);
1328 return true;
1329 }
1330
1331 // A variation on the RemoveElement method defined above that assumes
1332 // that 'operator==' is defined for elem_type.
1333 template<class Item>
1334 bool RemoveElement(const Item& item) {
1335 return RemoveElement(item, nsDefaultComparator<elem_type, Item>());
1336 }
1337
1338 // This helper function combines IndexOfFirstElementGt with
1339 // RemoveElementAt to "search and destroy" the last element that
1340 // is equal to the given element.
1341 // @param item The item to search for.
1342 // @param comp The Comparator used to determine element equality.
1343 // @return true if the element was found
1344 template<class Item, class Comparator>
1345 bool RemoveElementSorted(const Item& item, const Comparator& comp) {
1346 index_type index = IndexOfFirstElementGt(item, comp);
1347 if (index > 0 && comp.Equals(ElementAt(index - 1), item)) {
1348 RemoveElementAt(index - 1);
1349 return true;
1350 }
1351 return false;
1352 }
1353
1354 // A variation on the RemoveElementSorted method defined above.
1355 template<class Item>
1356 bool RemoveElementSorted(const Item& item) {
1357 return RemoveElementSorted(item, nsDefaultComparator<elem_type, Item>());
1358 }
1359
1360 // This method causes the elements contained in this array and the given
1361 // array to be swapped.
1362 template<class Allocator>
1363 typename Alloc::ResultType
1364 SwapElements(nsTArray_Impl<E, Allocator>& other) {
1365 return Alloc::Result(this->SwapArrayElements(other, sizeof(elem_type),
1366 MOZ_ALIGNOF(elem_type)));
1367 }
1368
1369 //
1370 // Allocation
1371 //
1372
1373 // This method may increase the capacity of this array object by the
1374 // specified amount. This method may be called in advance of several
1375 // AppendElement operations to minimize heap re-allocations. This method
1376 // will not reduce the number of elements in this array.
1377 // @param capacity The desired capacity of this array.
1378 // @return True if the operation succeeded; false if we ran out of memory
1379 typename Alloc::ResultType SetCapacity(size_type capacity) {
1380 return Alloc::Result(this->EnsureCapacity(capacity, sizeof(elem_type)));
1381 }
1382
1383 // This method modifies the length of the array. If the new length is
1384 // larger than the existing length of the array, then new elements will be
1385 // constructed using elem_type's default constructor. Otherwise, this call
1386 // removes elements from the array (see also RemoveElementsAt).
1387 // @param newLen The desired length of this array.
1388 // @return True if the operation succeeded; false otherwise.
1389 // See also TruncateLength if the new length is guaranteed to be
1390 // smaller than the old.
1391 typename Alloc::ResultType SetLength(size_type newLen) {
1392 size_type oldLen = Length();
1393 if (newLen > oldLen) {
1394 return Alloc::ConvertBoolToResultType(InsertElementsAt(oldLen, newLen - oldLen) != nullptr);
1395 }
1396
1397 TruncateLength(newLen);
1398 return Alloc::ConvertBoolToResultType(true);
1399 }
1400
1401 // This method modifies the length of the array, but may only be
1402 // called when the new length is shorter than the old. It can
1403 // therefore be called when elem_type has no default constructor,
1404 // unlike SetLength. It removes elements from the array (see also
1405 // RemoveElementsAt).
1406 // @param newLen The desired length of this array.
1407 void TruncateLength(size_type newLen) {
1408 size_type oldLen = Length();
1409 NS_ABORT_IF_FALSE(newLen <= oldLen,
1410 "caller should use SetLength instead");
1411 RemoveElementsAt(newLen, oldLen - newLen);
1412 }
1413
1414 // This method ensures that the array has length at least the given
1415 // length. If the current length is shorter than the given length,
1416 // then new elements will be constructed using elem_type's default
1417 // constructor.
1418 // @param minLen The desired minimum length of this array.
1419 // @return True if the operation succeeded; false otherwise.
1420 typename Alloc::ResultType EnsureLengthAtLeast(size_type minLen) {
1421 size_type oldLen = Length();
1422 if (minLen > oldLen) {
1423 return Alloc::ConvertBoolToResultType(!!InsertElementsAt(oldLen, minLen - oldLen));
1424 }
1425 return Alloc::ConvertBoolToResultType(true);
1426 }
1427
1428 // This method inserts elements into the array, constructing
1429 // them using elem_type's default constructor.
1430 // @param index the place to insert the new elements. This must be no
1431 // greater than the current length of the array.
1432 // @param count the number of elements to insert
1433 elem_type *InsertElementsAt(index_type index, size_type count) {
1434 if (!base_type::InsertSlotsAt(index, count, sizeof(elem_type), MOZ_ALIGNOF(elem_type))) {
1435 return nullptr;
1436 }
1437
1438 // Initialize the extra array elements
1439 elem_type *iter = Elements() + index, *end = iter + count;
1440 for (; iter != end; ++iter) {
1441 elem_traits::Construct(iter);
1442 }
1443
1444 return Elements() + index;
1445 }
1446
1447 // This method inserts elements into the array, constructing them
1448 // elem_type's copy constructor (or whatever one-arg constructor
1449 // happens to match the Item type).
1450 // @param index the place to insert the new elements. This must be no
1451 // greater than the current length of the array.
1452 // @param count the number of elements to insert.
1453 // @param item the value to use when constructing the new elements.
1454 template<class Item>
1455 elem_type *InsertElementsAt(index_type index, size_type count,
1456 const Item& item) {
1457 if (!base_type::InsertSlotsAt(index, count, sizeof(elem_type), MOZ_ALIGNOF(elem_type))) {
1458 return nullptr;
1459 }
1460
1461 // Initialize the extra array elements
1462 elem_type *iter = Elements() + index, *end = iter + count;
1463 for (; iter != end; ++iter) {
1464 elem_traits::Construct(iter, item);
1465 }
1466
1467 return Elements() + index;
1468 }
1469
1470 // This method may be called to minimize the memory used by this array.
1471 void Compact() {
1472 ShrinkCapacity(sizeof(elem_type), MOZ_ALIGNOF(elem_type));
1473 }
1474
1475 //
1476 // Sorting
1477 //
1478
1479 // This function is meant to be used with the NS_QuickSort function. It
1480 // maps the callback API expected by NS_QuickSort to the Comparator API
1481 // used by nsTArray_Impl. See nsTArray_Impl::Sort.
1482 template<class Comparator>
1483 static int Compare(const void* e1, const void* e2, void *data) {
1484 const Comparator* c = reinterpret_cast<const Comparator*>(data);
1485 const elem_type* a = static_cast<const elem_type*>(e1);
1486 const elem_type* b = static_cast<const elem_type*>(e2);
1487 return c->LessThan(*a, *b) ? -1 : (c->Equals(*a, *b) ? 0 : 1);
1488 }
1489
1490 // This method sorts the elements of the array. It uses the LessThan
1491 // method defined on the given Comparator object to collate elements.
1492 // @param comp The Comparator used to collate elements.
1493 template<class Comparator>
1494 void Sort(const Comparator& comp) {
1495 NS_QuickSort(Elements(), Length(), sizeof(elem_type),
1496 Compare<Comparator>, const_cast<Comparator*>(&comp));
1497 }
1498
1499 // A variation on the Sort method defined above that assumes that
1500 // 'operator<' is defined for elem_type.
1501 void Sort() {
1502 Sort(nsDefaultComparator<elem_type, elem_type>());
1503 }
1504
1505 //
1506 // Binary Heap
1507 //
1508
1509 // Sorts the array into a binary heap.
1510 // @param comp The Comparator used to create the heap
1511 template<class Comparator>
1512 void MakeHeap(const Comparator& comp) {
1513 if (!Length()) {
1514 return;
1515 }
1516 index_type index = (Length() - 1) / 2;
1517 do {
1518 SiftDown(index, comp);
1519 } while (index--);
1520 }
1521
1522 // A variation on the MakeHeap method defined above.
1523 void MakeHeap() {
1524 MakeHeap(nsDefaultComparator<elem_type, elem_type>());
1525 }
1526
1527 // Adds an element to the heap
1528 // @param item The item to add
1529 // @param comp The Comparator used to sift-up the item
1530 template<class Item, class Comparator>
1531 elem_type *PushHeap(const Item& item, const Comparator& comp) {
1532 if (!base_type::InsertSlotsAt(Length(), 1, sizeof(elem_type), MOZ_ALIGNOF(elem_type))) {
1533 return nullptr;
1534 }
1535 // Sift up the new node
1536 elem_type *elem = Elements();
1537 index_type index = Length() - 1;
1538 index_type parent_index = (index - 1) / 2;
1539 while (index && comp.LessThan(elem[parent_index], item)) {
1540 elem[index] = elem[parent_index];
1541 index = parent_index;
1542 parent_index = (index - 1) / 2;
1543 }
1544 elem[index] = item;
1545 return &elem[index];
1546 }
1547
1548 // A variation on the PushHeap method defined above.
1549 template<class Item>
1550 elem_type *PushHeap(const Item& item) {
1551 return PushHeap(item, nsDefaultComparator<elem_type, Item>());
1552 }
1553
1554 // Delete the root of the heap and restore the heap
1555 // @param comp The Comparator used to restore the heap
1556 template<class Comparator>
1557 void PopHeap(const Comparator& comp) {
1558 if (!Length()) {
1559 return;
1560 }
1561 index_type last_index = Length() - 1;
1562 elem_type *elem = Elements();
1563 elem[0] = elem[last_index];
1564 TruncateLength(last_index);
1565 if (Length()) {
1566 SiftDown(0, comp);
1567 }
1568 }
1569
1570 // A variation on the PopHeap method defined above.
1571 void PopHeap() {
1572 PopHeap(nsDefaultComparator<elem_type, elem_type>());
1573 }
1574
1575 protected:
1576 using base_type::Hdr;
1577 using base_type::ShrinkCapacity;
1578
1579 // This method invokes elem_type's destructor on a range of elements.
1580 // @param start The index of the first element to destroy.
1581 // @param count The number of elements to destroy.
1582 void DestructRange(index_type start, size_type count) {
1583 elem_type *iter = Elements() + start, *end = iter + count;
1584 for (; iter != end; ++iter) {
1585 elem_traits::Destruct(iter);
1586 }
1587 }
1588
1589 // This method invokes elem_type's copy-constructor on a range of elements.
1590 // @param start The index of the first element to construct.
1591 // @param count The number of elements to construct.
1592 // @param values The array of elements to copy.
1593 template<class Item>
1594 void AssignRange(index_type start, size_type count,
1595 const Item *values) {
1596 AssignRangeAlgorithm<mozilla::IsPod<Item>::value,
1597 mozilla::IsSame<Item, elem_type>::value>
1598 ::implementation(Elements(), start, count, values);
1599 }
1600
1601 // This method sifts an item down to its proper place in a binary heap
1602 // @param index The index of the node to start sifting down from
1603 // @param comp The Comparator used to sift down
1604 template<class Comparator>
1605 void SiftDown(index_type index, const Comparator& comp) {
1606 elem_type *elem = Elements();
1607 elem_type item = elem[index];
1608 index_type end = Length() - 1;
1609 while ((index * 2) < end) {
1610 const index_type left = (index * 2) + 1;
1611 const index_type right = (index * 2) + 2;
1612 const index_type parent_index = index;
1613 if (comp.LessThan(item, elem[left])) {
1614 if (left < end &&
1615 comp.LessThan(elem[left], elem[right])) {
1616 index = right;
1617 } else {
1618 index = left;
1619 }
1620 } else if (left < end &&
1621 comp.LessThan(item, elem[right])) {
1622 index = right;
1623 } else {
1624 break;
1625 }
1626 elem[parent_index] = elem[index];
1627 }
1628 elem[index] = item;
1629 }
1630 };
1631
1632 template <typename E, typename Alloc>
1633 inline void
1634 ImplCycleCollectionUnlink(nsTArray_Impl<E, Alloc>& aField)
1635 {
1636 aField.Clear();
1637 }
1638
1639 template <typename E, typename Alloc>
1640 inline void
1641 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
1642 nsTArray_Impl<E, Alloc>& aField,
1643 const char* aName,
1644 uint32_t aFlags = 0)
1645 {
1646 aFlags |= CycleCollectionEdgeNameArrayFlag;
1647 uint32_t length = aField.Length();
1648 for (uint32_t i = 0; i < length; ++i) {
1649 ImplCycleCollectionTraverse(aCallback, aField[i], aName, aFlags);
1650 }
1651 }
1652
1653 //
1654 // nsTArray is an infallible vector class. See the comment at the top of this
1655 // file for more details.
1656 //
1657 template <class E>
1658 class nsTArray : public nsTArray_Impl<E, nsTArrayInfallibleAllocator>
1659 {
1660 public:
1661 typedef nsTArray_Impl<E, nsTArrayInfallibleAllocator> base_type;
1662 typedef nsTArray<E> self_type;
1663 typedef typename base_type::size_type size_type;
1664
1665 nsTArray() {}
1666 explicit nsTArray(size_type capacity) : base_type(capacity) {}
1667 explicit nsTArray(const nsTArray& other) : base_type(other) {}
1668
1669 template<class Allocator>
1670 explicit nsTArray(const nsTArray_Impl<E, Allocator>& other) : base_type(other) {}
1671 };
1672
1673 //
1674 // FallibleTArray is a fallible vector class.
1675 //
1676 template <class E>
1677 class FallibleTArray : public nsTArray_Impl<E, nsTArrayFallibleAllocator>
1678 {
1679 public:
1680 typedef nsTArray_Impl<E, nsTArrayFallibleAllocator> base_type;
1681 typedef FallibleTArray<E> self_type;
1682 typedef typename base_type::size_type size_type;
1683
1684 FallibleTArray() {}
1685 explicit FallibleTArray(size_type capacity) : base_type(capacity) {}
1686 explicit FallibleTArray(const FallibleTArray<E>& other) : base_type(other) {}
1687
1688 template<class Allocator>
1689 explicit FallibleTArray(const nsTArray_Impl<E, Allocator>& other) : base_type(other) {}
1690 };
1691
1692 //
1693 // nsAutoArrayBase is a base class for AutoFallibleTArray and nsAutoTArray.
1694 // You shouldn't use this class directly.
1695 //
1696 template <class TArrayBase, uint32_t N>
1697 class nsAutoArrayBase : public TArrayBase
1698 {
1699 public:
1700 typedef nsAutoArrayBase<TArrayBase, N> self_type;
1701 typedef TArrayBase base_type;
1702 typedef typename base_type::Header Header;
1703 typedef typename base_type::elem_type elem_type;
1704
1705 template<typename Allocator>
1706 self_type& operator=(const nsTArray_Impl<elem_type, Allocator>& other) {
1707 base_type::operator=(other);
1708 return *this;
1709 }
1710
1711 protected:
1712 nsAutoArrayBase() {
1713 Init();
1714 }
1715
1716 // We need this constructor because nsAutoTArray and friends all have
1717 // implicit copy-constructors. If we don't have this method, those
1718 // copy-constructors will call nsAutoArrayBase's implicit copy-constructor,
1719 // which won't call Init() and set up the auto buffer!
1720 nsAutoArrayBase(const self_type &aOther) {
1721 Init();
1722 this->AppendElements(aOther);
1723 }
1724
1725 private:
1726 // nsTArray_base casts itself as an nsAutoArrayBase in order to get a pointer
1727 // to mAutoBuf.
1728 template<class Allocator, class Copier>
1729 friend class nsTArray_base;
1730
1731 void Init() {
1732 static_assert(MOZ_ALIGNOF(elem_type) <= 8,
1733 "can't handle alignments greater than 8, "
1734 "see nsTArray_base::UsesAutoArrayBuffer()");
1735 // Temporary work around for VS2012 RC compiler crash
1736 Header** phdr = base_type::PtrToHdr();
1737 *phdr = reinterpret_cast<Header*>(&mAutoBuf);
1738 (*phdr)->mLength = 0;
1739 (*phdr)->mCapacity = N;
1740 (*phdr)->mIsAutoArray = 1;
1741
1742 MOZ_ASSERT(base_type::GetAutoArrayBuffer(MOZ_ALIGNOF(elem_type)) ==
1743 reinterpret_cast<Header*>(&mAutoBuf),
1744 "GetAutoArrayBuffer needs to be fixed");
1745 }
1746
1747 // Declare mAutoBuf aligned to the maximum of the header's alignment and
1748 // elem_type's alignment. We need to use a union rather than
1749 // MOZ_ALIGNED_DECL because GCC is picky about what goes into
1750 // __attribute__((aligned(foo))).
1751 union {
1752 char mAutoBuf[sizeof(nsTArrayHeader) + N * sizeof(elem_type)];
1753 // Do the max operation inline to ensure that it is a compile-time constant.
1754 mozilla::AlignedElem<(MOZ_ALIGNOF(Header) > MOZ_ALIGNOF(elem_type))
1755 ? MOZ_ALIGNOF(Header) : MOZ_ALIGNOF(elem_type)> mAlign;
1756 };
1757 };
1758
1759 //
1760 // nsAutoTArray<E, N> is an infallible vector class with N elements of inline
1761 // storage. If you try to store more than N elements inside an
1762 // nsAutoTArray<E, N>, we'll call malloc() and store them all on the heap.
1763 //
1764 // Note that you can cast an nsAutoTArray<E, N> to
1765 // |const AutoFallibleTArray<E, N>&|.
1766 //
1767 template<class E, uint32_t N>
1768 class nsAutoTArray : public nsAutoArrayBase<nsTArray<E>, N>
1769 {
1770 typedef nsAutoTArray<E, N> self_type;
1771 typedef nsAutoArrayBase<nsTArray<E>, N> Base;
1772
1773 public:
1774 nsAutoTArray() {}
1775
1776 template<typename Allocator>
1777 explicit nsAutoTArray(const nsTArray_Impl<E, Allocator>& other) {
1778 Base::AppendElements(other);
1779 }
1780
1781 operator const AutoFallibleTArray<E, N>&() const {
1782 return *reinterpret_cast<const AutoFallibleTArray<E, N>*>(this);
1783 }
1784 };
1785
1786 //
1787 // AutoFallibleTArray<E, N> is a fallible vector class with N elements of
1788 // inline storage.
1789 //
1790 template<class E, uint32_t N>
1791 class AutoFallibleTArray : public nsAutoArrayBase<FallibleTArray<E>, N>
1792 {
1793 typedef AutoFallibleTArray<E, N> self_type;
1794 typedef nsAutoArrayBase<FallibleTArray<E>, N> Base;
1795
1796 public:
1797 AutoFallibleTArray() {}
1798
1799 template<typename Allocator>
1800 explicit AutoFallibleTArray(const nsTArray_Impl<E, Allocator>& other) {
1801 Base::AppendElements(other);
1802 }
1803
1804 operator const nsAutoTArray<E, N>&() const {
1805 return *reinterpret_cast<const nsAutoTArray<E, N>*>(this);
1806 }
1807 };
1808
1809 // Assert that nsAutoTArray doesn't have any extra padding inside.
1810 //
1811 // It's important that the data stored in this auto array takes up a multiple of
1812 // 8 bytes; e.g. nsAutoTArray<uint32_t, 1> wouldn't work. Since nsAutoTArray
1813 // contains a pointer, its size must be a multiple of alignof(void*). (This is
1814 // because any type may be placed into an array, and there's no padding between
1815 // elements of an array.) The compiler pads the end of the structure to
1816 // enforce this rule.
1817 //
1818 // If we used nsAutoTArray<uint32_t, 1> below, this assertion would fail on a
1819 // 64-bit system, where the compiler inserts 4 bytes of padding at the end of
1820 // the auto array to make its size a multiple of alignof(void*) == 8 bytes.
1821
1822 static_assert(sizeof(nsAutoTArray<uint32_t, 2>) ==
1823 sizeof(void*) + sizeof(nsTArrayHeader) + sizeof(uint32_t) * 2,
1824 "nsAutoTArray shouldn't contain any extra padding, "
1825 "see the comment");
1826
1827 // Definitions of nsTArray_Impl methods
1828 #include "nsTArray-inl.h"
1829
1830 #endif // nsTArray_h__

mercurial