Bug 819791 - Part 3: Make typeof nsTArray == typeof InfallibleTArray. r=bz
authorJustin Lebar <justin.lebar@gmail.com>
Tue, 18 Dec 2012 20:16:06 -0500
changeset 116479 1a0cd3aa18645212d34e73cea7a80f65c9fc97d7
parent 116478 28b5c8d25fb9cd733b1a3fa9d30c34a0698d3b78
child 116480 3877a7a5fdf6040adf950d3a367971862dda252c
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersbz
bugs819791
milestone20.0a1
Bug 819791 - Part 3: Make typeof nsTArray == typeof InfallibleTArray. r=bz Also make typeof nsAutoTArray == typeof AutoInfallibleTArray and switch files to using nsTArrayForwardDeclare.h.
content/base/src/nsAttrValue.h
docshell/shistory/public/nsISHistoryInternal.idl
dom/bindings/Nullable.h
layout/generic/nsIAnonymousContentCreator.h
layout/style/nsCSSStyleSheet.h
modules/libpref/public/nsIPrefService.idl
xpcom/glue/Makefile.in
xpcom/glue/nsTArray-inl.h
xpcom/glue/nsTArray.h
xpcom/glue/nsTArrayForwardDeclare.h
--- a/content/base/src/nsAttrValue.h
+++ b/content/base/src/nsAttrValue.h
@@ -14,21 +14,21 @@
 #include "nscore.h"
 #include "nsStringGlue.h"
 #include "nsStringBuffer.h"
 #include "nsColor.h"
 #include "nsCaseTreatment.h"
 #include "nsMargin.h"
 #include "nsCOMPtr.h"
 #include "SVGAttrValueWrapper.h"
+#include "nsTArrayForwardDeclare.h"
 
 class nsAString;
 class nsIAtom;
 class nsIDocument;
