mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-30 11:07:29 +09:00
Issue #2148 - Shrink Vector from (usually) four pointers in size to three when no inline storage is used.
See Bug 1338374
This commit is contained in:
parent
0365f940fe
commit
481069044d
2 changed files with 168 additions and 82 deletions
199
mfbt/Vector.h
199
mfbt/Vector.h
|
|
@ -146,7 +146,7 @@ struct VectorImpl
|
||||||
aV.free_(aV.mBegin);
|
aV.free_(aV.mBegin);
|
||||||
aV.mBegin = newbuf;
|
aV.mBegin = newbuf;
|
||||||
/* aV.mLength is unchanged. */
|
/* aV.mLength is unchanged. */
|
||||||
aV.mCapacity = aNewCap;
|
aV.mTail.mCapacity = aNewCap;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -225,28 +225,30 @@ struct VectorImpl<T, N, AP, true>
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!aV.usingInlineStorage());
|
MOZ_ASSERT(!aV.usingInlineStorage());
|
||||||
MOZ_ASSERT(!CapacityHasExcessSpace<T>(aNewCap));
|
MOZ_ASSERT(!CapacityHasExcessSpace<T>(aNewCap));
|
||||||
T* newbuf = aV.template pod_realloc<T>(aV.mBegin, aV.mCapacity, aNewCap);
|
T* newbuf =
|
||||||
|
aV.template pod_realloc<T>(aV.mBegin, aV.mTail.mCapacity, aNewCap);
|
||||||
if (MOZ_UNLIKELY(!newbuf)) {
|
if (MOZ_UNLIKELY(!newbuf)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
aV.mBegin = newbuf;
|
aV.mBegin = newbuf;
|
||||||
/* aV.mLength is unchanged. */
|
/* aV.mLength is unchanged. */
|
||||||
aV.mCapacity = aNewCap;
|
aV.mTail.mCapacity = aNewCap;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
podResizeToFit(Vector<T, N, AP>& aV)
|
podResizeToFit(Vector<T, N, AP>& aV)
|
||||||
{
|
{
|
||||||
if (aV.usingInlineStorage() || aV.mLength == aV.mCapacity) {
|
if (aV.usingInlineStorage() || aV.mLength == aV.mTail.mCapacity) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
T* newbuf = aV.template pod_realloc<T>(aV.mBegin, aV.mCapacity, aV.mLength);
|
T* newbuf =
|
||||||
|
aV.template pod_realloc<T>(aV.mBegin, aV.mTail.mCapacity, aV.mLength);
|
||||||
if (MOZ_UNLIKELY(!newbuf)) {
|
if (MOZ_UNLIKELY(!newbuf)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
aV.mBegin = newbuf;
|
aV.mBegin = newbuf;
|
||||||
aV.mCapacity = aV.mLength;
|
aV.mTail.mCapacity = aV.mLength;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -341,6 +343,35 @@ class MOZ_NON_PARAM Vector final : private AllocPolicy
|
||||||
/* Number of elements in the vector. */
|
/* Number of elements in the vector. */
|
||||||
size_t mLength;
|
size_t mLength;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Memory used to store capacity, reserved element count (debug builds only),
|
||||||
|
* and inline storage. The simple "answer" is:
|
||||||
|
*
|
||||||
|
* size_t mCapacity;
|
||||||
|
* #ifdef DEBUG
|
||||||
|
* size_t mReserved;
|
||||||
|
* #endif
|
||||||
|
* alignas(T) unsigned char mBytes[kInlineCapacity * sizeof(T)];
|
||||||
|
*
|
||||||
|
* but there are complications. First, C++ forbids zero-sized arrays that
|
||||||
|
* might result. Second, we don't want zero capacity to affect Vector's size
|
||||||
|
* (even empty classes take up a byte, unless they're base classes).
|
||||||
|
*
|
||||||
|
* Yet again, we eliminate the zero-sized array using partial specialization.
|
||||||
|
* And we eliminate potential size hit by putting capacity/reserved in one
|
||||||
|
* struct, then putting the array (if any) in a derived struct. If no array
|
||||||
|
* is needed, the derived struct won't consume extra space.
|
||||||
|
*/
|
||||||
|
struct CapacityAndReserved
|
||||||
|
{
|
||||||
|
explicit CapacityAndReserved(size_t aCapacity, size_t aReserved)
|
||||||
|
: mCapacity(aCapacity)
|
||||||
|
#ifdef DEBUG
|
||||||
|
, mReserved(aReserved)
|
||||||
|
#endif
|
||||||
|
{}
|
||||||
|
CapacityAndReserved() = default;
|
||||||
|
|
||||||
/* Max number of elements storable in the vector without resizing. */
|
/* Max number of elements storable in the vector without resizing. */
|
||||||
size_t mCapacity;
|
size_t mCapacity;
|
||||||
|
|
||||||
|
|
@ -348,35 +379,48 @@ class MOZ_NON_PARAM Vector final : private AllocPolicy
|
||||||
/* Max elements of reserved or used space in this vector. */
|
/* Max elements of reserved or used space in this vector. */
|
||||||
size_t mReserved;
|
size_t mReserved;
|
||||||
#endif
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
// Silence warnings about this struct possibly being padded dued to the
|
||||||
|
// alignas() in it -- there's nothing we can do to avoid it.
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# pragma warning(push)
|
||||||
|
# pragma warning(disable:4324)
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
/*
|
|
||||||
* Memory used for inline storage. We want basically this:
|
|
||||||
*
|
|
||||||
* alignas(T) unsigned char storage[kInlineCapacity * sizeof(T)];
|
|
||||||
*
|
|
||||||
* but C++ forbids zero-sized arrays that might result if we did this. We fix
|
|
||||||
* this by (again) using partial specialization, defining an array only if
|
|
||||||
* contains at least one element.
|
|
||||||
*/
|
|
||||||
template<size_t Capacity, size_t Dummy>
|
template<size_t Capacity, size_t Dummy>
|
||||||
struct InlineStorage
|
struct CRAndStorage : CapacityAndReserved
|
||||||
{
|
{
|
||||||
|
explicit CRAndStorage(size_t aCapacity, size_t aReserved)
|
||||||
|
: CapacityAndReserved(aCapacity, aReserved)
|
||||||
|
{}
|
||||||
|
CRAndStorage() = default;
|
||||||
|
|
||||||
alignas(T) unsigned char mBytes[Capacity * sizeof(T)];
|
alignas(T) unsigned char mBytes[Capacity * sizeof(T)];
|
||||||
|
|
||||||
// GCC fails due to -Werror=strict-aliasing if |mBytes| is directly cast to
|
// GCC fails due to -Werror=strict-aliasing if |mBytes| is directly cast to
|
||||||
// T*. Indirecting through this function addresses the problem.
|
// T*. Indirecting through this function addresses the problem.
|
||||||
void* data() { return mBytes; }
|
void* data() { return mBytes; }
|
||||||
|
|
||||||
T* addr() { return static_cast<T*>(data()); }
|
T* storage() { return static_cast<T*>(data()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template<size_t Dummy>
|
template<size_t Dummy>
|
||||||
struct InlineStorage<0, Dummy>
|
struct CRAndStorage<0, Dummy> : CapacityAndReserved
|
||||||
{
|
{
|
||||||
T* addr() { return nullptr; }
|
explicit CRAndStorage(size_t aCapacity, size_t aReserved)
|
||||||
|
: CapacityAndReserved(aCapacity, aReserved)
|
||||||
|
{}
|
||||||
|
CRAndStorage() = default;
|
||||||
|
|
||||||
|
T* storage() { return nullptr; }
|
||||||
};
|
};
|
||||||
|
|
||||||
InlineStorage<kInlineCapacity, 0> mStorage;
|
CRAndStorage<kInlineCapacity, 0> mTail;
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# pragma warning(pop)
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
friend class ReentrancyGuard;
|
friend class ReentrancyGuard;
|
||||||
|
|
@ -392,7 +436,7 @@ class MOZ_NON_PARAM Vector final : private AllocPolicy
|
||||||
|
|
||||||
T* inlineStorage()
|
T* inlineStorage()
|
||||||
{
|
{
|
||||||
return mStorage.addr();
|
return mTail.storage();
|
||||||
}
|
}
|
||||||
|
|
||||||
T* beginNoCheck() const
|
T* beginNoCheck() const
|
||||||
|
|
@ -420,9 +464,9 @@ class MOZ_NON_PARAM Vector final : private AllocPolicy
|
||||||
*/
|
*/
|
||||||
size_t reserved() const
|
size_t reserved() const
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mLength <= mReserved);
|
MOZ_ASSERT(mLength <= mTail.mReserved);
|
||||||
MOZ_ASSERT(mReserved <= mCapacity);
|
MOZ_ASSERT(mTail.mReserved <= mTail.mCapacity);
|
||||||
return mReserved;
|
return mTail.mReserved;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -455,7 +499,7 @@ public:
|
||||||
|
|
||||||
bool empty() const { return mLength == 0; }
|
bool empty() const { return mLength == 0; }
|
||||||
|
|
||||||
size_t capacity() const { return mCapacity; }
|
size_t capacity() const { return mTail.mCapacity; }
|
||||||
|
|
||||||
T* begin()
|
T* begin()
|
||||||
{
|
{
|
||||||
|
|
@ -782,10 +826,10 @@ private:
|
||||||
/* This does the re-entrancy check plus several other sanity checks. */
|
/* This does the re-entrancy check plus several other sanity checks. */
|
||||||
#define MOZ_REENTRANCY_GUARD_ET_AL \
|
#define MOZ_REENTRANCY_GUARD_ET_AL \
|
||||||
ReentrancyGuard g(*this); \
|
ReentrancyGuard g(*this); \
|
||||||
MOZ_ASSERT_IF(usingInlineStorage(), mCapacity == kInlineCapacity); \
|
MOZ_ASSERT_IF(usingInlineStorage(), mTail.mCapacity == kInlineCapacity); \
|
||||||
MOZ_ASSERT(reserved() <= mCapacity); \
|
MOZ_ASSERT(reserved() <= mTail.mCapacity); \
|
||||||
MOZ_ASSERT(mLength <= reserved()); \
|
MOZ_ASSERT(mLength <= reserved()); \
|
||||||
MOZ_ASSERT(mLength <= mCapacity)
|
MOZ_ASSERT(mLength <= mTail.mCapacity)
|
||||||
|
|
||||||
/* Vector Implementation */
|
/* Vector Implementation */
|
||||||
|
|
||||||
|
|
@ -794,9 +838,8 @@ MOZ_ALWAYS_INLINE
|
||||||
Vector<T, N, AP>::Vector(AP aAP)
|
Vector<T, N, AP>::Vector(AP aAP)
|
||||||
: AP(aAP)
|
: AP(aAP)
|
||||||
, mLength(0)
|
, mLength(0)
|
||||||
, mCapacity(kInlineCapacity)
|
, mTail(kInlineCapacity, 0)
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
, mReserved(0)
|
|
||||||
, mEntered(false)
|
, mEntered(false)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
|
@ -813,9 +856,9 @@ Vector<T, N, AllocPolicy>::Vector(Vector&& aRhs)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
mLength = aRhs.mLength;
|
mLength = aRhs.mLength;
|
||||||
mCapacity = aRhs.mCapacity;
|
mTail.mCapacity = aRhs.mTail.mCapacity;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
mReserved = aRhs.mReserved;
|
mTail.mReserved = aRhs.mTail.mReserved;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (aRhs.usingInlineStorage()) {
|
if (aRhs.usingInlineStorage()) {
|
||||||
|
|
@ -833,10 +876,10 @@ Vector<T, N, AllocPolicy>::Vector(Vector&& aRhs)
|
||||||
*/
|
*/
|
||||||
mBegin = aRhs.mBegin;
|
mBegin = aRhs.mBegin;
|
||||||
aRhs.mBegin = aRhs.inlineStorage();
|
aRhs.mBegin = aRhs.inlineStorage();
|
||||||
aRhs.mCapacity = kInlineCapacity;
|
aRhs.mTail.mCapacity = kInlineCapacity;
|
||||||
aRhs.mLength = 0;
|
aRhs.mLength = 0;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
aRhs.mReserved = 0;
|
aRhs.mTail.mReserved = 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -900,7 +943,7 @@ Vector<T, N, AP>::convertToHeapStorage(size_t aNewCap)
|
||||||
/* Switch in heap buffer. */
|
/* Switch in heap buffer. */
|
||||||
mBegin = newBuf;
|
mBegin = newBuf;
|
||||||
/* mLength is unchanged. */
|
/* mLength is unchanged. */
|
||||||
mCapacity = aNewCap;
|
mTail.mCapacity = aNewCap;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -908,7 +951,7 @@ template<typename T, size_t N, class AP>
|
||||||
MOZ_NEVER_INLINE bool
|
MOZ_NEVER_INLINE bool
|
||||||
Vector<T, N, AP>::growStorageBy(size_t aIncr)
|
Vector<T, N, AP>::growStorageBy(size_t aIncr)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mLength + aIncr > mCapacity);
|
MOZ_ASSERT(mLength + aIncr > mTail.mCapacity);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When choosing a new capacity, its size should is as close to 2**N bytes
|
* When choosing a new capacity, its size should is as close to 2**N bytes
|
||||||
|
|
@ -1000,9 +1043,9 @@ Vector<T, N, AP>::initCapacity(size_t aRequest)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
mBegin = newbuf;
|
mBegin = newbuf;
|
||||||
mCapacity = aRequest;
|
mTail.mCapacity = aRequest;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
mReserved = aRequest;
|
mTail.mReserved = aRequest;
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -1027,7 +1070,7 @@ Vector<T, N, AP>::maybeCheckSimulatedOOM(size_t aRequestedSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (aRequestedSize <= mReserved) {
|
if (aRequestedSize <= mTail.mReserved) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -1040,7 +1083,7 @@ inline bool
|
||||||
Vector<T, N, AP>::reserve(size_t aRequest)
|
Vector<T, N, AP>::reserve(size_t aRequest)
|
||||||
{
|
{
|
||||||
MOZ_REENTRANCY_GUARD_ET_AL;
|
MOZ_REENTRANCY_GUARD_ET_AL;
|
||||||
if (aRequest > mCapacity) {
|
if (aRequest > mTail.mCapacity) {
|
||||||
if (MOZ_UNLIKELY(!growStorageBy(aRequest - mLength))) {
|
if (MOZ_UNLIKELY(!growStorageBy(aRequest - mLength))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -1048,11 +1091,11 @@ Vector<T, N, AP>::reserve(size_t aRequest)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (aRequest > mReserved) {
|
if (aRequest > mTail.mReserved) {
|
||||||
mReserved = aRequest;
|
mTail.mReserved = aRequest;
|
||||||
}
|
}
|
||||||
MOZ_ASSERT(mLength <= mReserved);
|
MOZ_ASSERT(mLength <= mTail.mReserved);
|
||||||
MOZ_ASSERT(mReserved <= mCapacity);
|
MOZ_ASSERT(mTail.mReserved <= mTail.mCapacity);
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -1080,20 +1123,20 @@ MOZ_ALWAYS_INLINE bool
|
||||||
Vector<T, N, AP>::growBy(size_t aIncr)
|
Vector<T, N, AP>::growBy(size_t aIncr)
|
||||||
{
|
{
|
||||||
MOZ_REENTRANCY_GUARD_ET_AL;
|
MOZ_REENTRANCY_GUARD_ET_AL;
|
||||||
if (aIncr > mCapacity - mLength) {
|
if (aIncr > mTail.mCapacity - mLength) {
|
||||||
if (MOZ_UNLIKELY(!growStorageBy(aIncr))) {
|
if (MOZ_UNLIKELY(!growStorageBy(aIncr))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (!maybeCheckSimulatedOOM(mLength + aIncr)) {
|
} else if (!maybeCheckSimulatedOOM(mLength + aIncr)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
MOZ_ASSERT(mLength + aIncr <= mCapacity);
|
MOZ_ASSERT(mLength + aIncr <= mTail.mCapacity);
|
||||||
T* newend = endNoCheck() + aIncr;
|
T* newend = endNoCheck() + aIncr;
|
||||||
Impl::initialize(endNoCheck(), newend);
|
Impl::initialize(endNoCheck(), newend);
|
||||||
mLength += aIncr;
|
mLength += aIncr;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (mLength > mReserved) {
|
if (mLength > mTail.mReserved) {
|
||||||
mReserved = mLength;
|
mTail.mReserved = mLength;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -1104,7 +1147,7 @@ MOZ_ALWAYS_INLINE bool
|
||||||
Vector<T, N, AP>::growByUninitialized(size_t aIncr)
|
Vector<T, N, AP>::growByUninitialized(size_t aIncr)
|
||||||
{
|
{
|
||||||
MOZ_REENTRANCY_GUARD_ET_AL;
|
MOZ_REENTRANCY_GUARD_ET_AL;
|
||||||
if (aIncr > mCapacity - mLength) {
|
if (aIncr > mTail.mCapacity - mLength) {
|
||||||
if (MOZ_UNLIKELY(!growStorageBy(aIncr))) {
|
if (MOZ_UNLIKELY(!growStorageBy(aIncr))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -1112,8 +1155,8 @@ Vector<T, N, AP>::growByUninitialized(size_t aIncr)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (mLength + aIncr > mReserved) {
|
if (mLength + aIncr > mTail.mReserved) {
|
||||||
mReserved = mLength + aIncr;
|
mTail.mReserved = mLength + aIncr;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
infallibleGrowByUninitialized(aIncr);
|
infallibleGrowByUninitialized(aIncr);
|
||||||
|
|
@ -1172,9 +1215,9 @@ Vector<T, N, AP>::clearAndFree()
|
||||||
}
|
}
|
||||||
this->free_(beginNoCheck());
|
this->free_(beginNoCheck());
|
||||||
mBegin = inlineStorage();
|
mBegin = inlineStorage();
|
||||||
mCapacity = kInlineCapacity;
|
mTail.mCapacity = kInlineCapacity;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
mReserved = 0;
|
mTail.mReserved = 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1191,7 +1234,7 @@ template<typename T, size_t N, class AP>
|
||||||
inline bool
|
inline bool
|
||||||
Vector<T, N, AP>::canAppendWithoutRealloc(size_t aNeeded) const
|
Vector<T, N, AP>::canAppendWithoutRealloc(size_t aNeeded) const
|
||||||
{
|
{
|
||||||
return mLength + aNeeded <= mCapacity;
|
return mLength + aNeeded <= mTail.mCapacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, size_t N, class AP>
|
template<typename T, size_t N, class AP>
|
||||||
|
|
@ -1207,8 +1250,8 @@ template<typename U>
|
||||||
MOZ_ALWAYS_INLINE void
|
MOZ_ALWAYS_INLINE void
|
||||||
Vector<T, N, AP>::internalAppend(U&& aU)
|
Vector<T, N, AP>::internalAppend(U&& aU)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mLength + 1 <= mReserved);
|
MOZ_ASSERT(mLength + 1 <= mTail.mReserved);
|
||||||
MOZ_ASSERT(mReserved <= mCapacity);
|
MOZ_ASSERT(mTail.mReserved <= mTail.mCapacity);
|
||||||
Impl::new_(endNoCheck(), Forward<U>(aU));
|
Impl::new_(endNoCheck(), Forward<U>(aU));
|
||||||
++mLength;
|
++mLength;
|
||||||
}
|
}
|
||||||
|
|
@ -1218,7 +1261,7 @@ MOZ_ALWAYS_INLINE bool
|
||||||
Vector<T, N, AP>::appendN(const T& aT, size_t aNeeded)
|
Vector<T, N, AP>::appendN(const T& aT, size_t aNeeded)
|
||||||
{
|
{
|
||||||
MOZ_REENTRANCY_GUARD_ET_AL;
|
MOZ_REENTRANCY_GUARD_ET_AL;
|
||||||
if (mLength + aNeeded > mCapacity) {
|
if (mLength + aNeeded > mTail.mCapacity) {
|
||||||
if (MOZ_UNLIKELY(!growStorageBy(aNeeded))) {
|
if (MOZ_UNLIKELY(!growStorageBy(aNeeded))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -1226,8 +1269,8 @@ Vector<T, N, AP>::appendN(const T& aT, size_t aNeeded)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (mLength + aNeeded > mReserved) {
|
if (mLength + aNeeded > mTail.mReserved) {
|
||||||
mReserved = mLength + aNeeded;
|
mTail.mReserved = mLength + aNeeded;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
internalAppendN(aT, aNeeded);
|
internalAppendN(aT, aNeeded);
|
||||||
|
|
@ -1238,8 +1281,8 @@ template<typename T, size_t N, class AP>
|
||||||
MOZ_ALWAYS_INLINE void
|
MOZ_ALWAYS_INLINE void
|
||||||
Vector<T, N, AP>::internalAppendN(const T& aT, size_t aNeeded)
|
Vector<T, N, AP>::internalAppendN(const T& aT, size_t aNeeded)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mLength + aNeeded <= mReserved);
|
MOZ_ASSERT(mLength + aNeeded <= mTail.mReserved);
|
||||||
MOZ_ASSERT(mReserved <= mCapacity);
|
MOZ_ASSERT(mTail.mReserved <= mTail.mCapacity);
|
||||||
Impl::copyConstructN(endNoCheck(), aNeeded, aT);
|
Impl::copyConstructN(endNoCheck(), aNeeded, aT);
|
||||||
mLength += aNeeded;
|
mLength += aNeeded;
|
||||||
}
|
}
|
||||||
|
|
@ -1304,7 +1347,7 @@ Vector<T, N, AP>::append(const U* aInsBegin, const U* aInsEnd)
|
||||||
{
|
{
|
||||||
MOZ_REENTRANCY_GUARD_ET_AL;
|
MOZ_REENTRANCY_GUARD_ET_AL;
|
||||||
size_t aNeeded = PointerRangeSize(aInsBegin, aInsEnd);
|
size_t aNeeded = PointerRangeSize(aInsBegin, aInsEnd);
|
||||||
if (mLength + aNeeded > mCapacity) {
|
if (mLength + aNeeded > mTail.mCapacity) {
|
||||||
if (MOZ_UNLIKELY(!growStorageBy(aNeeded))) {
|
if (MOZ_UNLIKELY(!growStorageBy(aNeeded))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -1312,8 +1355,8 @@ Vector<T, N, AP>::append(const U* aInsBegin, const U* aInsEnd)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (mLength + aNeeded > mReserved) {
|
if (mLength + aNeeded > mTail.mReserved) {
|
||||||
mReserved = mLength + aNeeded;
|
mTail.mReserved = mLength + aNeeded;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
internalAppend(aInsBegin, aNeeded);
|
internalAppend(aInsBegin, aNeeded);
|
||||||
|
|
@ -1325,8 +1368,8 @@ template<typename U>
|
||||||
MOZ_ALWAYS_INLINE void
|
MOZ_ALWAYS_INLINE void
|
||||||
Vector<T, N, AP>::internalAppend(const U* aInsBegin, size_t aInsLength)
|
Vector<T, N, AP>::internalAppend(const U* aInsBegin, size_t aInsLength)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mLength + aInsLength <= mReserved);
|
MOZ_ASSERT(mLength + aInsLength <= mTail.mReserved);
|
||||||
MOZ_ASSERT(mReserved <= mCapacity);
|
MOZ_ASSERT(mTail.mReserved <= mTail.mCapacity);
|
||||||
Impl::copyConstruct(endNoCheck(), aInsBegin, aInsBegin + aInsLength);
|
Impl::copyConstruct(endNoCheck(), aInsBegin, aInsBegin + aInsLength);
|
||||||
mLength += aInsLength;
|
mLength += aInsLength;
|
||||||
}
|
}
|
||||||
|
|
@ -1337,7 +1380,7 @@ MOZ_ALWAYS_INLINE bool
|
||||||
Vector<T, N, AP>::append(U&& aU)
|
Vector<T, N, AP>::append(U&& aU)
|
||||||
{
|
{
|
||||||
MOZ_REENTRANCY_GUARD_ET_AL;
|
MOZ_REENTRANCY_GUARD_ET_AL;
|
||||||
if (mLength == mCapacity) {
|
if (mLength == mTail.mCapacity) {
|
||||||
if (MOZ_UNLIKELY(!growStorageBy(1))) {
|
if (MOZ_UNLIKELY(!growStorageBy(1))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -1345,8 +1388,8 @@ Vector<T, N, AP>::append(U&& aU)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (mLength + 1 > mReserved) {
|
if (mLength + 1 > mTail.mReserved) {
|
||||||
mReserved = mLength + 1;
|
mTail.mReserved = mLength + 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
internalAppend(Forward<U>(aU));
|
internalAppend(Forward<U>(aU));
|
||||||
|
|
@ -1401,9 +1444,9 @@ Vector<T, N, AP>::extractRawBuffer()
|
||||||
T* ret = mBegin;
|
T* ret = mBegin;
|
||||||
mBegin = inlineStorage();
|
mBegin = inlineStorage();
|
||||||
mLength = 0;
|
mLength = 0;
|
||||||
mCapacity = kInlineCapacity;
|
mTail.mCapacity = kInlineCapacity;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
mReserved = 0;
|
mTail.mReserved = 0;
|
||||||
#endif
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
@ -1427,9 +1470,9 @@ Vector<T, N, AP>::extractOrCopyRawBuffer()
|
||||||
Impl::destroy(beginNoCheck(), endNoCheck());
|
Impl::destroy(beginNoCheck(), endNoCheck());
|
||||||
mBegin = inlineStorage();
|
mBegin = inlineStorage();
|
||||||
mLength = 0;
|
mLength = 0;
|
||||||
mCapacity = kInlineCapacity;
|
mTail.mCapacity = kInlineCapacity;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
mReserved = 0;
|
mTail.mReserved = 0;
|
||||||
#endif
|
#endif
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
@ -1455,17 +1498,17 @@ Vector<T, N, AP>::replaceRawBuffer(T* aP, size_t aLength)
|
||||||
*/
|
*/
|
||||||
mBegin = inlineStorage();
|
mBegin = inlineStorage();
|
||||||
mLength = aLength;
|
mLength = aLength;
|
||||||
mCapacity = kInlineCapacity;
|
mTail.mCapacity = kInlineCapacity;
|
||||||
Impl::moveConstruct(mBegin, aP, aP + aLength);
|
Impl::moveConstruct(mBegin, aP, aP + aLength);
|
||||||
Impl::destroy(aP, aP + aLength);
|
Impl::destroy(aP, aP + aLength);
|
||||||
this->free_(aP);
|
this->free_(aP);
|
||||||
} else {
|
} else {
|
||||||
mBegin = aP;
|
mBegin = aP;
|
||||||
mLength = aLength;
|
mLength = aLength;
|
||||||
mCapacity = aLength;
|
mTail.mCapacity = aLength;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
mReserved = aLength;
|
mTail.mReserved = aLength;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1504,9 +1547,9 @@ Vector<T, N, AP>::swap(Vector& aOther)
|
||||||
}
|
}
|
||||||
|
|
||||||
Swap(mLength, aOther.mLength);
|
Swap(mLength, aOther.mLength);
|
||||||
Swap(mCapacity, aOther.mCapacity);
|
Swap(mTail.mCapacity, aOther.mTail.mCapacity);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
Swap(mReserved, aOther.mReserved);
|
Swap(mTail.mReserved, aOther.mTail.mReserved);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -396,6 +396,49 @@ mozilla::detail::VectorTesting::testInsert()
|
||||||
MOZ_RELEASE_ASSERT(S::destructCount == 1);
|
MOZ_RELEASE_ASSERT(S::destructCount == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Declare but leave (permanently) incomplete.
|
||||||
|
struct Incomplete;
|
||||||
|
|
||||||
|
// We could even *construct* a Vector<Incomplete, 0> if we wanted. But we can't
|
||||||
|
// destruct it, so it's not worth the trouble.
|
||||||
|
static_assert(sizeof(Vector<Incomplete, 0>) > 0,
|
||||||
|
"Vector of an incomplete type will compile");
|
||||||
|
|
||||||
|
// Vector with no inline storage should occupy the absolute minimum space in
|
||||||
|
// non-debug builds. (Debug adds a laundry list of other constraints, none
|
||||||
|
// directly relevant to shipping builds, that aren't worth precisely modeling.)
|
||||||
|
#ifndef DEBUG
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct NoInlineStorageLayout
|
||||||
|
{
|
||||||
|
T* mBegin;
|
||||||
|
size_t mLength;
|
||||||
|
struct CRAndStorage {
|
||||||
|
size_t mCapacity;
|
||||||
|
} mTail;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Only one of these should be necessary, but test a few of them for good
|
||||||
|
// measure.
|
||||||
|
static_assert(sizeof(Vector<int, 0>) == sizeof(NoInlineStorageLayout<int>),
|
||||||
|
"Vector of int without inline storage shouldn't occupy dead "
|
||||||
|
"space for that absence of storage");
|
||||||
|
|
||||||
|
static_assert(sizeof(Vector<bool, 0>) == sizeof(NoInlineStorageLayout<bool>),
|
||||||
|
"Vector of bool without inline storage shouldn't occupy dead "
|
||||||
|
"space for that absence of storage");
|
||||||
|
|
||||||
|
static_assert(sizeof(Vector<S, 0>) == sizeof(NoInlineStorageLayout<S>),
|
||||||
|
"Vector of S without inline storage shouldn't occupy dead "
|
||||||
|
"space for that absence of storage");
|
||||||
|
|
||||||
|
static_assert(sizeof(Vector<Incomplete, 0>) == sizeof(NoInlineStorageLayout<Incomplete>),
|
||||||
|
"Vector of an incomplete class without inline storage shouldn't "
|
||||||
|
"occupy dead space for that absence of storage");
|
||||||
|
|
||||||
|
#endif // DEBUG
|
||||||
|
|
||||||
int
|
int
|
||||||
main()
|
main()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue