diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index b85e582e2d28..337210432cfc 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -138,6 +138,7 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID); #include "nsIDOMUserDataHandler.h" #include "nsIFragmentContentSink.h" #include "nsContentCreatorFunctions.h" +#include "nsTPtrArray.h" #ifdef IBMBIDI #include "nsIBidiKeyboard.h" @@ -1228,7 +1229,7 @@ nsContentUtils::GetCommonAncestor(nsINode* aNode1, } // Build the chain of parents - nsAutoVoidArray parents1, parents2; + nsAutoTPtrArray parents1, parents2; do { parents1.AppendElement(aNode1); aNode1 = aNode1->GetNodeParent(); @@ -1239,13 +1240,13 @@ nsContentUtils::GetCommonAncestor(nsINode* aNode1, } while (aNode2); // Find where the parent chain differs - PRUint32 pos1 = parents1.Count(); - PRUint32 pos2 = parents2.Count(); + PRUint32 pos1 = parents1.Length(); + PRUint32 pos2 = parents2.Length(); nsINode* parent = nsnull; PRUint32 len; for (len = PR_MIN(pos1, pos2); len > 0; --len) { - nsINode* child1 = NS_STATIC_CAST(nsINode*, parents1.FastElementAt(--pos1)); - nsINode* child2 = NS_STATIC_CAST(nsINode*, parents2.FastElementAt(--pos2)); + nsINode* child1 = parents1.ElementAt(--pos1); + nsINode* child2 = parents2.ElementAt(--pos2); if (child1 != child2) { break; } @@ -1265,7 +1266,7 @@ nsContentUtils::ComparePosition(nsINode* aNode1, return 0; } - nsAutoVoidArray parents1, parents2; + nsAutoTPtrArray parents1, parents2; // Check if either node is an attribute nsIAttribute* attr1 = nsnull; @@ -1276,7 +1277,7 @@ nsContentUtils::ComparePosition(nsINode* aNode1, // to the chain and walk up to the element if (elem) { aNode1 = elem; - parents1.AppendElement(attr1); + parents1.AppendElement(NS_STATIC_CAST(nsINode*, attr1)); } } if (aNode2->IsNodeOfType(nsINode::eATTRIBUTE)) { @@ -1306,7 +1307,7 @@ nsContentUtils::ComparePosition(nsINode* aNode1, if (elem) { aNode2 = elem; - parents2.AppendElement(attr2); + parents2.AppendElement(NS_STATIC_CAST(nsINode*, attr2)); } } @@ -1326,10 +1327,10 @@ nsContentUtils::ComparePosition(nsINode* aNode1, } while (aNode2); // Check if the nodes are disconnected. - PRUint32 pos1 = parents1.Count(); - PRUint32 pos2 = parents2.Count(); - nsINode* top1 = NS_STATIC_CAST(nsINode*, parents1.FastElementAt(--pos1)); - nsINode* top2 = NS_STATIC_CAST(nsINode*, parents2.FastElementAt(--pos2)); + PRUint32 pos1 = parents1.Length(); + PRUint32 pos2 = parents2.Length(); + nsINode* top1 = parents1.ElementAt(--pos1); + nsINode* top2 = parents2.ElementAt(--pos2); if (top1 != top2) { return top1 < top2 ? (nsIDOM3Node::DOCUMENT_POSITION_PRECEDING | @@ -1344,8 +1345,8 @@ nsContentUtils::ComparePosition(nsINode* aNode1, nsINode* parent = top1; PRUint32 len; for (len = PR_MIN(pos1, pos2); len > 0; --len) { - nsINode* child1 = NS_STATIC_CAST(nsINode*, parents1.FastElementAt(--pos1)); - nsINode* child2 = NS_STATIC_CAST(nsINode*, parents2.FastElementAt(--pos2)); + nsINode* child1 = parents1.ElementAt(--pos1); + nsINode* child2 = parents2.ElementAt(--pos2); if (child1 != child2) { // child1 or child2 can be an attribute here. This will work fine since // IndexOf will return -1 for the attribute making the attribute be diff --git a/xpcom/glue/nsTArray.cpp b/xpcom/glue/nsTArray.cpp index bdf81e00a234..82b607f54c86 100644 --- a/xpcom/glue/nsTArray.cpp +++ b/xpcom/glue/nsTArray.cpp @@ -46,7 +46,7 @@ nsTArray_base::Header nsTArray_base::sEmptyHdr = { 0, 0, 0 }; #ifdef NS_BUILD_REFCNT_LOGGING nsTArray_base::nsTArray_base() - : mHdr(NS_CONST_CAST(Header *, &sEmptyHdr)) { + : mHdr(&sEmptyHdr) { MOZ_COUNT_CTOR(nsTArray_base); } diff --git a/xpcom/glue/nsTArray.h b/xpcom/glue/nsTArray.h index 1f0dbfa610f7..312cdf593611 100644 --- a/xpcom/glue/nsTArray.h +++ b/xpcom/glue/nsTArray.h @@ -77,10 +77,16 @@ class NS_COM_GLUE nsTArray_base { return mHdr->mCapacity; } +#ifdef DEBUG + void* DebugGetHeader() { + return mHdr; + } +#endif + protected: #ifndef NS_BUILD_REFCNT_LOGGING nsTArray_base() - : mHdr(NS_CONST_CAST(Header *, &sEmptyHdr)) { + : mHdr(&sEmptyHdr) { } #else nsTArray_base(); @@ -108,8 +114,11 @@ class NS_COM_GLUE nsTArray_base { size_type elementSize); // This method increments the length member of the array's header. + // Note that mHdr may actually be sEmptyHdr in the case where a + // zero-length array is inserted into our array. But then n should + // always be 0. void IncrementLength(PRUint32 n) { - NS_ASSERTION(mHdr != &sEmptyHdr, "bad data pointer"); + NS_ASSERTION(mHdr != &sEmptyHdr || n == 0, "bad data pointer"); mHdr->mLength += n; } @@ -123,14 +132,44 @@ class NS_COM_GLUE nsTArray_base { protected: + // NOTE: This method isn't heavily optimized if either array is an + // nsAutoTArray. + PRBool SwapArrayElements(nsTArray_base& other, size_type elementSize); + + // Helper function for SwapArrayElements. Ensures that if the array + // is an nsAutoTArray that it doesn't use the built-in buffer. + PRBool EnsureNotUsingAutoArrayBuffer(size_type elemSize); + // We prefix mData with a structure of this type. This is done to minimize // the size of the nsTArray object when it is empty. struct Header { PRUint32 mLength; - PRUint32 mCapacity; + PRUint32 mCapacity : 31; + PRUint32 mIsAutoArray : 1; }; - static const Header sEmptyHdr; + // Returns true if this nsTArray is an nsAutoTArray with a built-in buffer. + PRBool IsAutoArray() { + return mHdr->mIsAutoArray; + } + + // Returns a Header for the built-in buffer of this nsAutoTArray. + Header* GetAutoArrayBuffer() { + NS_ASSERTION(IsAutoArray(), "Should be an auto array to call this"); + + return NS_REINTERPRET_CAST(Header*, &mHdr + 1); + } + + // Returns true if this is an nsAutoTArray and it currently uses the + // built-in buffer to store its elements. + PRBool UsesAutoArrayBuffer() { + return mHdr->mIsAutoArray && mHdr == GetAutoArrayBuffer(); + } + + // This is not const since we may actually write to it. However we will + // always write to it the same data that it already contains. See + // IncrementLength + static Header sEmptyHdr; // The array's elements (prefixed with a Header). This pointer is never // null. If the array is empty, then this will point to sEmptyHdr. @@ -533,10 +572,10 @@ class nsTArray : public nsTArray_base { // This method causes the elements contained in this array and the given // array to be swapped. - void SwapElements(self_type& other) { - Header *h = other.mHdr; - other.mHdr = mHdr; - mHdr = h; + // NOTE: This method isn't heavily optimized if either array is an + // nsAutoTArray. + PRBool SwapElements(self_type& other) { + return SwapArrayElements(other, sizeof(elem_type)); } // @@ -661,4 +700,22 @@ class nsTArray : public nsTArray_base { } }; +template +class nsAutoTArray : public nsTArray { + public: + nsAutoTArray() { + mHdr = NS_REINTERPRET_CAST(Header*, &mAutoBuf); + mHdr->mLength = 0; + mHdr->mCapacity = N; + mHdr->mIsAutoArray = 1; + + NS_ASSERTION(GetAutoArrayBuffer() == + NS_REINTERPRET_CAST(Header*, &mAutoBuf), + "GetAutoArrayBuffer needs to be fixed"); + } + + protected: + char mAutoBuf[sizeof(Header) + N * sizeof(E)]; +}; + #endif // nsTArray_h__ diff --git a/xpcom/glue/nsTPtrArray.h b/xpcom/glue/nsTPtrArray.h index bfed6169b7e6..57a5146240af 100755 --- a/xpcom/glue/nsTPtrArray.h +++ b/xpcom/glue/nsTPtrArray.h @@ -94,4 +94,22 @@ class nsTPtrArray : public nsTArray { } }; +template +class nsAutoTPtrArray : public nsTPtrArray { + public: + nsAutoTPtrArray() { + mHdr = NS_REINTERPRET_CAST(Header*, &mAutoBuf); + mHdr->mLength = 0; + mHdr->mCapacity = N; + mHdr->mIsAutoArray = 1; + + NS_ASSERTION(GetAutoArrayBuffer() == + NS_REINTERPRET_CAST(Header*, &mAutoBuf), + "GetAutoArrayBuffer needs to be fixed"); + } + + protected: + char mAutoBuf[sizeof(Header) + N * sizeof(E*)]; +}; + #endif // nsTPtrArray_h__ diff --git a/xpcom/tests/TestTArray.cpp b/xpcom/tests/TestTArray.cpp index 1012796609e4..44ccac9df3ff 100644 --- a/xpcom/tests/TestTArray.cpp +++ b/xpcom/tests/TestTArray.cpp @@ -410,6 +410,72 @@ static PRBool test_ptrarray() { //---- +static PRBool test_autoarray() { + PRUint32 data[] = {4,6,8,2,4,1,5,7,3}; + nsAutoTArray array; + + void* hdr = array.DebugGetHeader(); + if (hdr == (nsTArray()).DebugGetHeader()) + return PR_FALSE; + if (hdr == (nsAutoTArray()).DebugGetHeader()) + return PR_FALSE; + + array.AppendElement(1); + if (hdr != array.DebugGetHeader()) + return PR_FALSE; + + array.RemoveElement(1); + array.AppendElements(data, NS_ARRAY_LENGTH(data)); + if (hdr != array.DebugGetHeader()) + return PR_FALSE; + + array.AppendElement(2); + if (hdr == array.DebugGetHeader()) + return PR_FALSE; + + array.Clear(); + array.Compact(); + if (hdr != array.DebugGetHeader()) + return PR_FALSE; + array.AppendElements(data, NS_ARRAY_LENGTH(data)); + if (hdr != array.DebugGetHeader()) + return PR_FALSE; + + nsTArray array2; + void* emptyHdr = array2.DebugGetHeader(); + array.SwapElements(array2); + if (emptyHdr == array.DebugGetHeader()) + return PR_FALSE; + if (hdr == array2.DebugGetHeader()) + return PR_FALSE; + PRUint32 i; + for (i = 0; i < NS_ARRAY_LENGTH(data); ++i) { + if (array2[i] != data[i]) + return PR_FALSE; + } + if (!array.IsEmpty()) + return PR_FALSE; + + array.Compact(); + array.AppendElements(data, NS_ARRAY_LENGTH(data)); + PRUint32 data3[] = {5, 7, 11}; + nsAutoTArray array3; + array3.AppendElements(data3, NS_ARRAY_LENGTH(data3)); + array.SwapElements(array3); + for (i = 0; i < NS_ARRAY_LENGTH(data); ++i) { + if (array3[i] != data[i]) + return PR_FALSE; + } + for (i = 0; i < NS_ARRAY_LENGTH(data3); ++i) { + if (array[i] != data3[i]) + return PR_FALSE; + } + + return PR_TRUE; +} + +//---- + typedef PRBool (*TestFunc)(); #define DECL_TEST(name) { #name, name } @@ -426,6 +492,7 @@ static const struct Test { DECL_TEST(test_comptr_array), DECL_TEST(test_refptr_array), DECL_TEST(test_ptrarray), + DECL_TEST(test_autoarray), { nsnull, nsnull } };