-template<class E, class A> class nsTArray;
 class nsStyledElementNotElementCSSInlineStyle;
 struct MiscContainer;
 
 namespace mozilla {
 namespace css {
 class StyleRule;
 struct URLValue;
 struct ImageValue;
--- a/docshell/shistory/public/nsISHistoryInternal.idl
+++ b/docshell/shistory/public/nsISHistoryInternal.idl
@@ -13,21 +13,20 @@ interface nsIDocShell;
 
 %{C++
 #define NS_SHISTORY_INTERNAL_CID \
 { 0x9c47c121, 0x1c6e, 0x4d8f, \
   { 0xb9, 0x04, 0x3a, 0xc9, 0x68, 0x11, 0x6e, 0x88 } }
 
 #define NS_SHISTORY_INTERNAL_CONTRACTID "@mozilla.org/browser/shistory-internal;1"
 
-struct nsTArrayInfallibleAllocator;
-template<class E, class Alloc> class nsTArray;
+#include "nsTArrayForwardDeclare.h"
 %}
 
-[ref] native nsDocshellIDArray(nsTArray<uint64_t, nsTArrayInfallibleAllocator>);
+[ref] native nsDocshellIDArray(nsTArray<uint64_t>);
 
 [scriptable, uuid(f9348014-0239-11e2-b029-3d38e719eb2d)]
 interface nsISHistoryInternal: nsISupports
 {
   /**
    * Add a new Entry to the History List
    * @param aEntry - The entry to add
    * @param aPersist - If true this specifies that the entry should persist
--- a/dom/bindings/Nullable.h
+++ b/dom/bindings/Nullable.h
@@ -3,20 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_Nullable_h
 #define mozilla_dom_Nullable_h
 
 #include "mozilla/Assertions.h"
-
-template<typename E, class Allocator> class nsTArray;
-template<typename E> class InfallibleTArray;
-template<typename E> class FallibleTArray;
+#include "nsTArrayForwardDeclare.h"
 
 namespace mozilla {
 namespace dom {
 
 // Support for nullable types
 template <typename T>
 struct Nullable
 {
@@ -64,29 +61,22 @@ public:
   }
 
   bool IsNull() const {
     return mIsNull;
   }
 
   // Make it possible to use a const Nullable of an array type with other
   // array types.
-  template<typename U, typename Allocator>
-  operator const Nullable< nsTArray<U, Allocator> >&() const {
-    // Make sure that T is ok to reinterpret to nsTArray<U, Allocator>
-    const nsTArray<U, Allocator>& arr = mValue;
+  template<typename U>
+  operator const Nullable< nsTArray<U> >&() const {
+    // Make sure that T is ok to reinterpret to nsTArray<U>
+    const nsTArray<U>& arr = mValue;
     (void)arr;
-    return *reinterpret_cast<const Nullable< nsTArray<U, Allocator> >*>(this);
-  }
-  template<typename U>
-  operator const Nullable< InfallibleTArray<U> >&() const {
-    // Make sure that T is ok to reinterpret to InfallibleTArray<U>
-    const InfallibleTArray<U>& arr = mValue;
-    (void)arr;
-    return *reinterpret_cast<const Nullable< InfallibleTArray<U> >*>(this);
+    return *reinterpret_cast<const Nullable< nsTArray<U> >*>(this);
   }
   template<typename U>
   operator const Nullable< FallibleTArray<U> >&() const {
     // Make sure that T is ok to reinterpret to FallibleTArray<U>
     const FallibleTArray<U>& arr = mValue;
     (void)arr;
     return *reinterpret_cast<const Nullable< FallibleTArray<U> >*>(this);
   }
--- a/layout/generic/nsIAnonymousContentCreator.h
+++ b/layout/generic/nsIAnonymousContentCreator.h
@@ -9,20 +9,20 @@
  */
 
 #ifndef nsIAnonymousContentCreator_h___
 #define nsIAnonymousContentCreator_h___
 
 #include "nsQueryFrame.h"
 #include "nsIContent.h"
 #include "nsStyleContext.h"
+#include "nsTArrayForwardDeclare.h"
 
 class nsBaseContentList;
 class nsIFrame;
-template <class T, class A> class nsTArray;
 
 /**
  * Any source for anonymous content can implement this interface to provide it.
  * HTML frames like nsFileControlFrame currently use this.
  *
  * @see nsCSSFrameConstructor
  */
 class nsIAnonymousContentCreator
--- a/layout/style/nsCSSStyleSheet.h
+++ b/layout/style/nsCSSStyleSheet.h
@@ -26,17 +26,16 @@
 class nsXMLNameSpaceMap;
 class nsCSSRuleProcessor;
 class nsIPrincipal;
 class nsIURI;
 class nsMediaList;
 class nsMediaQueryResultCacheKey;
 class nsCSSStyleSheet;
 class nsPresContext;
-template<class E, class A> class nsTArray;
 
 namespace mozilla {
 namespace css {
 class Rule;
 class GroupRule;
 class ImportRule;
 }
 }
--- a/modules/libpref/public/nsIPrefService.idl
+++ b/modules/libpref/public/nsIPrefService.idl
@@ -3,21 +3,20 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 #include "nsIPrefBranch.idl"
 
 %{C++
 struct PrefTuple;
-template<class E, class A> class nsTArray;
-struct nsTArrayInfallibleAllocator;
+#include "nsTArrayForwardDeclare.h"
 %}
 
-[ptr] native nsPreferencesArrayPtr(nsTArray<PrefTuple, nsTArrayInfallibleAllocator>);
+[ptr] native nsPreferencesArrayPtr(nsTArray<PrefTuple>);
 [ptr] native nsPreferencePtr(PrefTuple);
 [ptr] native nsPreferencePtrConst(const PrefTuple);
 
 interface nsIFile;
 
 /**
  * The nsIPrefService interface is the main entry point into the back end
  * preferences management library. The preference service is directly
--- a/xpcom/glue/Makefile.in
+++ b/xpcom/glue/Makefile.in
@@ -64,16 +64,17 @@ SDK_HEADERS = \
 		nsMemory.h \
 		nsQuickSort.h \
 		nsRefPtrHashtable.h \
 		nsServiceManagerUtils.h \
 		nsStringAPI.h \
 		nsStringGlue.h \
 		nsTArray.h \
 		nsTArray-inl.h \
+		nsTArrayForwardDeclare.h \
 		nsTHashtable.h \
 		nsTObserverArray.h \
 		nsTWeakRef.h \
 		nsTextFormatter.h \
 		nsTraceRefcnt.h \
 		nsVersionComparator.h \
 		nsVoidArray.h \
 		nsWeakReference.h \
--- a/xpcom/glue/nsTArray-inl.h
+++ b/xpcom/glue/nsTArray-inl.h
@@ -365,17 +365,17 @@ nsTArray_base<Alloc>::SwapArrayElements(
     largerElements = Hdr() + 1;
   }
 
   // Allocate temporary storage for the smaller of the two arrays.  We want to
   // allocate this space on the stack, if it's not too large.  Sounds like a
   // job for AutoTArray!  (One of the two arrays we're swapping is using an
   // auto buffer, so we're likely not allocating a lot of space here.  But one
   // could, in theory, allocate a huge AutoTArray on the heap.)
-  nsAutoTArray<uint8_t, 64, Alloc> temp;
+  nsAutoArrayBase<nsTArray_Impl<uint8_t, Alloc>, 64> temp;
   if (!temp.SetCapacity(smallerLength * elemSize)) {
     return false;
   }
 
   memcpy(temp.Elements(), smallerElements, smallerLength * elemSize);
   memcpy(smallerElements, largerElements, largerLength * elemSize);
   memcpy(largerElements, temp.Elements(), smallerLength * elemSize);
 
--- a/xpcom/glue/nsTArray.h
+++ b/xpcom/glue/nsTArray.h
@@ -2,41 +2,85 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsTArray_h__
 #define nsTArray_h__
 
+#include "nsTArrayForwardDeclare.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Util.h"
 
 #include <string.h>
 
 #include "nsCycleCollectionNoteChild.h"
 #include "nsAlgorithm.h"
 #include "nscore.h"
 #include "nsQuickSort.h"
 #include "nsDebug.h"
 #include "nsTraceRefcnt.h"
 #include NEW_H
 
 //
-// NB: nsTArray assumes that your "T" can be memmove()d.  This is in
-// contrast to STL containers, which follow C++
-// construction/destruction rules.
+// nsTArray is a resizable array class, like std::vector.
+//
+// Unlike std::vector, which follows C++'s construction/destruction rules,
+// nsTArray assumes that your "T" can be memmoved()'ed safely.
+//
+// The public classes defined in this header are
+//
+//   nsTArray<T>,
+//   FallibleTArray<T>,
+//   nsAutoTArray<T, N>, and
+//   AutoFallibleTArray<T, N>.
+//
+// nsTArray and nsAutoTArray are infallible; if one tries to make an allocation
+// which fails, it crashes the program.  In contrast, FallibleTArray and
+// AutoFallibleTArray are fallible; if you use one of these classes, you must
+// check the return values of methods such as Append() which may allocate.  If
+// in doubt, choose an infallible type.
+//
+// InfallibleTArray and AutoInfallibleTArray are aliases for nsTArray and
+// nsAutoTArray.
 //
-// Don't use nsTArray if your "T" can't be memmove()d correctly.
+// If you just want to declare the nsTArray types (e.g., if you're in a header
+// file and don't need the full nsTArray definitions) consider including
+// nsTArrayForwardDeclare.h instead of nsTArray.h.
+//
+// The template parameter (i.e., T in nsTArray<T>) specifies the type of the
+// elements and has the following requirements:
+//
+//   T MUST be safely memmove()'able.
+//   T MUST define a copy-constructor.
+//   T MAY define operator< for sorting.
+//   T MAY define operator== for searching.
+//
+// For methods taking a Comparator instance, the Comparator must be a class
+// defining the following methods:
+//
+//   class Comparator {
+//     public:
+//       /** @return True if the elements are equals; false otherwise. */
+//       bool Equals(const elem_type& a, const Item& b) const;
+//
+//       /** @return True if (a < b); false otherwise. */
+//       bool LessThan(const elem_type& a, const Item& b) const;
+//   };
+//
+// The Equals method is used for searching, and the LessThan method is used for
+// searching and sorting.  The |Item| type above can be arbitrary, but must
+// match the Item type passed to the sort or search function.
 //
 
+
 //
-// nsTArray*Allocators must all use the same |free()|, to allow
-// swapping between fallible and infallible variants.  (NS_Free() and
-// moz_free() end up calling the same underlying free()).
+// nsTArray*Allocators must all use the same |free()|, to allow swap()'ing
+// between fallible and infallible variants.
 //
 
 #if defined(MOZALLOC_HAVE_XMALLOC)
 #include "mozilla/mozalloc_abort.h"
 
 struct nsTArrayFallibleAllocator
 {
   static void* Malloc(size_t size) {
@@ -401,62 +445,37 @@ public:
     return a < b;
   }
 };
 
 template <class E> class InfallibleTArray;
 template <class E> class FallibleTArray;
 
 //
-// The templatized array class that dynamically resizes its storage as
-// elements are added.  This class is designed to behave a bit like
-// std::vector, though note that unlike std::vector, nsTArray doesn't
-// follow C++ construction/destruction rules.
-//
-// The template parameter specifies the type of the elements (elem_type), and
-// has the following requirements:
+// nsTArray_Impl contains most of the guts supporting nsTArray, FallibleTArray,
+// nsAutoTArray, and AutoFallibleTArray.
 //
-//   elem_type MUST define a copy-constructor.
-//   elem_type MAY define operator< for sorting.
-//   elem_type MAY define operator== for searching.
-//
-// For methods taking a Comparator instance, the Comparator must be a class
-// defining the following methods:
-//
-//   class Comparator {
-//     public:
-//       /** @return True if the elements are equals; false otherwise. */
-//       bool Equals(const elem_type& a, const Item& b) const;
+// The only situation in which you might need to use nsTArray_Impl in your code
+// is if you're writing code which mutates a TArray which may or may not be
+// infallible.
 //
-//       /** @return True if (a < b); false otherwise. */
-//       bool LessThan(const elem_type& a, const Item& b) const;
-//   };
-//
-// The Equals method is used for searching, and the LessThan method is used
-// for sorting.  The |Item| type above can be arbitrary, but must match the
-// Item type passed to the sort or search function.
+// Code which merely reads from a TArray which may or may not be infallible can
+// simply cast the TArray to |const nsTArray&|; both fallible and infallible
+// TArrays can be cast to |const nsTArray&|.
 //
-// The Alloc template parameter can be used to choose between
-// "fallible" and "infallible" nsTArray (if available), defaulting to
-// fallible.  If the *fallible* allocator is used, the return value of
-// methods that might allocate needs to be checked; Append() is
-// one such method.  These return values don't need to be checked if
-// the *in*fallible allocator is chosen.  When in doubt, choose the
-// infallible allocator.
-//
-template<class E, class Alloc=nsTArrayInfallibleAllocator>
-class nsTArray : public nsTArray_base<Alloc>,
-                 public nsTArray_SafeElementAtHelper<E, nsTArray<E, Alloc> >
+template<class E, class Alloc>
+class nsTArray_Impl : public nsTArray_base<Alloc>,
+                      public nsTArray_SafeElementAtHelper<E, nsTArray_Impl<E, Alloc> >
 {
 public:
   typedef nsTArray_base<Alloc>           base_type;
   typedef typename base_type::size_type  size_type;
   typedef typename base_type::index_type index_type;
   typedef E                              elem_type;
-  typedef nsTArray<E, Alloc>             self_type;
+  typedef nsTArray_Impl<E, Alloc>        self_type;
   typedef nsTArrayElementTraits<E>       elem_traits;
   typedef nsTArray_SafeElementAtHelper<E, self_type> safeelementat_helper_type;
 
   using safeelementat_helper_type::SafeElementAt;
   using base_type::EmptyHdr;
 
   // A special value that is used to indicate an invalid or unknown index
   // into the array.
@@ -465,66 +484,74 @@ public:
   };
 
   using base_type::Length;
 
   //
   // Finalization method
   //
 
-  ~nsTArray() { Clear(); }
+  ~nsTArray_Impl() { Clear(); }
 
   //
   // Initialization methods
   //
 
-  nsTArray() {}
+  nsTArray_Impl() {}
 
   // Initialize this array and pre-allocate some number of elements.
-  explicit nsTArray(size_type capacity) {
+  explicit nsTArray_Impl(size_type capacity) {
     SetCapacity(capacity);
   }
 
   // The array's copy-constructor performs a 'deep' copy of the given array.
   // @param other  The array object to copy.
-  explicit nsTArray(const self_type& other) {
-    AppendElements(other);
-  }
-
-  template<typename Allocator>
-  explicit nsTArray(const nsTArray<E, Allocator>& other) {
+  //
+  // It's very important that we declare this method as taking |const
+  // self_type&| as opposed to taking |const nsTArray_Impl<E, OtherAlloc>| for
+  // an arbitrary OtherAlloc.
+  //
+  // If we don't declare a constructor taking |const self_type&|, C++ generates
+  // a copy-constructor for this class which merely copies the object's
+  // members, which is obviously wrong.
+  //
+  // You can pass an nsTArray_Impl<E, OtherAlloc> to this method because
+  // nsTArray_Impl<E, X> can be cast to const nsTArray_Impl<E, Y>&.  So the
+  // effect on the API is the same as if we'd declared this method as taking
+  // |const nsTArray_Impl<E, OtherAlloc>&|.
+  explicit nsTArray_Impl(const self_type& other) {
     AppendElements(other);
   }
 
   // Allow converting to a const array with a different kind of allocator,
   // Since the allocator doesn't matter for const arrays
   template<typename Allocator>
-  operator const nsTArray<E, Allocator>&() const {
-    return *reinterpret_cast<const nsTArray<E, Allocator>*>(this);
+  operator const nsTArray_Impl<E, Allocator>&() const {
+    return *reinterpret_cast<const nsTArray_Impl<E, Allocator>*>(this);
   }
   // And we have to do this for our subclasses too
-  operator const InfallibleTArray<E>&() const {
+  operator const nsTArray<E>&() const {
     return *reinterpret_cast<const InfallibleTArray<E>*>(this);
   }
   operator const FallibleTArray<E>&() const {
     return *reinterpret_cast<const FallibleTArray<E>*>(this);
   }
 
   // The array's assignment operator performs a 'deep' copy of the given
   // array.  It is optimized to reuse existing storage if possible.
   // @param other  The array object to copy.
-  nsTArray& operator=(const self_type& other) {
+  self_type& operator=(const self_type& other) {
     ReplaceElementsAt(0, Length(), other.Elements(), other.Length());
     return *this;
   }
 
   // Return true if this array has the same length and the same
   // elements as |other|.
   template<typename Allocator>
-  bool operator==(const nsTArray<E, Allocator>& other) const {
+  bool operator==(const nsTArray_Impl<E, Allocator>& other) const {
     size_type len = Length();
     if (len != other.Length())
       return false;
 
     // XXX std::equal would be as fast or faster here
     for (index_type i = 0; i < len; ++i)
       if (!(operator[](i) == other[i]))
         return false;
@@ -534,30 +561,30 @@ public:
 
   // Return true if this array does not have the same length and the same
   // elements as |other|.
   bool operator!=(const self_type& other) const {
     return !operator==(other);
   }
 
   template<typename Allocator>
-  nsTArray& operator=(const nsTArray<E, Allocator>& other) {
+  self_type& operator=(const nsTArray_Impl<E, Allocator>& other) {
     ReplaceElementsAt(0, Length(), other.Elements(), other.Length());
     return *this;
   }
 
-  // @return The amount of memory used by this nsTArray, excluding
+  // @return The amount of memory used by this nsTArray_Impl, excluding
   // sizeof(*this).
   size_t SizeOfExcludingThis(nsMallocSizeOfFun mallocSizeOf) const {
     if (this->UsesAutoArrayBuffer() || Hdr() == EmptyHdr())
       return 0;
     return mallocSizeOf(this->Hdr());
   }
 
-  // @return The amount of memory used by this nsTArray, including
+  // @return The amount of memory used by this nsTArray_Impl, including
   // sizeof(*this).
   size_t SizeOfIncludingThis(nsMallocSizeOfFun mallocSizeOf) const {
     return mallocSizeOf(this) + SizeOfExcludingThis(mallocSizeOf);
   }
 
   //
   // Accessor methods
   //
@@ -805,18 +832,18 @@ public:
   // A variation on the ReplaceElementsAt method defined above.
   template<class Item>
   elem_type *InsertElementsAt(index_type index, const Item* array,
                               size_type arrayLen) {
     return ReplaceElementsAt(index, 0, array, arrayLen);
   }
 
   // A variation on the ReplaceElementsAt method defined above.
-  template<class Item>
-  elem_type *InsertElementsAt(index_type index, const nsTArray<Item>& array) {
+  template<class Item, class Allocator>
+  elem_type *InsertElementsAt(index_type index, const nsTArray_Impl<Item, Allocator>& array) {
     return ReplaceElementsAt(index, 0, array.Elements(), array.Length());
   }
 
   // A variation on the ReplaceElementsAt method defined above.
   template<class Item>
   elem_type *InsertElementAt(index_type index, const Item& item) {
     return ReplaceElementsAt(index, 0, &item, 1);
   }
@@ -926,17 +953,17 @@ public:
     index_type len = Length();
     AssignRange(len, arrayLen, array);
     this->IncrementLength(arrayLen);
     return Elements() + len;
   }
 
   // A variation on the AppendElements method defined above.
   template<class Item, class Allocator>
-  elem_type *AppendElements(const nsTArray<Item, Allocator>& array) {
+  elem_type *AppendElements(const nsTArray_Impl<Item, Allocator>& array) {
     return AppendElements(array.Elements(), array.Length());
   }
 
   // A variation on the AppendElements method defined above.
   template<class Item>
   elem_type *AppendElement(const Item& item) {
     return AppendElements(&item, 1);
   }
@@ -962,17 +989,17 @@ public:
   elem_type *AppendElement() {
     return AppendElements(1);
   }
 
   // Move all elements from another array to the end of this array without 
   // calling copy constructors or destructors.
   // @return A pointer to the newly appended elements, or null on OOM.
   template<class Item, class Allocator>
-  elem_type *MoveElementsFrom(nsTArray<Item, Allocator>& array) {
+  elem_type *MoveElementsFrom(nsTArray_Impl<Item, Allocator>& array) {
     MOZ_ASSERT(&array != this, "argument must be different array");
     index_type len = Length();
     index_type otherLen = array.Length();
     if (!this->EnsureCapacity(len + otherLen, sizeof(elem_type)))
       return nullptr;
     memcpy(Elements() + len, array.Elements(), otherLen * sizeof(elem_type));
     this->IncrementLength(otherLen);      
     array.ShiftData(0, otherLen, 0, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
@@ -1042,17 +1069,17 @@ public:
   template<class Item>
   bool RemoveElementSorted(const Item& item) {
     return RemoveElementSorted(item, nsDefaultComparator<elem_type, Item>());
   }
 
   // This method causes the elements contained in this array and the given
   // array to be swapped.
   template<class Allocator>
-  bool SwapElements(nsTArray<E, Allocator>& other) {
+  bool SwapElements(nsTArray_Impl<E, Allocator>& other) {
     return this->SwapArrayElements(other, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
   }
 
   //
   // Allocation
   //
 
   // This method may increase the capacity of this array object by the
@@ -1158,17 +1185,17 @@ public:
   }
 
   //
   // Sorting
   //
  
   // This function is meant to be used with the NS_QuickSort function.  It
   // maps the callback API expected by NS_QuickSort to the Comparator API
-  // used by nsTArray.  See nsTArray::Sort.
+  // used by nsTArray_Impl.  See nsTArray_Impl::Sort.
   template<class Comparator>
   static int Compare(const void* e1, const void* e2, void *data) {
     const Comparator* c = reinterpret_cast<const Comparator*>(data);
     const elem_type* a = static_cast<const elem_type*>(e1);
     const elem_type* b = static_cast<const elem_type*>(e2);
     return c->LessThan(*a, *b) ? -1 : (c->Equals(*a, *b) ? 0 : 1);
   }
 
@@ -1312,115 +1339,93 @@ protected:
       elem[parent_index] = elem[index];
     }
     elem[index] = item;
   }
 };
 
 template <typename E, typename Alloc>
 inline void
-ImplCycleCollectionUnlink(nsTArray<E, Alloc>& aField)
+ImplCycleCollectionUnlink(nsTArray_Impl<E, Alloc>& aField)
 {
   aField.Clear();
 }
 
 template <typename E, typename Alloc>
 inline void
 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
-                            nsTArray<E, Alloc>& aField,
+                            nsTArray_Impl<E, Alloc>& aField,
                             const char* aName,
                             uint32_t aFlags = 0)
 {
   aFlags |= CycleCollectionEdgeNameArrayFlag;
   size_t length = aField.Length();
   for (size_t i = 0; i < length; ++i) {
     ImplCycleCollectionTraverse(aCallback, aField[i], aName, aFlags);
   }
 }
 
 //
-// Convenience subtypes of nsTArray.
+// nsTArray is an infallible vector class.  See the comment at the top of this
+// file for more details.
 //
 template <class E>
-class FallibleTArray : public nsTArray<E, nsTArrayFallibleAllocator>
+class nsTArray : public nsTArray_Impl<E, nsTArrayInfallibleAllocator>
 {
 public:
-  typedef nsTArray<E, nsTArrayFallibleAllocator>   base_type;
-  typedef typename base_type::size_type            size_type;
+  typedef nsTArray_Impl<E, nsTArrayInfallibleAllocator> base_type;
+  typedef nsTArray<E>                                   self_type;
+  typedef typename base_type::size_type                 size_type;
+
+  nsTArray() {}
+  explicit nsTArray(size_type capacity) : base_type(capacity) {}
+  nsTArray(const nsTArray& other) : base_type(other) {}
+
+  template<class Allocator>
+  nsTArray(const nsTArray_Impl<E, Allocator>& other) : base_type(other) {}
+};
+
+//
+// FallibleTArray is a fallible vector class.
+//
+template <class E>
+class FallibleTArray : public nsTArray_Impl<E, nsTArrayFallibleAllocator>
+{
+public:
+  typedef nsTArray_Impl<E, nsTArrayFallibleAllocator>   base_type;
+  typedef FallibleTArray<E>                             self_type;
+  typedef typename base_type::size_type                 size_type;
 
   FallibleTArray() {}
   explicit FallibleTArray(size_type capacity) : base_type(capacity) {}
-  FallibleTArray(const FallibleTArray& other) : base_type(other) {}
+  FallibleTArray(const FallibleTArray<E>& other) : base_type(other) {}
+
+  template<class Allocator>
+  FallibleTArray(const nsTArray_Impl<E, Allocator>& other) : base_type(other) {}
 };
 
-template <typename E>
-inline void
-ImplCycleCollectionUnlink(FallibleTArray<E>& aField)
-{
-  aField.Clear();
-}
-
-template <typename E>
-inline void
-ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
-                            FallibleTArray<E>& aField,
-                            const char* aName,
-                            uint32_t aFlags = 0)
-{
-  aFlags |= CycleCollectionEdgeNameArrayFlag;
-  size_t length = aField.Length();
-  for (size_t i = 0; i < length; ++i) {
-    ImplCycleCollectionTraverse(aCallback, aField[i], aName, aFlags);
-  }
-}
-
-
-#ifdef MOZALLOC_HAVE_XMALLOC
-template <class E>
-class InfallibleTArray : public nsTArray<E, nsTArrayInfallibleAllocator>
-{
-public:
-  typedef nsTArray<E, nsTArrayInfallibleAllocator> base_type;
-  typedef typename base_type::size_type            size_type;
- 
-  InfallibleTArray() {}
-  explicit InfallibleTArray(size_type capacity) : base_type(capacity) {}
-  InfallibleTArray(const InfallibleTArray& other) : base_type(other) {}
-};
-
-template <typename E>
-inline void ImplCycleCollectionUnlink(InfallibleTArray<E>& aField)
-{
-  aField.Clear();
-}
-
-template <typename E>
-inline void
-ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
-                            InfallibleTArray<E>& aField,
-                            const char* aName,
-                            uint32_t aFlags = 0)
-{
-  aFlags |= CycleCollectionEdgeNameArrayFlag;
-  size_t length = aField.Length();
-  for (size_t i = 0; i < length; ++i) {
-    ImplCycleCollectionTraverse(aCallback, aField[i], aName, aFlags);
-  }
-}
-
-#endif
-
+//
+// nsAutoArrayBase is a base class for AutoFallibleTArray and nsAutoTArray.
+// You shouldn't use this class directly.
+//
 template <class TArrayBase, uint32_t N>
 class nsAutoArrayBase : public TArrayBase
 {
 public:
+  typedef nsAutoArrayBase<TArrayBase, N> self_type;
   typedef TArrayBase base_type;
   typedef typename base_type::Header Header;
   typedef typename base_type::elem_type elem_type;
 
+  template<typename Allocator>
+  self_type& operator=(const nsTArray_Impl<elem_type, Allocator>& other) {
+    base_type::operator=(other);
+    return *this;
+  }
+
 protected:
   nsAutoArrayBase() {
     Init();
   }
 
   // We need this constructor because nsAutoTArray and friends all have
   // implicit copy-constructors.  If we don't have this method, those
   // copy-constructors will call nsAutoArrayBase's implicit copy-constructor,
@@ -1459,28 +1464,64 @@ private:
   union {
     char mAutoBuf[sizeof(nsTArrayHeader) + N * sizeof(elem_type)];
     // Do the max operation inline to ensure that it is a compile-time constant.
     mozilla::AlignedElem<(MOZ_ALIGNOF(Header) > MOZ_ALIGNOF(elem_type))
                          ? MOZ_ALIGNOF(Header) : MOZ_ALIGNOF(elem_type)> mAlign;
   };
 };
 
-template<class E, uint32_t N, class Alloc=nsTArrayInfallibleAllocator>
-class nsAutoTArray : public nsAutoArrayBase<nsTArray<E, Alloc>, N>
+//
+// nsAutoTArray<E, N> is an infallible vector class with N elements of inline
+// storage.  If you try to store more than N elements inside an
+// nsAutoTArray<E, N>, we'll call malloc() and store them all on the heap.
+//
+// Note that you can cast an nsAutoTArray<E, N> to
+// |const AutoFallibleTArray<E, N>&|.
+//
+template<class E, uint32_t N>
+class nsAutoTArray : public nsAutoArrayBase<nsTArray<E>, N>
 {
-  typedef nsAutoArrayBase<nsTArray<E, Alloc>, N> Base;
+  typedef nsAutoTArray<E, N> self_type;
+  typedef nsAutoArrayBase<nsTArray<E>, N> Base;
 
 public:
   nsAutoTArray() {}
 
   template<typename Allocator>
-  nsAutoTArray(const nsTArray<E, Allocator>& other) {
+  nsAutoTArray(const nsTArray_Impl<E, Allocator>& other) {
     Base::AppendElements(other);
   }
+
+  operator const AutoFallibleTArray<E, N>&() const {
+    return *reinterpret_cast<const AutoFallibleTArray<E, N>*>(this);
+  }
+};
+
+//
+// AutoFallibleTArray<E, N> is a fallible vector class with N elements of
+// inline storage.
+//
+template<class E, uint32_t N>
+class AutoFallibleTArray : public nsAutoArrayBase<FallibleTArray<E>, N>
+{
+  typedef AutoFallibleTArray<E, N> self_type;
+  typedef nsAutoArrayBase<FallibleTArray<E>, N> Base;
+
+public:
+  AutoFallibleTArray() {}
+
+  template<typename Allocator>
+  AutoFallibleTArray(const nsTArray_Impl<E, Allocator>& other) {
+    Base::AppendElements(other);
+  }
+
+  operator const nsAutoTArray<E, N>&() const {
+    return *reinterpret_cast<const nsAutoTArray<E, N>*>(this);
+  }
 };
 
 // Assert that nsAutoTArray doesn't have any extra padding inside.
 //
 // It's important that the data stored in this auto array takes up a multiple of
 // 8 bytes; e.g. nsAutoTArray<uint32_t, 1> wouldn't work.  Since nsAutoTArray
 // contains a pointer, its size must be a multiple of alignof(void*).  (This is
 // because any type may be placed into an array, and there's no padding between
@@ -1491,70 +1532,12 @@ public:
 // 64-bit system, where the compiler inserts 4 bytes of padding at the end of
 // the auto array to make its size a multiple of alignof(void*) == 8 bytes.
 
 MOZ_STATIC_ASSERT(sizeof(nsAutoTArray<uint32_t, 2>) ==
                   sizeof(void*) + sizeof(nsTArrayHeader) + sizeof(uint32_t) * 2,
                   "nsAutoTArray shouldn't contain any extra padding, "
                   "see the comment");
 
-template<class E, uint32_t N>
-class AutoFallibleTArray : public nsAutoArrayBase<FallibleTArray<E>, N>
-{
-  typedef nsAutoArrayBase<FallibleTArray<E>, N> Base;
-
-public:
-  AutoFallibleTArray() {}
-
-  template<typename Allocator>
-  AutoFallibleTArray(const nsTArray<E, Allocator>& other) {
-    Base::AppendElements(other);
-  }
-};
-
-#if defined(MOZALLOC_HAVE_XMALLOC)
-template<class E, uint32_t N>
-class AutoInfallibleTArray : public nsAutoArrayBase<InfallibleTArray<E>, N>
-{
-  typedef nsAutoArrayBase<InfallibleTArray<E>, N> Base;
-
-public:
-  AutoInfallibleTArray() {}
-
-  template<typename Allocator>
-  AutoInfallibleTArray(const nsTArray<E, Allocator>& other) {
-    Base::AppendElements(other);
-  }
-};
-#endif
-
-// specializations for N = 0. this makes the inheritance model easier for
-// templated users of nsAutoTArray.
-template<class E>
-class nsAutoTArray<E, 0, nsTArrayInfallibleAllocator> :
-  public nsAutoArrayBase< nsTArray<E, nsTArrayInfallibleAllocator>, 0>
-{
-public:
-  nsAutoTArray() {}
-};
-
-template<class E>
-class AutoFallibleTArray<E, 0> :
-  public nsAutoArrayBase< FallibleTArray<E>, 0>
-{
-public:
-  AutoFallibleTArray() {}
-};
-
-#if defined(MOZALLOC_HAVE_XMALLOC)
-template<class E>
-class AutoInfallibleTArray<E, 0> :
-  public nsAutoArrayBase< InfallibleTArray<E>, 0>
-{
-public:
-  AutoInfallibleTArray() {}
-};
-#endif
- 
-// Definitions of nsTArray methods
+// Definitions of nsTArray_Impl methods
 #include "nsTArray-inl.h"
 
 #endif  // nsTArray_h__
new file mode 100644
--- /dev/null
+++ b/xpcom/glue/nsTArrayForwardDeclare.h
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsTArrayForwardDeclare_h__
+#define nsTArrayForwardDeclare_h__
+
+//
+// This simple header file contains forward declarations for the TArray family
+// of classes.
+//
+// Including this header is preferable to writing
+//
+//   template<class E> class nsTArray;
+//
+// yourself, since this header gives us flexibility to e.g. change the default
+// template parameters.
+//
+
+#include "mozilla/StandardInteger.h"
+
+template<class E>
+class nsTArray;
+
+template<class E>
+class FallibleTArray;
+
+template<class E, uint32_t N>
+class nsAutoTArray;
+
+template<class E, uint32_t N>
+class AutoFallibleTArray;
+
+#define InfallibleTArray nsTArray
+#define AutoInfallibleTArray nsAutoTArray
+
+#endif