mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 11:55:49 +00:00
Bug 1431122 - Part 1: Add UnorderedRemoveElement[s]At to nsTArray, r=froydnj
MozReview-Commit-ID: H0oqG7H7299
This commit is contained in:
parent
281f61ed94
commit
0c171ce388
@ -273,6 +273,61 @@ nsTArray_base<Alloc, Copy>::ShiftData(index_type aStart,
|
||||
}
|
||||
}
|
||||
|
||||
template<class Alloc, class Copy>
|
||||
template<typename ActualAlloc>
|
||||
void
|
||||
nsTArray_base<Alloc, Copy>::SwapFromEnd(index_type aStart,
|
||||
size_type aCount,
|
||||
size_type aElemSize,
|
||||
size_t aElemAlign)
|
||||
{
|
||||
// This method is part of the implementation of
|
||||
// nsTArray::SwapRemoveElement{s,}At. For more information, read the
|
||||
// documentation on that method.
|
||||
if (aCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We are going to be removing aCount elements. Update our length to point to
|
||||
// the new end of the array.
|
||||
size_type oldLength = mHdr->mLength;
|
||||
mHdr->mLength -= aCount;
|
||||
|
||||
if (mHdr->mLength == 0) {
|
||||
// If we have no elements remaining in the array, we can free our buffer.
|
||||
ShrinkCapacity(aElemSize, aElemAlign);
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine how many elements we need to move from the end of the array into
|
||||
// the now-removed section. This will either be the number of elements which
|
||||
// were removed (if there are more elements in the tail of the array), or the
|
||||
// entire tail of the array, whichever is smaller.
|
||||
size_type relocCount = std::min(aCount, mHdr->mLength - aStart);
|
||||
if (relocCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Move the elements which are now stranded after the end of the array back
|
||||
// into the now-vacated memory.
|
||||
index_type sourceBytes = (oldLength - relocCount) * aElemSize;
|
||||
index_type destBytes = aStart * aElemSize;
|
||||
|
||||
// Perform the final copy. This is guaranteed to be a non-overlapping copy
|
||||
// as our source contains only still-valid entries, and the destination
|
||||
// contains only invalid entries which need to be overwritten.
|
||||
MOZ_ASSERT(sourceBytes >= destBytes,
|
||||
"The source should be after the destination.");
|
||||
MOZ_ASSERT(sourceBytes - destBytes >= relocCount * aElemSize,
|
||||
"The range should be nonoverlapping");
|
||||
|
||||
char* baseAddr = reinterpret_cast<char*>(mHdr + 1);
|
||||
Copy::MoveNonOverlappingRegion(baseAddr + destBytes,
|
||||
baseAddr + sourceBytes,
|
||||
relocCount,
|
||||
aElemSize);
|
||||
}
|
||||
|
||||
template<class Alloc, class Copy>
|
||||
template<typename ActualAlloc>
|
||||
bool
|
||||
|
@ -410,6 +410,17 @@ protected:
|
||||
void ShiftData(index_type aStart, size_type aOldLen, size_type aNewLen,
|
||||
size_type aElemSize, size_t aElemAlign);
|
||||
|
||||
// This method may be called to swap elements from the end of the array to
|
||||
// fill a "gap" in the array. If the resulting array has zero elements, then
|
||||
// the array's memory is free'd.
|
||||
// @param aStart The starting index of the gap.
|
||||
// @param aCount The length of the gap.
|
||||
// @param aElemSize The size of an array element.
|
||||
// @param aElemAlign The alignment in bytes of an array element.
|
||||
template<typename ActualAlloc>
|
||||
void SwapFromEnd(index_type aStart, size_type aCount,
|
||||
size_type aElemSize, size_t aElemAlign);
|
||||
|
||||
// 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 aNum should
|
||||
@ -1717,6 +1728,58 @@ public:
|
||||
// A variation on the RemoveElementsAt method defined above.
|
||||
void RemoveElementAt(index_type aIndex) { RemoveElementsAt(aIndex, 1); }
|
||||
|
||||
// This method performs index-based removals from an array without preserving
|
||||
// the order of the array. This is useful if you are using the array as a
|
||||
// set-like data structure.
|
||||
//
|
||||
// These removals are efficient, as they move as few elements as possible. At
|
||||
// most N elements, where N is the number of removed elements, will have to
|
||||
// be relocated.
|
||||
//
|
||||
// ## Examples
|
||||
//
|
||||
// When removing an element from the end of the array, it can be removed in
|
||||
// place, by destroying it and decrementing the length.
|
||||
//
|
||||
// [ 1, 2, 3 ] => [ 1, 2 ]
|
||||
// ^
|
||||
//
|
||||
// When removing any other single element, it is removed by swapping it with
|
||||
// the last element, and then decrementing the length as before.
|
||||
//
|
||||
// [ 1, 2, 3, 4, 5, 6 ] => [ 1, 6, 3, 4, 5 ]
|
||||
// ^
|
||||
//
|
||||
// This method also supports efficiently removing a range of elements. If they
|
||||
// are at the end, then they can all be removed like in the one element case.
|
||||
//
|
||||
// [ 1, 2, 3, 4, 5, 6 ] => [ 1, 2 ]
|
||||
// ^--------^
|
||||
//
|
||||
// If more elements are removed than exist after the removed section, the
|
||||
// remaining elements will be shifted down like in a normal removal.
|
||||
//
|
||||
// [ 1, 2, 3, 4, 5, 6, 7, 8 ] => [ 1, 2, 7, 8 ]
|
||||
// ^--------^
|
||||
//
|
||||
// And if fewer elements are removed than exist after the removed section,
|
||||
// elements will be moved from the end of the array to fill the vacated space.
|
||||
//
|
||||
// [ 1, 2, 3, 4, 5, 6, 7, 8 ] => [ 1, 7, 8, 4, 5, 6 ]
|
||||
// ^--^
|
||||
//
|
||||
// @param aStart The starting index of the elements to remove. @param aCount
|
||||
// The number of elements to remove.
|
||||
void UnorderedRemoveElementsAt(index_type aStart, size_type aCount);
|
||||
|
||||
// A variation on the UnorderedRemoveElementsAt method defined above to remove
|
||||
// a single element. This operation is sometimes called `SwapRemove`.
|
||||
//
|
||||
// This method is O(1), but does not preserve the order of the elements.
|
||||
void UnorderedRemoveElementAt(index_type aIndex) {
|
||||
UnorderedRemoveElementsAt(aIndex, 1);
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
ClearAndRetainStorage();
|
||||
Compact();
|
||||
@ -2053,6 +2116,28 @@ nsTArray_Impl<E, Alloc>::RemoveElementsAt(index_type aStart, size_type aCount)
|
||||
MOZ_ALIGNOF(elem_type));
|
||||
}
|
||||
|
||||
template<typename E, class Alloc>
|
||||
void
|
||||
nsTArray_Impl<E, Alloc>::UnorderedRemoveElementsAt(index_type aStart, size_type aCount)
|
||||
{
|
||||
MOZ_ASSERT(aCount == 0 || aStart < Length(), "Invalid aStart index");
|
||||
|
||||
mozilla::CheckedInt<index_type> rangeEnd = aStart;
|
||||
rangeEnd += aCount;
|
||||
|
||||
if (MOZ_UNLIKELY(!rangeEnd.isValid() || rangeEnd.value() > Length())) {
|
||||
InvalidArrayIndex_CRASH(aStart, Length());
|
||||
}
|
||||
|
||||
// Destroy the elements which are being removed, and then swap elements in to
|
||||
// replace them from the end. See the docs on the declaration of this
|
||||
// function.
|
||||
DestructRange(aStart, aCount);
|
||||
this->template SwapFromEnd<InfallibleAlloc>(aStart, aCount,
|
||||
sizeof(elem_type),
|
||||
MOZ_ALIGNOF(elem_type));
|
||||
}
|
||||
|
||||
template<typename E, class Alloc>
|
||||
template<typename Predicate>
|
||||
void
|
||||
|
Loading…
Reference in New Issue
Block a user