Bug 1654991 - Simplify move constructor of nsTArray_Impl. r=froydnj

The move constructor of nsTArray_Impl (and therefore of nsTArray) was
implemented using SwapElements, which is a rather generic and therefore
complex method (in the sense of template instantiation and code generation),
which doesn't make use of the knowledge that the target array does not have
inline storage and is empty with 0 capacity. Therefore, a new specialized method,
MoveConstructNonAutoArray, is introduced that does use this knowledge. This
adds another method to maintain, but given that the move constructor is a
frequently used operation that is expected to have a small compile-time and
run-time cost (potentially used implicitly), this seems like a reasonable
trade-off.

Differential Revision: https://phabricator.services.mozilla.com/D84804
This commit is contained in:
Simon Giesecke 2020-08-03 15:14:38 +00:00
Родитель 32848c3a4f
Коммит fcbd7f145f
2 изменённых файлов: 44 добавлений и 2 удалений

Просмотреть файл

@ -506,6 +506,38 @@ nsTArray_base<Alloc, RelocationStrategy>::SwapArrayElements(
return ActualAlloc::SuccessResult();
}
template <class Alloc, class RelocationStrategy>
template <class Allocator>
void nsTArray_base<Alloc, RelocationStrategy>::MoveConstructNonAutoArray(
nsTArray_base<Allocator, RelocationStrategy>& aOther, size_type aElemSize,
size_t aElemAlign) {
// We know that we are not an (Copyable)AutoTArray and we know that we are
// empty, so don't use SwapArrayElements which doesn't know either of these
// facts and is very complex.
// aOther might be an (Copyable)AutoTArray though, and it might use its inline
// buffer.
const bool otherUsesAutoArrayBuffer = aOther.UsesAutoArrayBuffer();
if (otherUsesAutoArrayBuffer) {
// Use nsTArrayInfallibleAllocator regardless of Alloc because this is
// called from a move constructor, which cannot report an error to the
// caller.
aOther.template EnsureNotUsingAutoArrayBuffer<nsTArrayInfallibleAllocator>(
aElemSize);
}
const bool otherIsAuto = otherUsesAutoArrayBuffer || aOther.IsAutoArray();
mHdr = aOther.mHdr;
if (otherIsAuto) {
mHdr->mIsAutoArray = false;
aOther.mHdr = aOther.GetAutoArrayBufferUnsafe(aElemAlign);
aOther.mHdr->mLength = 0;
} else {
aOther.mHdr = aOther.EmptyHdr();
}
}
template <class Alloc, class RelocationStrategy>
template <typename ActualAlloc>
bool nsTArray_base<Alloc, RelocationStrategy>::EnsureNotUsingAutoArrayBuffer(

Просмотреть файл

@ -512,6 +512,11 @@ class nsTArray_base {
nsTArray_base<Allocator, RelocationStrategy>& aOther, size_type aElemSize,
size_t aElemAlign);
template <class Allocator>
void MoveConstructNonAutoArray(
nsTArray_base<Allocator, RelocationStrategy>& aOther, size_type aElemSize,
size_t aElemAlign);
// This is an RAII class used in SwapArrayElements.
class IsAutoArrayRestorer {
public:
@ -1007,8 +1012,13 @@ class nsTArray_Impl
// Initialize this array with an r-value.
// Allow different types of allocators, since the allocator doesn't matter.
template <typename Allocator>
explicit nsTArray_Impl(nsTArray_Impl<E, Allocator>&& aOther) {
SwapElements(aOther);
explicit nsTArray_Impl(nsTArray_Impl<E, Allocator>&& aOther) noexcept {
// We cannot be a (Copyable)AutoTArray because that overrides this ctor.
MOZ_ASSERT(!this->IsAutoArray());
// This does not use SwapArrayElements because that's unnecessarily complex.
this->MoveConstructNonAutoArray(aOther, sizeof(elem_type),
MOZ_ALIGNOF(elem_type));
}
// The array's copy-constructor performs a 'deep' copy of the given array.