Bug 1337953 - Make nsDeque templated on pointer type r=froydnj

Differential Revision: https://phabricator.services.mozilla.com/D79629
This commit is contained in:
Chris Fronk 2020-06-25 02:39:23 +00:00
Родитель a383fd6b63
Коммит 6f84249b41
29 изменённых файлов: 445 добавлений и 361 удалений

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

@ -261,7 +261,7 @@ class EventSourceImpl final : public nsIObserver,
// EventSourceImpl on target thread but should only be used on target thread.
nsString mLastEventID;
UniquePtr<Message> mCurrentMessage;
nsDeque mMessagesToDispatch;
nsDeque<Message> mMessagesToDispatch;
ParserStatus mStatus;
mozilla::UniquePtr<mozilla::Decoder> mUnicodeDecoder;
nsString mLastFieldName;
@ -457,7 +457,7 @@ void EventSourceImpl::CloseInternal() {
}
while (mMessagesToDispatch.GetSize() != 0) {
delete static_cast<Message*>(mMessagesToDispatch.PopFront());
delete mMessagesToDispatch.PopFront();
}
SetFrozen(false);
ResetDecoder();
@ -1450,8 +1450,7 @@ void EventSourceImpl::DispatchAllMessageEvents() {
JSContext* cx = jsapi.cx();
while (mMessagesToDispatch.GetSize() > 0) {
UniquePtr<Message> message(
static_cast<Message*>(mMessagesToDispatch.PopFront()));
UniquePtr<Message> message(mMessagesToDispatch.PopFront());
if (message->mLastEventID.isSome()) {
mLastEventID.Assign(message->mLastEventID.value());

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

@ -886,7 +886,7 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
// Hash table to track coalesced mousemove events for different pointers.
nsClassHashtable<nsUint32HashKey, CoalescedMouseData> mCoalescedMouseData;
nsDeque mToBeDispatchedMouseData;
nsDeque<CoalescedMouseData> mToBeDispatchedMouseData;
CoalescedWheelData mCoalescedWheelData;
RefPtr<CoalescedMouseMoveFlusher> mCoalescedMouseEventFlusher;

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

@ -3951,28 +3951,28 @@ RefPtr<GenericPromise> MediaDecoderStateMachine::RequestDebugInfo(
return p;
}
class VideoQueueMemoryFunctor : public nsDequeFunctor {
class VideoQueueMemoryFunctor : public nsDequeFunctor<VideoData> {
public:
VideoQueueMemoryFunctor() : mSize(0) {}
MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf);
virtual void operator()(void* aObject) override {
const VideoData* v = static_cast<const VideoData*>(aObject);
virtual void operator()(VideoData* aObject) override {
const VideoData* v = aObject;
mSize += v->SizeOfIncludingThis(MallocSizeOf);
}
size_t mSize;
};
class AudioQueueMemoryFunctor : public nsDequeFunctor {
class AudioQueueMemoryFunctor : public nsDequeFunctor<AudioData> {
public:
AudioQueueMemoryFunctor() : mSize(0) {}
MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf);
virtual void operator()(void* aObject) override {
const AudioData* audioData = static_cast<const AudioData*>(aObject);
virtual void operator()(AudioData* aObject) override {
const AudioData* audioData = aObject;
mSize += audioData->SizeOfIncludingThis(MallocSizeOf);
}

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

@ -21,17 +21,17 @@ class AudioData;
// Thread and type safe wrapper around nsDeque.
template <class T>
class MediaQueueDeallocator : public nsDequeFunctor {
virtual void operator()(void* aObject) override {
RefPtr<T> releaseMe = dont_AddRef(static_cast<T*>(aObject));
class MediaQueueDeallocator : public nsDequeFunctor<T> {
virtual void operator()(T* aObject) override {
RefPtr<T> releaseMe = dont_AddRef(aObject);
}
};
template <class T>
class MediaQueue : private nsDeque {
class MediaQueue : private nsDeque<T> {
public:
MediaQueue()
: nsDeque(new MediaQueueDeallocator<T>()),
: nsDeque<T>(new MediaQueueDeallocator<T>()),
mRecursiveMutex("mediaqueue"),
mEndOfStream(false) {}
@ -39,7 +39,7 @@ class MediaQueue : private nsDeque {
inline size_t GetSize() const {
RecursiveMutexAutoLock lock(mRecursiveMutex);
return nsDeque::GetSize();
return nsDeque<T>::GetSize();
}
inline void Push(T* aItem) {
@ -52,7 +52,7 @@ class MediaQueue : private nsDeque {
T* item = aItem.take();
MOZ_DIAGNOSTIC_ASSERT(item);
MOZ_DIAGNOSTIC_ASSERT(item->GetEndTime() >= item->mTime);
nsDeque::Push(item);
nsDeque<T>::Push(item);
mPushEvent.Notify(RefPtr<T>(item));
// Pushing new data after queue has ended means that the stream is active
// again, so we should not mark it as ended.
@ -63,7 +63,7 @@ class MediaQueue : private nsDeque {
inline already_AddRefed<T> PopFront() {
RecursiveMutexAutoLock lock(mRecursiveMutex);
RefPtr<T> rv = dont_AddRef(static_cast<T*>(nsDeque::PopFront()));
RefPtr<T> rv = dont_AddRef(nsDeque<T>::PopFront());
if (rv) {
MOZ_DIAGNOSTIC_ASSERT(rv->GetEndTime() >= rv->mTime);
mPopFrontEvent.Notify(rv);
@ -73,24 +73,24 @@ class MediaQueue : private nsDeque {
inline already_AddRefed<T> PopBack() {
RecursiveMutexAutoLock lock(mRecursiveMutex);
RefPtr<T> rv = dont_AddRef(static_cast<T*>(nsDeque::Pop()));
RefPtr<T> rv = dont_AddRef(nsDeque<T>::Pop());
return rv.forget();
}
inline RefPtr<T> PeekFront() const {
RecursiveMutexAutoLock lock(mRecursiveMutex);
return static_cast<T*>(nsDeque::PeekFront());
return nsDeque<T>::PeekFront();
}
inline RefPtr<T> PeekBack() const {
RecursiveMutexAutoLock lock(mRecursiveMutex);
return static_cast<T*>(nsDeque::Peek());
return nsDeque<T>::Peek();
}
void Reset() {
RecursiveMutexAutoLock lock(mRecursiveMutex);
while (GetSize() > 0) {
RefPtr<T> x = dont_AddRef(static_cast<T*>(nsDeque::PopFront()));
RefPtr<T> x = dont_AddRef(nsDeque<T>::PopFront());
}
mEndOfStream = false;
}
@ -123,14 +123,14 @@ class MediaQueue : private nsDeque {
if (GetSize() == 0) {
return 0;
}
T* last = static_cast<T*>(nsDeque::Peek());
T* first = static_cast<T*>(nsDeque::PeekFront());
T* last = nsDeque<T>::Peek();
T* first = nsDeque<T>::PeekFront();
return (last->GetEndTime() - first->mTime).ToMicroseconds();
}
void LockedForEach(nsDequeFunctor& aFunctor) const {
void LockedForEach(nsDequeFunctor<T>& aFunctor) const {
RecursiveMutexAutoLock lock(mRecursiveMutex);
ForEach(aFunctor);
nsDeque<T>::ForEach(aFunctor);
}
// Extracts elements from the queue into aResult, in order.
@ -140,13 +140,13 @@ class MediaQueue : private nsDeque {
if (GetSize() == 0) return;
size_t i;
for (i = GetSize() - 1; i > 0; --i) {
T* v = static_cast<T*>(ObjectAt(i));
T* v = nsDeque<T>::ObjectAt(i);
if (v->GetEndTime().ToMicroseconds() < aTime) break;
}
// Elements less than i have a end time before aTime. It's also possible
// that the element at i has a end time before aTime, but that's OK.
for (; i < GetSize(); ++i) {
RefPtr<T> elem = static_cast<T*>(ObjectAt(static_cast<size_t>(i)));
RefPtr<T> elem = nsDeque<T>::ObjectAt(i);
aResult->AppendElement(elem);
}
}
@ -159,7 +159,7 @@ class MediaQueue : private nsDeque {
void GetFirstElements(uint32_t aMaxElements, nsTArray<RefPtr<T>>* aResult) {
RecursiveMutexAutoLock lock(mRecursiveMutex);
for (size_t i = 0; i < aMaxElements && i < GetSize(); ++i) {
*aResult->AppendElement() = static_cast<T*>(ObjectAt(i));
*aResult->AppendElement() = nsDeque<T>::ObjectAt(i);
}
}
@ -169,7 +169,7 @@ class MediaQueue : private nsDeque {
RecursiveMutexAutoLock lock(mRecursiveMutex);
uint32_t frames = 0;
for (size_t i = 0; i < GetSize(); ++i) {
T* v = static_cast<T*>(ObjectAt(i));
T* v = nsDeque<T>::ObjectAt(i);
frames += v->Frames();
}
return frames;

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

@ -284,7 +284,7 @@ TEST(MultiWriterQueue, MultiWriterMultiReader)
// Single-threaded use only.
struct DequeWrapperST {
nsDeque mDQ;
nsDeque<void> mDQ;
bool Push(int i) {
mDQ.PushFront(reinterpret_cast<void*>(static_cast<uintptr_t>(i)));

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

@ -11,14 +11,13 @@ using mozilla::AudioData;
using mozilla::AudioDataValue;
using mozilla::MediaQueue;
class MemoryFunctor : public nsDequeFunctor {
class MemoryFunctor : public nsDequeFunctor<AudioData> {
public:
MemoryFunctor() : mSize(0) {}
MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf);
void operator()(void* aObject) override {
const AudioData* audioData = static_cast<const AudioData*>(aObject);
mSize += audioData->SizeOfIncludingThis(MallocSizeOf);
void operator()(AudioData* aObject) override {
mSize += aObject->SizeOfIncludingThis(MallocSizeOf);
}
size_t mSize;

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

@ -31,14 +31,14 @@ size_t ResourceItem::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
return aMallocSizeOf(this);
}
class ResourceQueueDeallocator : public nsDequeFunctor {
void operator()(void* aObject) override {
delete static_cast<ResourceItem*>(aObject);
}
class ResourceQueueDeallocator : public nsDequeFunctor<ResourceItem> {
void operator()(ResourceItem* aObject) override { delete aObject; }
};
ResourceQueue::ResourceQueue()
: nsDeque(new ResourceQueueDeallocator()), mLogicalLength(0), mOffset(0) {}
: nsDeque<ResourceItem>(new ResourceQueueDeallocator()),
mLogicalLength(0),
mOffset(0) {}
uint64_t ResourceQueue::GetOffset() { return mOffset; }
@ -125,7 +125,7 @@ uint32_t ResourceQueue::EvictAll() {
size_t ResourceQueue::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
// Calculate the size of the internal deque.
size_t size = nsDeque::SizeOfExcludingThis(aMallocSizeOf);
size_t size = nsDeque<ResourceItem>::SizeOfExcludingThis(aMallocSizeOf);
// Sum the ResourceItems. The ResourceItems's MediaSpans may share the
// same underlying MediaByteBuffers, so we need to de-dupe the buffers
@ -194,7 +194,7 @@ uint32_t ResourceQueue::GetAtOffset(uint64_t aOffset,
}
ResourceItem* ResourceQueue::PopFront() {
return static_cast<ResourceItem*>(nsDeque::PopFront());
return nsDeque<ResourceItem>::PopFront();
}
#undef SBR_DEBUG

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

@ -32,7 +32,7 @@ struct ResourceItem {
uint64_t mOffset;
};
class ResourceQueue : private nsDeque {
class ResourceQueue : private nsDeque<ResourceItem> {
public:
ResourceQueue();

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

@ -62,9 +62,9 @@ struct OggPacketDeletePolicy {
using OggPacketPtr = UniquePtr<ogg_packet, OggPacketDeletePolicy>;
// Deallocates a packet, used in OggPacketQueue below.
class OggPacketDeallocator : public nsDequeFunctor {
virtual void operator()(void* aPacket) override {
OggPacketDeletePolicy()(static_cast<ogg_packet*>(aPacket));
class OggPacketDeallocator : public nsDequeFunctor<ogg_packet> {
virtual void operator()(ogg_packet* aPacket) override {
OggPacketDeletePolicy()(aPacket);
}
};
@ -78,29 +78,25 @@ class OggPacketDeallocator : public nsDequeFunctor {
// frames/samples, reducing the amount of frames/samples we must decode to
// determine start-time at a particular offset, and gives us finer control
// over memory usage.
class OggPacketQueue : private nsDeque {
class OggPacketQueue : private nsDeque<ogg_packet> {
public:
OggPacketQueue() : nsDeque(new OggPacketDeallocator()) {}
~OggPacketQueue() { Erase(); }
bool IsEmpty() { return nsDeque::GetSize() == 0; }
bool IsEmpty() { return nsDeque<ogg_packet>::GetSize() == 0; }
void Append(OggPacketPtr aPacket);
OggPacketPtr PopFront() {
return OggPacketPtr(static_cast<ogg_packet*>(nsDeque::PopFront()));
}
ogg_packet* PeekFront() {
return static_cast<ogg_packet*>(nsDeque::PeekFront());
}
OggPacketPtr Pop() {
return OggPacketPtr(static_cast<ogg_packet*>(nsDeque::Pop()));
return OggPacketPtr(nsDeque<ogg_packet>::PopFront());
}
ogg_packet* PeekFront() { return nsDeque<ogg_packet>::PeekFront(); }
OggPacketPtr Pop() { return OggPacketPtr(nsDeque<ogg_packet>::Pop()); }
ogg_packet* operator[](size_t aIndex) const {
return static_cast<ogg_packet*>(nsDeque::ObjectAt(aIndex));
return nsDeque<ogg_packet>::ObjectAt(aIndex);
}
size_t Length() const { return nsDeque::GetSize(); }
size_t Length() const { return nsDeque<ogg_packet>::GetSize(); }
void PushFront(OggPacketPtr aPacket) {
nsDeque::PushFront(aPacket.release());
nsDeque<ogg_packet>::PushFront(aPacket.release());
}
void Erase() { nsDeque::Erase(); }
void Erase() { nsDeque<ogg_packet>::Erase(); }
};
// Encapsulates the data required for decoding an ogg bitstream and for

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

@ -14,15 +14,16 @@
namespace mozilla {
class TransactionStackDeallocator final : public nsDequeFunctor {
virtual void operator()(void* aObject) override {
RefPtr<TransactionItem> releaseMe =
dont_AddRef(static_cast<TransactionItem*>(aObject));
class TransactionStackDeallocator final
: public nsDequeFunctor<TransactionItem> {
virtual void operator()(TransactionItem* aObject) override {
RefPtr<TransactionItem> releaseMe = dont_AddRef(aObject);
}
};
TransactionStack::TransactionStack(Type aType)
: nsDeque(new TransactionStackDeallocator()), mType(aType) {}
: nsDeque<TransactionItem>(new TransactionStackDeallocator()),
mType(aType) {}
TransactionStack::~TransactionStack() { Clear(); }
@ -42,33 +43,31 @@ void TransactionStack::Push(
return;
}
nsDeque::Push(transactionItem.forget().take());
nsDeque<TransactionItem>::Push(transactionItem.forget().take());
}
already_AddRefed<TransactionItem> TransactionStack::Pop() {
RefPtr<TransactionItem> item =
dont_AddRef(static_cast<TransactionItem*>(nsDeque::Pop()));
RefPtr<TransactionItem> item = dont_AddRef(nsDeque<TransactionItem>::Pop());
return item.forget();
}
already_AddRefed<TransactionItem> TransactionStack::PopBottom() {
RefPtr<TransactionItem> item =
dont_AddRef(static_cast<TransactionItem*>(nsDeque::PopFront()));
dont_AddRef(nsDeque<TransactionItem>::PopFront());
return item.forget();
}
already_AddRefed<TransactionItem> TransactionStack::Peek() {
RefPtr<TransactionItem> item = static_cast<TransactionItem*>(nsDeque::Peek());
RefPtr<TransactionItem> item = nsDeque<TransactionItem>::Peek();
return item.forget();
}
already_AddRefed<TransactionItem> TransactionStack::GetItemAt(
size_t aIndex) const {
if (NS_WARN_IF(aIndex >= nsDeque::GetSize())) {
if (NS_WARN_IF(aIndex >= nsDeque<TransactionItem>::GetSize())) {
return nullptr;
}
RefPtr<TransactionItem> item =
static_cast<TransactionItem*>(nsDeque::ObjectAt(aIndex));
RefPtr<TransactionItem> item = nsDeque<TransactionItem>::ObjectAt(aIndex);
return item.forget();
}
@ -81,7 +80,7 @@ void TransactionStack::Clear() {
void TransactionStack::DoTraverse(nsCycleCollectionTraversalCallback& cb) {
size_t size = GetSize();
for (size_t i = 0; i < size; ++i) {
TransactionItem* item = static_cast<TransactionItem*>(nsDeque::ObjectAt(i));
TransactionItem* item = nsDeque<TransactionItem>::ObjectAt(i);
if (item) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "transaction stack mDeque[i]");
cb.NoteNativeChild(item,

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

@ -15,7 +15,7 @@ namespace mozilla {
class TransactionItem;
class TransactionStack : private nsDeque {
class TransactionStack : private nsDeque<TransactionItem> {
public:
enum Type { FOR_UNDO, FOR_REDO };

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

@ -104,8 +104,7 @@ EventTokenBucket::~EventTokenBucket() {
// Complete any queued events to prevent hangs
while (mEvents.GetSize()) {
RefPtr<TokenBucketCancelable> cancelable =
dont_AddRef(static_cast<TokenBucketCancelable*>(mEvents.PopFront()));
RefPtr<TokenBucketCancelable> cancelable = dont_AddRef(mEvents.PopFront());
cancelable->Fire();
}
}
@ -197,8 +196,7 @@ void EventTokenBucket::Stop() {
// Complete any queued events to prevent hangs
while (mEvents.GetSize()) {
RefPtr<TokenBucketCancelable> cancelable =
dont_AddRef(static_cast<TokenBucketCancelable*>(mEvents.PopFront()));
RefPtr<TokenBucketCancelable> cancelable = dont_AddRef(mEvents.PopFront());
cancelable->Fire();
}
}
@ -244,8 +242,7 @@ void EventTokenBucket::DispatchEvents() {
if (mPaused || mStopped) return;
while (mEvents.GetSize() && mUnitCost <= mCredit) {
RefPtr<TokenBucketCancelable> cancelable =
dont_AddRef(static_cast<TokenBucketCancelable*>(mEvents.PopFront()));
RefPtr<TokenBucketCancelable> cancelable = dont_AddRef(mEvents.PopFront());
if (cancelable->mEvent) {
SOCKET_LOG(
("EventTokenBucket::DispachEvents [%p] "

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

@ -121,7 +121,7 @@ class EventTokenBucket : public nsITimerCallback,
bool mPaused;
bool mStopped;
nsDeque mEvents;
nsDeque<TokenBucketCancelable> mEvents;
bool mTimerArmed;
TimeStamp mLastUpdate;

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

@ -43,7 +43,7 @@ static nsDataHashtable<nsPtrHashKey<PRFileDesc>, NetworkFuzzingBuffer*>
gConnectedNetworkFuzzingBuffers;
// This holds all buffers for connections we can still open.
static nsDeque gNetworkFuzzingBuffers;
static nsDeque<NetworkFuzzingBuffer> gNetworkFuzzingBuffers;
// This is `true` once all connections are closed and either there are
// no buffers left to be used or all remaining buffers are marked optional.
@ -143,8 +143,7 @@ static PRStatus FuzzyConnect(PRFileDesc* fd, const PRNetAddr* addr,
MutexAutoLock lock(gConnRecvMutex);
NetworkFuzzingBuffer* buf =
(NetworkFuzzingBuffer*)gNetworkFuzzingBuffers.PopFront();
NetworkFuzzingBuffer* buf = gNetworkFuzzingBuffers.PopFront();
if (!buf) {
FUZZING_LOG(("[FuzzyConnect] Denying additional connection."));
return PR_FAILURE;
@ -266,8 +265,7 @@ static PRStatus FuzzyClose(PRFileDesc* fd) {
// unused network buffers that were not marked as optional.
bool haveRemainingUnusedBuffers = false;
for (size_t i = 0; i < gNetworkFuzzingBuffers.GetSize(); ++i) {
NetworkFuzzingBuffer* buf = static_cast<NetworkFuzzingBuffer*>(
gNetworkFuzzingBuffers.ObjectAt(i));
NetworkFuzzingBuffer* buf = gNetworkFuzzingBuffers.ObjectAt(i);
if (!buf->allowUnused) {
haveRemainingUnusedBuffers = true;

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

@ -24,7 +24,7 @@
namespace mozilla {
namespace net {
static nsDeque* gStaticHeaders = nullptr;
static nsDeque<nvPair>* gStaticHeaders = nullptr;
class HpackStaticTableReporter final : public nsIMemoryReporter {
public:
@ -104,7 +104,7 @@ static void AddStaticElement(const nsCString& name) {
static void InitializeStaticHeaders() {
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
if (!gStaticHeaders) {
gStaticHeaders = new nsDeque();
gStaticHeaders = new nsDeque<nvPair>();
gStaticReporter = new HpackStaticTableReporter();
RegisterStrongMemoryReporter(gStaticReporter);
AddStaticElement(NS_LITERAL_CSTRING(":authority"));
@ -198,7 +198,7 @@ void nvFIFO::AddElement(const nsCString& name) {
}
void nvFIFO::RemoveElement() {
nvPair* pair = static_cast<nvPair*>(mTable.Pop());
nvPair* pair = mTable.Pop();
if (pair) {
mByteCount -= pair->Size();
delete pair;
@ -217,7 +217,9 @@ size_t nvFIFO::StaticLength() const { return gStaticHeaders->GetSize(); }
void nvFIFO::Clear() {
mByteCount = 0;
while (mTable.GetSize()) delete static_cast<nvPair*>(mTable.Pop());
while (mTable.GetSize()) {
delete mTable.Pop();
}
}
const nvPair* nvFIFO::operator[](size_t index) const {
@ -229,10 +231,9 @@ const nvPair* nvFIFO::operator[](size_t index) const {
return nullptr;
}
if (index >= gStaticHeaders->GetSize()) {
return static_cast<nvPair*>(
mTable.ObjectAt(index - gStaticHeaders->GetSize()));
return mTable.ObjectAt(index - gStaticHeaders->GetSize());
}
return static_cast<nvPair*>(gStaticHeaders->ObjectAt(index));
return gStaticHeaders->ObjectAt(index);
}
Http2BaseCompressor::Http2BaseCompressor()

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

@ -50,7 +50,7 @@ class nvFIFO {
private:
uint32_t mByteCount;
nsDeque mTable;
nsDeque<nvPair> mTable;
};
class HpackDynamicTableReporter;

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

@ -587,8 +587,7 @@ void Http2Session::QueueStream(Http2Stream* stream) {
#ifdef DEBUG
int32_t qsize = mQueuedStreams.GetSize();
for (int32_t i = 0; i < qsize; i++) {
Http2Stream* qStream =
static_cast<Http2Stream*>(mQueuedStreams.ObjectAt(i));
Http2Stream* qStream = mQueuedStreams.ObjectAt(i);
MOZ_ASSERT(qStream != stream);
MOZ_ASSERT(qStream->Queued());
}
@ -602,8 +601,7 @@ void Http2Session::ProcessPending() {
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
Http2Stream* stream;
while (RoomForMoreConcurrent() &&
(stream = static_cast<Http2Stream*>(mQueuedStreams.PopFront()))) {
while (RoomForMoreConcurrent() && (stream = mQueuedStreams.PopFront())) {
LOG3(("Http2Session::ProcessPending %p stream %p woken from queue.", this,
stream));
MOZ_ASSERT(!stream->CountAsActive());
@ -1270,10 +1268,11 @@ void Http2Session::CleanupStream(uint32_t aID, nsresult aResult,
CleanupStream(stream, aResult, aResetCode);
}
static void RemoveStreamFromQueue(Http2Stream* aStream, nsDeque& queue) {
static void RemoveStreamFromQueue(Http2Stream* aStream,
nsDeque<Http2Stream>& queue) {
size_t size = queue.GetSize();
for (size_t count = 0; count < size; ++count) {
Http2Stream* stream = static_cast<Http2Stream*>(queue.PopFront());
Http2Stream* stream = queue.PopFront();
if (stream != aStream) queue.Push(stream);
}
}
@ -2179,8 +2178,7 @@ nsresult Http2Session::RecvGoAway(Http2Session* self) {
// are not covered by the last-good id.
size = self->mQueuedStreams.GetSize();
for (size_t count = 0; count < size; ++count) {
Http2Stream* stream =
static_cast<Http2Stream*>(self->mQueuedStreams.PopFront());
Http2Stream* stream = self->mQueuedStreams.PopFront();
MOZ_ASSERT(stream->Queued());
stream->SetQueued(false);
if (self->mPeerGoAwayReason == HTTP_1_1_REQUIRED) {
@ -2763,7 +2761,7 @@ nsresult Http2Session::ReadSegmentsAgain(nsAHttpSegmentReader* reader,
LOG3(("Http2Session::ReadSegments %p", this));
Http2Stream* stream = static_cast<Http2Stream*>(mReadyForWrite.PopFront());
Http2Stream* stream = mReadyForWrite.PopFront();
if (!stream) {
LOG3(("Http2Session %p could not identify a stream to write; suspending.",
this));
@ -3002,8 +3000,7 @@ nsresult Http2Session::WriteSegmentsAgain(nsAHttpSegmentWriter* writer,
// If there are http transactions attached to a push stream with filled
// buffers trigger that data pump here. This only reads from buffers (not the
// network) so mDownstreamState doesn't matter.
Http2Stream* pushConnectedStream =
static_cast<Http2Stream*>(mPushesReadyForRead.PopFront());
Http2Stream* pushConnectedStream = mPushesReadyForRead.PopFront();
if (pushConnectedStream) {
return ProcessConnectedPush(pushConnectedStream, writer, count,
countWritten);
@ -3011,8 +3008,7 @@ nsresult Http2Session::WriteSegmentsAgain(nsAHttpSegmentWriter* writer,
// feed gecko channels that previously stopped consuming data
// only take data from stored buffers
Http2Stream* slowConsumer =
static_cast<Http2Stream*>(mSlowConsumersReadyForRead.PopFront());
Http2Stream* slowConsumer = mSlowConsumersReadyForRead.PopFront();
if (slowConsumer) {
internalStateType savedState = mDownstreamState;
mDownstreamState = NOT_USING_NETWORK;

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

@ -381,10 +381,10 @@ class Http2Session final : public ASpdySession,
nsClassHashtable<nsPtrHashKey<nsAHttpTransaction>, Http2Stream>
mStreamTransactionHash;
nsDeque mReadyForWrite;
nsDeque mQueuedStreams;
nsDeque mPushesReadyForRead;
nsDeque mSlowConsumersReadyForRead;
nsDeque<Http2Stream> mReadyForWrite;
nsDeque<Http2Stream> mQueuedStreams;
nsDeque<Http2Stream> mPushesReadyForRead;
nsDeque<Http2Stream> mSlowConsumersReadyForRead;
nsTArray<Http2PushedStream*> mPushedStreams;
// Compression contexts for header transport.
@ -527,7 +527,7 @@ class Http2Session final : public ASpdySession,
bool mPreviousUsed; // true when backup is used
// used as a temporary buffer while enumerating the stream hash during GoAway
nsDeque mGoAwayStreamsToRestart;
nsDeque<Http2Stream> mGoAwayStreamsToRestart;
// Each session gets a unique serial number because the push cache is
// correlated by the load group and the serial number can be used as part of

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

@ -571,7 +571,7 @@ void Http3Session::ProcessPending() {
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
Http3Stream* stream;
while ((stream = static_cast<Http3Stream*>(mQueuedStreams.PopFront()))) {
while ((stream = mQueuedStreams.PopFront())) {
LOG3(("Http3Session::ProcessPending %p stream %p woken from queue.", this,
stream));
MOZ_ASSERT(stream->Queued());
@ -583,10 +583,11 @@ void Http3Session::ProcessPending() {
}
}
static void RemoveStreamFromQueue(Http3Stream* aStream, nsDeque& queue) {
static void RemoveStreamFromQueue(Http3Stream* aStream,
nsDeque<Http3Stream>& queue) {
size_t size = queue.GetSize();
for (size_t count = 0; count < size; ++count) {
Http3Stream* stream = static_cast<Http3Stream*>(queue.PopFront());
Http3Stream* stream = queue.PopFront();
if (stream != aStream) {
queue.Push(stream);
}
@ -759,7 +760,7 @@ nsresult Http3Session::ReadSegmentsAgain(nsAHttpSegmentReader* reader,
while (
(mState ==
CONNECTED) && // Do not send transaction data untill we are connected.
(stream = static_cast<Http3Stream*>(mReadyForWrite.PopFront()))) {
(stream = mReadyForWrite.PopFront())) {
LOG(
("Http3Session::ReadSegmentsAgain call ReadSegments from stream=%p "
"[this=%p]",

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

@ -143,10 +143,10 @@ class Http3Session final : public nsAHttpTransaction,
nsRefPtrHashtable<nsPtrHashKey<nsAHttpTransaction>, Http3Stream>
mStreamTransactionHash;
nsDeque mReadyForWrite;
nsDeque<Http3Stream> mReadyForWrite;
nsTArray<uint64_t> mReadyForWriteButBlocked;
nsTArray<RefPtr<Http3Stream>> mSlowConsumersReadyForRead;
nsDeque mQueuedStreams;
nsDeque<Http3Stream> mQueuedStreams;
enum State { INITIALIZING, CONNECTED, CLOSING, CLOSED } mState;

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

@ -1162,12 +1162,15 @@ WebSocketChannel::~WebSocketChannel() {
free(mDynamicOutput);
delete mCurrentOut;
while ((mCurrentOut = (OutboundMessage*)mOutgoingPingMessages.PopFront()))
while ((mCurrentOut = mOutgoingPingMessages.PopFront())) {
delete mCurrentOut;
while ((mCurrentOut = (OutboundMessage*)mOutgoingPongMessages.PopFront()))
}
while ((mCurrentOut = mOutgoingPongMessages.PopFront())) {
delete mCurrentOut;
while ((mCurrentOut = (OutboundMessage*)mOutgoingMessages.PopFront()))
}
while ((mCurrentOut = mOutgoingMessages.PopFront())) {
delete mCurrentOut;
}
mListenerMT = nullptr;
@ -1885,7 +1888,7 @@ void WebSocketChannel::GeneratePong(uint8_t* payload, uint32_t len) {
new OutboundMessage(kMsgTypePong, buf));
}
void WebSocketChannel::EnqueueOutgoingMessage(nsDeque& aQueue,
void WebSocketChannel::EnqueueOutgoingMessage(nsDeque<OutboundMessage>& aQueue,
OutboundMessage* aMsg) {
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
@ -1921,16 +1924,16 @@ void WebSocketChannel::PrimeNewOutgoingMessage() {
nsresult rv = NS_OK;
mCurrentOut = (OutboundMessage*)mOutgoingPongMessages.PopFront();
mCurrentOut = mOutgoingPongMessages.PopFront();
if (mCurrentOut) {
MOZ_ASSERT(mCurrentOut->GetMsgType() == kMsgTypePong, "Not pong message!");
} else {
mCurrentOut = (OutboundMessage*)mOutgoingPingMessages.PopFront();
mCurrentOut = mOutgoingPingMessages.PopFront();
if (mCurrentOut)
MOZ_ASSERT(mCurrentOut->GetMsgType() == kMsgTypePing,
"Not ping message!");
else
mCurrentOut = (OutboundMessage*)mOutgoingMessages.PopFront();
mCurrentOut = mOutgoingMessages.PopFront();
}
if (!mCurrentOut) return;

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

@ -140,7 +140,8 @@ class WebSocketChannel : public BaseWebSocketChannel,
uint32_t length,
nsIInputStream* aStream = nullptr);
void EnqueueOutgoingMessage(nsDeque& aQueue, OutboundMessage* aMsg);
void EnqueueOutgoingMessage(nsDeque<OutboundMessage>& aQueue,
OutboundMessage* aMsg);
void PrimeNewOutgoingMessage();
void DeleteCurrentOutGoingMessage();
@ -284,9 +285,9 @@ class WebSocketChannel : public BaseWebSocketChannel,
OutboundMessage* mCurrentOut;
uint32_t mCurrentOutSent;
nsDeque mOutgoingMessages;
nsDeque mOutgoingPingMessages;
nsDeque mOutgoingPongMessages;
nsDeque<OutboundMessage> mOutgoingMessages;
nsDeque<OutboundMessage> mOutgoingPingMessages;
nsDeque<OutboundMessage> mOutgoingPongMessages;
uint32_t mHdrOutToSend;
uint8_t* mHdrOut;
uint8_t mOutHeader[kCopyBreak + 16];

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

@ -904,18 +904,16 @@ void DataChannelConnection::ProcessQueuedOpens() {
// Can't copy nsDeque's. Move into temp array since any that fail will
// go back to mPending
nsDeque temp;
nsDeque<DataChannel> temp;
DataChannel* temp_channel; // really already_AddRefed<>
while (nullptr !=
(temp_channel = static_cast<DataChannel*>(mPending.PopFront()))) {
temp.Push(static_cast<void*>(temp_channel));
while (nullptr != (temp_channel = mPending.PopFront())) {
temp.Push(temp_channel);
}
RefPtr<DataChannel> channel;
// All these entries have an AddRef(); make that explicit now via the
// dont_AddRef()
while (nullptr !=
(channel = dont_AddRef(static_cast<DataChannel*>(temp.PopFront())))) {
while (nullptr != (channel = dont_AddRef(temp.PopFront()))) {
if (channel->mFlags & DATA_CHANNEL_FLAGS_FINISH_OPEN) {
DC_DEBUG(("Processing queued open for %p (%u)", channel.get(),
channel->mStream));
@ -3057,8 +3055,7 @@ void DataChannelConnection::CloseAll() {
// Clean up any pending opens for channels
RefPtr<DataChannel> channel;
while (nullptr != (channel = dont_AddRef(
static_cast<DataChannel*>(mPending.PopFront())))) {
while (nullptr != (channel = dont_AddRef(mPending.PopFront()))) {
DC_DEBUG(("closing pending channel %p, stream %u", channel.get(),
channel->mStream));
channel->Close(); // also releases the ref on each iteration

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

@ -360,7 +360,7 @@ class DataChannelConnection final : public net::NeckoTargetHolder
Channels mChannels;
// STS only
uint32_t mCurrentStream = 0;
nsDeque mPending; // Holds addref'ed DataChannel's -- careful!
nsDeque<DataChannel> mPending; // Holds addref'ed DataChannel's -- careful!
// STS and main
size_t mNegotiatedIdLimit = 0; // GUARDED_BY(mConnection->mLock)
uint8_t mPendingType = PENDING_NONE;

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

@ -172,12 +172,9 @@ typedef nsClassHashtable<nsCStringHashKey, BFSTableData> BFSHashTable;
// nsObjectHashtable enumerator functions.
class CStreamConvDeallocator : public nsDequeFunctor {
class CStreamConvDeallocator : public nsDequeFunctor<nsCString> {
public:
void operator()(void* anObject) override {
nsCString* string = (nsCString*)anObject;
delete string;
}
void operator()(nsCString* anObject) override { delete anObject; }
};
// walks the graph using a breadth-first-search algorithm which generates a

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

@ -1221,9 +1221,9 @@ class GraphWalker {
private:
Visitor mVisitor;
void DoWalk(nsDeque& aQueue);
void DoWalk(nsDeque<PtrInfo>& aQueue);
void CheckedPush(nsDeque& aQueue, PtrInfo* aPi) {
void CheckedPush(nsDeque<PtrInfo>& aQueue, PtrInfo* aPi) {
if (!aPi) {
MOZ_CRASH();
}
@ -1280,14 +1280,14 @@ static void ToParticipant(void* aParti, nsCycleCollectionParticipant** aCp) {
template <class Visitor>
MOZ_NEVER_INLINE void GraphWalker<Visitor>::Walk(PtrInfo* aPi) {
nsDeque queue;
nsDeque<PtrInfo> queue;
CheckedPush(queue, aPi);
DoWalk(queue);
}
template <class Visitor>
MOZ_NEVER_INLINE void GraphWalker<Visitor>::WalkFromRoots(CCGraph& aGraph) {
nsDeque queue;
nsDeque<PtrInfo> queue;
NodePool::Enumerator etor(aGraph.mNodes);
for (uint32_t i = 0; i < aGraph.mRootCount; ++i) {
CheckedPush(queue, etor.GetNext());
@ -1296,11 +1296,11 @@ MOZ_NEVER_INLINE void GraphWalker<Visitor>::WalkFromRoots(CCGraph& aGraph) {
}
template <class Visitor>
MOZ_NEVER_INLINE void GraphWalker<Visitor>::DoWalk(nsDeque& aQueue) {
MOZ_NEVER_INLINE void GraphWalker<Visitor>::DoWalk(nsDeque<PtrInfo>& aQueue) {
// Use a aQueue to match the breadth-first traversal used when we
// built the graph, for hopefully-better locality.
while (aQueue.GetSize() > 0) {
PtrInfo* pi = static_cast<PtrInfo*>(aQueue.PopFront());
PtrInfo* pi = aQueue.PopFront();
if (pi->WasTraversed() && mVisitor.ShouldVisitNode(pi)) {
mVisitor.VisitNode(pi);

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

@ -12,13 +12,15 @@
#define modulus(x, y) ((x) % (y))
namespace mozilla {
namespace detail {
/**
* Standard constructor
* @param deallocator, called by Erase and ~nsDeque
* @param deallocator, called by Erase and ~nsDequeBase
*/
nsDeque::nsDeque(nsDequeFunctor* aDeallocator) {
MOZ_COUNT_CTOR(nsDeque);
mDeallocator = aDeallocator;
nsDequeBase::nsDequeBase() {
MOZ_COUNT_CTOR(nsDequeBase);
mOrigin = mSize = 0;
mData = mBuffer; // don't allocate space until you must
mCapacity = sizeof(mBuffer) / sizeof(mBuffer[0]);
@ -28,49 +30,29 @@ nsDeque::nsDeque(nsDequeFunctor* aDeallocator) {
/**
* Destructor
*/
nsDeque::~nsDeque() {
MOZ_COUNT_DTOR(nsDeque);
nsDequeBase::~nsDequeBase() {
MOZ_COUNT_DTOR(nsDequeBase);
Erase();
if (mData && mData != mBuffer) {
free(mData);
}
mData = 0;
SetDeallocator(0);
mData = nullptr;
}
size_t nsDeque::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
size_t nsDequeBase::SizeOfExcludingThis(
mozilla::MallocSizeOf aMallocSizeOf) const {
size_t size = 0;
if (mData != mBuffer) {
size += aMallocSizeOf(mData);
}
if (mDeallocator) {
size += aMallocSizeOf(mDeallocator);
}
return size;
}
size_t nsDeque::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
}
/**
* Set the functor to be called by Erase()
* The deque owns the functor.
*
* @param aDeallocator functor object for use by Erase()
*/
void nsDeque::SetDeallocator(nsDequeFunctor* aDeallocator) {
delete mDeallocator;
mDeallocator = aDeallocator;
}
/**
* Remove all items from container without destroying them.
*/
void nsDeque::Empty() {
void nsDequeBase::Empty() {
if (mSize && mData) {
memset(mData, 0, mCapacity * sizeof(*mData));
}
@ -78,16 +60,6 @@ void nsDeque::Empty() {
mOrigin = 0;
}
/**
* Remove and delete all items from container
*/
void nsDeque::Erase() {
if (mDeallocator && mSize) {
ForEach(*mDeallocator);
}
Empty();
}
/**
* This method quadruples the size of the deque
* Elements in the deque are resequenced so that elements
@ -95,7 +67,7 @@ void nsDeque::Erase() {
*
* @return whether growing succeeded
*/
bool nsDeque::GrowCapacity() {
bool nsDequeBase::GrowCapacity() {
mozilla::CheckedInt<size_t> newCapacity = mCapacity;
newCapacity *= 4;
@ -144,7 +116,7 @@ bool nsDeque::GrowCapacity() {
*
* @param aItem: new item to be added to deque
*/
bool nsDeque::Push(void* aItem, const fallible_t&) {
bool nsDequeBase::Push(void* aItem, const fallible_t&) {
if (mSize == mCapacity && !GrowCapacity()) {
return false;
}
@ -185,7 +157,7 @@ bool nsDeque::Push(void* aItem, const fallible_t&) {
* --
* @param aItem: new item to be added to deque
*/
bool nsDeque::PushFront(void* aItem, const fallible_t&) {
bool nsDequeBase::PushFront(void* aItem, const fallible_t&) {
if (mOrigin == 0) {
mOrigin = mCapacity - 1;
} else {
@ -209,13 +181,13 @@ bool nsDeque::PushFront(void* aItem, const fallible_t&) {
*
* @return ptr to last item in container
*/
void* nsDeque::Pop() {
void* result = 0;
void* nsDequeBase::Pop() {
void* result = nullptr;
if (mSize > 0) {
--mSize;
size_t offset = modulus(mSize + mOrigin, mCapacity);
result = mData[offset];
mData[offset] = 0;
mData[offset] = nullptr;
if (!mSize) {
mOrigin = 0;
}
@ -229,12 +201,12 @@ void* nsDeque::Pop() {
*
* @return last item in container
*/
void* nsDeque::PopFront() {
void* result = 0;
void* nsDequeBase::PopFront() {
void* result = nullptr;
if (mSize > 0) {
NS_ASSERTION(mOrigin < mCapacity, "Error: Bad origin");
result = mData[mOrigin];
mData[mOrigin++] = 0; // zero it out for debugging purposes.
mData[mOrigin++] = nullptr; // zero it out for debugging purposes.
mSize--;
// Cycle around if we pop off the end
// and reset origin if when we pop the last element
@ -251,8 +223,8 @@ void* nsDeque::PopFront() {
*
* @return last item in container
*/
void* nsDeque::Peek() const {
void* result = 0;
void* nsDequeBase::Peek() const {
void* result = nullptr;
if (mSize > 0) {
result = mData[modulus(mSize - 1 + mOrigin, mCapacity)];
}
@ -265,8 +237,8 @@ void* nsDeque::Peek() const {
*
* @return last item in container
*/
void* nsDeque::PeekFront() const {
void* result = 0;
void* nsDequeBase::PeekFront() const {
void* result = nullptr;
if (mSize > 0) {
result = mData[mOrigin];
}
@ -282,24 +254,12 @@ void* nsDeque::PeekFront() const {
* @param aIndex : 0 relative offset of item you want
* @return void* or null
*/
void* nsDeque::ObjectAt(size_t aIndex) const {
void* result = 0;
void* nsDequeBase::ObjectAt(size_t aIndex) const {
void* result = nullptr;
if (aIndex < mSize) {
result = mData[modulus(mOrigin + aIndex, mCapacity)];
}
return result;
}
/**
* Call this method when you want to iterate all the
* members of the container, passing a functor along
* to call your code.
*
* @param aFunctor object to call for each member
* @return *this
*/
void nsDeque::ForEach(nsDequeFunctor& aFunctor) const {
for (size_t i = 0; i < mSize; ++i) {
aFunctor(ObjectAt(i));
}
}
} // namespace detail
} // namespace mozilla

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

@ -8,7 +8,7 @@
* MODULE NOTES:
*
* The Deque is a very small, very efficient container object
* than can hold items of type void*, offering the following features:
* than can hold items of type T*, offering the following features:
* - Its interface supports pushing, popping, and peeking of items at the back
* or front, and retrieval from any position.
* - It can iterate over items via a ForEach method, range-for, or an iterator
@ -31,21 +31,9 @@
#include "mozilla/fallible.h"
#include "mozilla/MemoryReporting.h"
/**
* The nsDequeFunctor class is used when you want to create
* callbacks between the deque and your generic code.
* Use these objects in a call to ForEach(), and as custom deallocators.
*/
class nsDequeFunctor {
public:
virtual void operator()(void* aObject) = 0;
virtual ~nsDequeFunctor() = default;
};
/******************************************************
* Here comes the nsDeque class itself...
******************************************************/
namespace mozilla {
namespace detail {
/**
* The deque (double-ended queue) class is a common container type,
* whose behavior mimics a line in your favorite checkout stand.
@ -53,27 +41,11 @@ class nsDequeFunctor {
* A deque allows insertion and removal at both ends of
* the container.
*
* The deque stores pointers to items.
* nsDequeBase implements the untyped deque data structure while
* nsDeque provides the typed implementation and iterators.
*/
class nsDeque {
typedef mozilla::fallible_t fallible_t;
class nsDequeBase {
public:
/**
* Constructs an empty deque.
*
* @param aDeallocator Optional deallocator functor that will be called from
* Erase() and the destructor on any remaining item.
* The deallocator is owned by the deque and will be
* deleted at destruction time.
*/
explicit nsDeque(nsDequeFunctor* aDeallocator = nullptr);
/**
* Deque destructor. Erases all items, deletes the deallocator.
*/
~nsDeque();
/**
* Returns the number of items currently stored in
* this deque.
@ -82,16 +54,23 @@ class nsDeque {
*/
inline size_t GetSize() const { return mSize; }
protected:
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
/**
* Appends new member at the end of the deque.
* Constructs an empty deque.
*
* @param aItem item to store in deque
* @param aDeallocator Optional deallocator functor that will be called from
* Erase() and the destructor on any remaining item.
* The deallocator is owned by the deque and will be
* deleted at destruction time.
*/
void Push(void* aItem) {
if (!Push(aItem, mozilla::fallible)) {
NS_ABORT_OOM(mSize * sizeof(void*));
}
}
explicit nsDequeBase();
/**
* Deque destructor. Erases all items, deletes the deallocator.
*/
~nsDequeBase();
/**
* Appends new member at the end of the deque.
@ -101,17 +80,6 @@ class nsDeque {
*/
[[nodiscard]] bool Push(void* aItem, const fallible_t&);
/**
* Inserts new member at the front of the deque.
*
* @param aItem item to store in deque
*/
void PushFront(void* aItem) {
if (!PushFront(aItem, mozilla::fallible)) {
NS_ABORT_OOM(mSize * sizeof(void*));
}
}
/**
* Inserts new member at the front of the deque.
*
@ -156,12 +124,171 @@ class nsDeque {
*/
void* ObjectAt(size_t aIndex) const;
bool GrowCapacity();
/**
* Remove all items from container without destroying them.
*/
void Empty();
size_t mSize;
size_t mCapacity;
size_t mOrigin;
void* mBuffer[8];
void** mData;
nsDequeBase& operator=(const nsDequeBase& aOther) = delete;
nsDequeBase(const nsDequeBase& aOther) = delete;
};
} // namespace detail
} // namespace mozilla
/**
* The nsDequeFunctor class is used when you want to create
* callbacks between the deque and your generic code.
* Use these objects in a call to ForEach(), and as custom deallocators.
*/
template <typename T>
class nsDequeFunctor {
public:
virtual void operator()(T* aObject) = 0;
virtual ~nsDequeFunctor() = default;
};
/******************************************************
* Here comes the nsDeque class itself...
******************************************************/
/**
* The deque (double-ended queue) class is a common container type,
* whose behavior mimics a line in your favorite checkout stand.
* Classic CS describes the common behavior of a queue as FIFO.
* A deque allows insertion and removal at both ends of
* the container.
*
* The deque stores pointers to items.
*/
template <typename T>
class nsDeque : public mozilla::detail::nsDequeBase {
typedef mozilla::fallible_t fallible_t;
public:
/**
* Constructs an empty deque.
*
* @param aDeallocator Optional deallocator functor that will be called from
* Erase() and the destructor on any remaining item.
* The deallocator is owned by the deque and will be
* deleted at destruction time.
*/
explicit nsDeque(nsDequeFunctor<T>* aDeallocator = nullptr) {
MOZ_COUNT_CTOR(nsDeque);
mDeallocator = aDeallocator;
}
/**
* Deque destructor. Erases all items, deletes the deallocator.
*/
~nsDeque() {
MOZ_COUNT_DTOR(nsDeque);
Erase();
SetDeallocator(nullptr);
}
/**
* Appends new member at the end of the deque.
*
* @param aItem item to store in deque
*/
inline void Push(T* aItem) {
if (!nsDequeBase::Push(aItem, mozilla::fallible)) {
NS_ABORT_OOM(mSize * sizeof(T*));
}
}
/**
* Appends new member at the end of the deque.
*
* @param aItem item to store in deque
* @return true if succeeded, false if failed to resize deque as needed
*/
[[nodiscard]] inline bool Push(T* aItem, const fallible_t& aFaillible) {
return nsDequeBase::Push(aItem, aFaillible);
}
/**
* Inserts new member at the front of the deque.
*
* @param aItem item to store in deque
*/
inline void PushFront(T* aItem) {
if (!nsDequeBase::PushFront(aItem, mozilla::fallible)) {
NS_ABORT_OOM(mSize * sizeof(T*));
}
}
/**
* Inserts new member at the front of the deque.
*
* @param aItem item to store in deque
* @return true if succeeded, false if failed to resize deque as needed
*/
[[nodiscard]] bool PushFront(T* aItem, const fallible_t& aFallible) {
return nsDequeBase::PushFront(aItem, aFallible);
}
/**
* Remove and return the last item in the container.
*
* @return the item that was the last item in container
*/
inline T* Pop() { return static_cast<T*>(nsDequeBase::Pop()); }
/**
* Remove and return the first item in the container.
*
* @return the item that was first item in container
*/
inline T* PopFront() { return static_cast<T*>(nsDequeBase::PopFront()); }
/**
* Retrieve the last item without removing it.
*
* @return the last item in container
*/
inline T* Peek() const { return static_cast<T*>(nsDequeBase::Peek()); }
/**
* Retrieve the first item without removing it.
*
* @return the first item in container
*/
inline T* PeekFront() const {
return static_cast<T*>(nsDequeBase::PeekFront());
}
/**
* Retrieve a member from the deque without removing it.
*
* @param index of desired item
* @return item in list, or nullptr if index is outside the deque
*/
inline T* ObjectAt(size_t aIndex) const {
return static_cast<T*>(nsDequeBase::ObjectAt(aIndex));
}
/**
* Remove and delete all items from container.
* Deletes are handled by the deallocator nsDequeFunctor
* which is specified at deque construction.
*/
void Erase();
void Erase() {
if (mDeallocator && mSize) {
ForEach(*mDeallocator);
}
Empty();
}
/**
* Call this method when you want to iterate through all
@ -173,7 +300,11 @@ class nsDeque {
*
* @param aFunctor object to call for each member
*/
void ForEach(nsDequeFunctor& aFunctor) const;
void ForEach(nsDequeFunctor<T>& aFunctor) const {
for (size_t i = 0; i < mSize; ++i) {
aFunctor(ObjectAt(i));
}
}
// This iterator assumes that the deque itself is const, i.e., it cannot be
// modified while the iterator is used.
@ -194,7 +325,7 @@ class nsDeque {
bool operator!=(const ConstDequeIterator& aOther) const {
return mIndex != aOther.mIndex;
}
void* operator*() const {
T* operator*() const {
// Don't allow out-of-deque dereferences.
MOZ_RELEASE_ASSERT(mIndex < mDeque.GetSize());
return mDeque.ObjectAt(mIndex);
@ -233,7 +364,7 @@ class nsDeque {
bool operator!=(const ConstIterator& aOther) const {
return EffectiveIndex() != aOther.EffectiveIndex();
}
void* operator*() const {
T* operator*() const {
// Don't allow out-of-deque dereferences.
MOZ_RELEASE_ASSERT(mIndex < mDeque.GetSize());
return mDeque.ObjectAt(mIndex);
@ -256,16 +387,20 @@ class nsDeque {
return ConstIterator(*this, ConstIterator::EndIteratorIndex);
}
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
size_t size = nsDequeBase::SizeOfExcludingThis(aMallocSizeOf);
if (mDeallocator) {
size += aMallocSizeOf(mDeallocator);
}
return size;
}
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
}
protected:
size_t mSize;
size_t mCapacity;
size_t mOrigin;
nsDequeFunctor* mDeallocator;
void* mBuffer[8];
void** mData;
nsDequeFunctor<T>* mDeallocator;
private:
/**
@ -283,12 +418,9 @@ class nsDeque {
*/
nsDeque& operator=(const nsDeque& aOther) = delete;
bool GrowCapacity();
void SetDeallocator(nsDequeFunctor* aDeallocator);
/**
* Remove all items from container without destroying them.
*/
void Empty();
void SetDeallocator(nsDequeFunctor<T>* aDeallocator) {
delete mDeallocator;
mDeallocator = aDeallocator;
}
};
#endif

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

@ -17,31 +17,32 @@
**************************************************************/
namespace TestNsDeque {
class _Dealloc : public nsDequeFunctor {
virtual void operator()(void* aObject) {}
template <typename T>
class _Dealloc : public nsDequeFunctor<T> {
virtual void operator()(T* aObject) {}
};
static bool VerifyContents(const nsDeque& aDeque, const int* aContents,
static bool VerifyContents(const nsDeque<int>& aDeque, const int* aContents,
size_t aLength) {
for (size_t i = 0; i < aLength; ++i) {
if (*(int*)aDeque.ObjectAt(i) != aContents[i]) {
if (*aDeque.ObjectAt(i) != aContents[i]) {
return false;
}
}
return true;
}
class Deallocator : public nsDequeFunctor {
virtual void operator()(void* aObject) {
class Deallocator : public nsDequeFunctor<int> {
virtual void operator()(int* aObject) {
if (aObject) {
// Set value to -1, to use in test function.
*((int*)aObject) = -1;
*(aObject) = -1;
}
}
};
class ForEachAdder : public nsDequeFunctor {
virtual void operator()(void* aObject) {
class ForEachAdder : public nsDequeFunctor<int> {
virtual void operator()(int* aObject) {
if (aObject) {
sum += *(int*)aObject;
}
@ -63,7 +64,7 @@ TEST(NsDeque, OriginalTest)
int ints[size];
size_t i = 0;
int temp;
nsDeque theDeque(new _Dealloc); // construct a simple one...
nsDeque<int> theDeque(new _Dealloc<int>); // construct a simple one...
// ints = [0...199]
for (i = 0; i < size; i++) { // initialize'em
@ -72,7 +73,7 @@ TEST(NsDeque, OriginalTest)
// queue = [0...69]
for (i = 0; i < 70; i++) {
theDeque.Push(&ints[i]);
temp = *(int*)theDeque.Peek();
temp = *theDeque.Peek();
EXPECT_EQ(static_cast<int>(i), temp) << "Verify end after push #1";
EXPECT_EQ(i + 1, theDeque.GetSize()) << "Verify size after push #1";
}
@ -81,7 +82,7 @@ TEST(NsDeque, OriginalTest)
// queue = [0...14]
for (i = 1; i <= 55; i++) {
temp = *(int*)theDeque.Pop();
temp = *theDeque.Pop();
EXPECT_EQ(70 - static_cast<int>(i), temp) << "Verify end after pop # 1";
EXPECT_EQ(70u - i, theDeque.GetSize()) << "Verify size after pop # 1";
}
@ -90,7 +91,7 @@ TEST(NsDeque, OriginalTest)
// queue = [0...14,0...54]
for (i = 0; i < 55; i++) {
theDeque.Push(&ints[i]);
temp = *(int*)theDeque.Peek();
temp = *theDeque.Peek();
EXPECT_EQ(static_cast<int>(i), temp) << "Verify end after push #2";
EXPECT_EQ(i + 15u + 1, theDeque.GetSize()) << "Verify size after push # 2";
}
@ -99,7 +100,7 @@ TEST(NsDeque, OriginalTest)
// queue = [0...14,0...19]
for (i = 1; i <= 35; i++) {
temp = *(int*)theDeque.Pop();
temp = *theDeque.Pop();
EXPECT_EQ(55 - static_cast<int>(i), temp) << "Verify end after pop # 2";
EXPECT_EQ(70u - i, theDeque.GetSize()) << "Verify size after pop #2";
}
@ -109,26 +110,26 @@ TEST(NsDeque, OriginalTest)
// queue = [0...14,0...19,0...34]
for (i = 0; i < 35; i++) {
theDeque.Push(&ints[i]);
temp = *(int*)theDeque.Peek();
temp = *theDeque.Peek();
EXPECT_EQ(static_cast<int>(i), temp) << "Verify end after push # 3";
EXPECT_EQ(35u + 1u + i, theDeque.GetSize()) << "Verify size after push #3";
}
// queue = [0...14,0...19]
for (i = 0; i < 35; i++) {
temp = *(int*)theDeque.Pop();
temp = *theDeque.Pop();
EXPECT_EQ(34 - static_cast<int>(i), temp) << "Verify end after pop # 3";
}
// queue = [0...14]
for (i = 0; i < 20; i++) {
temp = *(int*)theDeque.Pop();
temp = *theDeque.Pop();
EXPECT_EQ(19 - static_cast<int>(i), temp) << "Verify end after pop # 4";
}
// queue = []
for (i = 0; i < 15; i++) {
temp = *(int*)theDeque.Pop();
temp = *theDeque.Pop();
EXPECT_EQ(14 - static_cast<int>(i), temp) << "Verify end after pop # 5";
}
@ -140,7 +141,7 @@ TEST(NsDeque, OriginalFlaw)
int ints[200];
int i = 0;
int temp;
nsDeque d(new _Dealloc);
nsDeque<int> d(new _Dealloc<int>);
/**
* Test 1. Origin near end, semi full, call Peek().
* you start, mCapacity is 8
@ -149,13 +150,13 @@ TEST(NsDeque, OriginalFlaw)
for (i = 0; i < 6; i++) {
d.Push(&ints[i]);
temp = *(int*)d.Peek();
temp = *d.Peek();
EXPECT_EQ(i, temp) << "OriginalFlaw push #1";
}
EXPECT_EQ(6u, d.GetSize()) << "OriginalFlaw size check #1";
for (i = 0; i < 4; i++) {
temp = *(int*)d.PopFront();
temp = *d.PopFront();
EXPECT_EQ(i, temp) << "PopFront test";
}
// d = [4,5]
@ -167,14 +168,14 @@ TEST(NsDeque, OriginalFlaw)
// d = [4...9]
for (i = 4; i <= 9; i++) {
temp = *(int*)d.PopFront();
temp = *d.PopFront();
EXPECT_EQ(i, temp) << "OriginalFlaw empty check";
}
}
TEST(NsDeque, TestObjectAt)
{
nsDeque d;
nsDeque<int> d;
const int count = 10;
int ints[count];
for (int i = 0; i < count; i++) {
@ -190,7 +191,7 @@ TEST(NsDeque, TestObjectAt)
// d = [2..5]
for (size_t i = 2; i <= 5; i++) {
int t = *(int*)d.ObjectAt(i - 2);
int t = *d.ObjectAt(i - 2);
EXPECT_EQ(static_cast<int>(i), t) << "Verify ObjectAt()";
}
}
@ -202,7 +203,7 @@ TEST(NsDeque, TestPushFront)
// - wrapping around works properly
// - growing works properly
nsDeque d;
nsDeque<int> d;
const int kPoolSize = 10;
const size_t kMaxSizeBeforeGrowth = 8;
@ -239,7 +240,8 @@ TEST(NsDeque, TestPushFront)
<< "verify pushfront 3";
}
static void CheckIfQueueEmpty(nsDeque& d) {
template <typename T>
static void CheckIfQueueEmpty(nsDeque<T>& d) {
EXPECT_EQ(0u, d.GetSize()) << "Size should be 0";
EXPECT_EQ(nullptr, d.Pop()) << "Invalid operation should return nullptr";
EXPECT_EQ(nullptr, d.PopFront()) << "Invalid operation should return nullptr";
@ -253,7 +255,7 @@ static void CheckIfQueueEmpty(nsDeque& d) {
TEST(NsDeque, TestEmpty)
{
// Make sure nsDeque gives sane results if it's empty.
nsDeque d;
nsDeque<void> d;
size_t numberOfEntries = 8;
CheckIfQueueEmpty(d);
@ -275,7 +277,7 @@ TEST(NsDeque, TestEmpty)
TEST(NsDeque, TestEraseMethod)
{
nsDeque d;
nsDeque<void> d;
const size_t numberOfEntries = 8;
// Fill it up before calling Erase
@ -292,14 +294,14 @@ TEST(NsDeque, TestEraseMethod)
TEST(NsDeque, TestEraseShouldCallDeallocator)
{
nsDeque d(new Deallocator());
nsDeque<int> d(new Deallocator());
const size_t NumTestValues = 8;
int* testArray[NumTestValues];
for (size_t i = 0; i < NumTestValues; i++) {
testArray[i] = new int();
*(testArray[i]) = i;
d.Push((void*)testArray[i]);
d.Push(testArray[i]);
}
d.Erase();
@ -315,7 +317,7 @@ TEST(NsDeque, TestEraseShouldCallDeallocator)
TEST(NsDeque, TestForEach)
{
nsDeque d(new Deallocator());
nsDeque<int> d(new Deallocator());
const size_t NumTestValues = 8;
int sum = 0;
@ -324,7 +326,7 @@ TEST(NsDeque, TestForEach)
testArray[i] = new int();
*(testArray[i]) = i;
sum += i;
d.Push((void*)testArray[i]);
d.Push(testArray[i]);
}
ForEachAdder adder;
@ -336,7 +338,7 @@ TEST(NsDeque, TestForEach)
TEST(NsDeque, TestConstRangeFor)
{
nsDeque d(new Deallocator());
nsDeque<int> d(new Deallocator());
const size_t NumTestValues = 3;
for (size_t i = 0; i < NumTestValues; ++i) {
@ -344,16 +346,17 @@ TEST(NsDeque, TestConstRangeFor)
}
static_assert(
std::is_same_v<nsDeque::ConstDequeIterator,
decltype(std::declval<const nsDeque&>().begin())>,
std::is_same_v<nsDeque<int>::ConstDequeIterator,
decltype(std::declval<const nsDeque<int>&>().begin())>,
"(const nsDeque).begin() should return ConstDequeIterator");
static_assert(std::is_same_v<nsDeque::ConstDequeIterator,
decltype(std::declval<const nsDeque&>().end())>,
"(const nsDeque).end() should return ConstDequeIterator");
static_assert(
std::is_same_v<nsDeque<int>::ConstDequeIterator,
decltype(std::declval<const nsDeque<int>&>().end())>,
"(const nsDeque).end() should return ConstDequeIterator");
int sum = 0;
for (void* ob : const_cast<const nsDeque&>(d)) {
sum += *static_cast<int*>(ob);
for (int* ob : const_cast<const nsDeque<int>&>(d)) {
sum += *ob;
}
EXPECT_EQ(1 + 2 + 3, sum) << "Const-range-for should iterate over values";
}
@ -363,73 +366,76 @@ TEST(NsDeque, TestRangeFor)
const size_t NumTestValues = 3;
struct Test {
size_t runAfterLoopCount;
std::function<void(nsDeque&)> function;
std::function<void(nsDeque<int>&)> function;
int expectedSum;
const char* description;
};
// Note: All tests start with a deque containing 3 pointers to ints 1, 2, 3.
Test tests[] = {
{0, [](nsDeque& d) {}, 1 + 2 + 3, "no changes"},
{0, [](nsDeque<int>& d) {}, 1 + 2 + 3, "no changes"},
{1, [](nsDeque& d) { d.Pop(); }, 1 + 2, "Pop after 1st loop"},
{2, [](nsDeque& d) { d.Pop(); }, 1 + 2, "Pop after 2nd loop"},
{3, [](nsDeque& d) { d.Pop(); }, 1 + 2 + 3, "Pop after 3rd loop"},
{1, [](nsDeque<int>& d) { d.Pop(); }, 1 + 2, "Pop after 1st loop"},
{2, [](nsDeque<int>& d) { d.Pop(); }, 1 + 2, "Pop after 2nd loop"},
{3, [](nsDeque<int>& d) { d.Pop(); }, 1 + 2 + 3, "Pop after 3rd loop"},
{1, [](nsDeque& d) { d.PopFront(); }, 1 + 3, "PopFront after 1st loop"},
{2, [](nsDeque& d) { d.PopFront(); }, 1 + 2, "PopFront after 2nd loop"},
{3, [](nsDeque& d) { d.PopFront(); }, 1 + 2 + 3,
{1, [](nsDeque<int>& d) { d.PopFront(); }, 1 + 3,
"PopFront after 1st loop"},
{2, [](nsDeque<int>& d) { d.PopFront(); }, 1 + 2,
"PopFront after 2nd loop"},
{3, [](nsDeque<int>& d) { d.PopFront(); }, 1 + 2 + 3,
"PopFront after 3rd loop"},
{1, [](nsDeque& d) { d.Push(new int(4)); }, 1 + 2 + 3 + 4,
{1, [](nsDeque<int>& d) { d.Push(new int(4)); }, 1 + 2 + 3 + 4,
"Push after 1st loop"},
{2, [](nsDeque& d) { d.Push(new int(4)); }, 1 + 2 + 3 + 4,
{2, [](nsDeque<int>& d) { d.Push(new int(4)); }, 1 + 2 + 3 + 4,
"Push after 2nd loop"},
{3, [](nsDeque& d) { d.Push(new int(4)); }, 1 + 2 + 3 + 4,
{3, [](nsDeque<int>& d) { d.Push(new int(4)); }, 1 + 2 + 3 + 4,
"Push after 3rd loop"},
{4, [](nsDeque& d) { d.Push(new int(4)); }, 1 + 2 + 3,
{4, [](nsDeque<int>& d) { d.Push(new int(4)); }, 1 + 2 + 3,
"Push after would-be-4th loop"},
{1, [](nsDeque& d) { d.PushFront(new int(4)); }, 1 + 1 + 2 + 3,
{1, [](nsDeque<int>& d) { d.PushFront(new int(4)); }, 1 + 1 + 2 + 3,
"PushFront after 1st loop"},
{2, [](nsDeque& d) { d.PushFront(new int(4)); }, 1 + 2 + 2 + 3,
{2, [](nsDeque<int>& d) { d.PushFront(new int(4)); }, 1 + 2 + 2 + 3,
"PushFront after 2nd loop"},
{3, [](nsDeque& d) { d.PushFront(new int(4)); }, 1 + 2 + 3 + 3,
{3, [](nsDeque<int>& d) { d.PushFront(new int(4)); }, 1 + 2 + 3 + 3,
"PushFront after 3rd loop"},
{4, [](nsDeque& d) { d.PushFront(new int(4)); }, 1 + 2 + 3,
{4, [](nsDeque<int>& d) { d.PushFront(new int(4)); }, 1 + 2 + 3,
"PushFront after would-be-4th loop"},
{1, [](nsDeque& d) { d.Erase(); }, 1, "Erase after 1st loop"},
{2, [](nsDeque& d) { d.Erase(); }, 1 + 2, "Erase after 2nd loop"},
{3, [](nsDeque& d) { d.Erase(); }, 1 + 2 + 3, "Erase after 3rd loop"},
{1, [](nsDeque<int>& d) { d.Erase(); }, 1, "Erase after 1st loop"},
{2, [](nsDeque<int>& d) { d.Erase(); }, 1 + 2, "Erase after 2nd loop"},
{3, [](nsDeque<int>& d) { d.Erase(); }, 1 + 2 + 3,
"Erase after 3rd loop"},
{1,
[](nsDeque& d) {
[](nsDeque<int>& d) {
d.Erase();
d.Push(new int(4));
},
1, "Erase after 1st loop, Push 4"},
{1,
[](nsDeque& d) {
[](nsDeque<int>& d) {
d.Erase();
d.Push(new int(4));
d.Push(new int(5));
},
1 + 5, "Erase after 1st loop, Push 4,5"},
{2,
[](nsDeque& d) {
[](nsDeque<int>& d) {
d.Erase();
d.Push(new int(4));
},
1 + 2, "Erase after 2nd loop, Push 4"},
{2,
[](nsDeque& d) {
[](nsDeque<int>& d) {
d.Erase();
d.Push(new int(4));
d.Push(new int(5));
},
1 + 2, "Erase after 2nd loop, Push 4,5"},
{2,
[](nsDeque& d) {
[](nsDeque<int>& d) {
d.Erase();
d.Push(new int(4));
d.Push(new int(5));
@ -438,21 +444,23 @@ TEST(NsDeque, TestRangeFor)
1 + 2 + 6, "Erase after 2nd loop, Push 4,5,6"}};
for (const Test& test : tests) {
nsDeque d(new Deallocator());
nsDeque<int> d(new Deallocator());
for (size_t i = 0; i < NumTestValues; ++i) {
d.Push(new int(i + 1));
}
static_assert(std::is_same_v<nsDeque::ConstIterator, decltype(d.begin())>,
"(non-const nsDeque).begin() should return ConstIterator");
static_assert(std::is_same_v<nsDeque::ConstIterator, decltype(d.end())>,
"(non-const nsDeque).end() should return ConstIterator");
static_assert(
std::is_same_v<nsDeque<int>::ConstIterator, decltype(d.begin())>,
"(non-const nsDeque).begin() should return ConstIterator");
static_assert(
std::is_same_v<nsDeque<int>::ConstIterator, decltype(d.end())>,
"(non-const nsDeque).end() should return ConstIterator");
int sum = 0;
size_t loopCount = 0;
for (void* ob : d) {
sum += *static_cast<int*>(ob);
for (int* ob : d) {
sum += *ob;
if (++loopCount == test.runAfterLoopCount) {
test.function(d);
}