From c55098af5e62f4f388d9c4e7f5bfbaa6a6ac687b Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Wed, 25 Jun 2025 13:03:43 -0700 Subject: [PATCH] [message] change queues to use non-circular linked list (#11630) This commit updates the `MessageQueue` and `PriorityQueue` implementations to use non-circular doubly linked lists instead of the previous circular ones. Using a non-circular list requires the queue to track the head element, but it simplifies common operations like getting the head and iterating over the messages. Particularly, `Message::GetNext()` now simply returns the `mNext` pointer. Previously, `Message` had to store a pointer to its `mQueue` within its `Metadata` to identify the tail of the queue and stop the iteration correctly. This commit also updates the unit tests. In particular, `test_priority_queue` is significantly enhanced to cover many scenarios, such as multiple messages with the same priority, and messages with different priorities being added and removed in various orders. --- include/openthread/instance.h | 2 +- include/openthread/message.h | 3 +- src/core/api/message_api.cpp | 11 +- src/core/common/message.cpp | 251 ++++++------ src/core/common/message.hpp | 63 +-- tests/unit/test_message_queue.cpp | 42 +- tests/unit/test_priority_queue.cpp | 590 ++++++++++++++++++++++++----- 7 files changed, 694 insertions(+), 268 deletions(-) diff --git a/include/openthread/instance.h b/include/openthread/instance.h index ae8d3cb42..dc9e4fcea 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -52,7 +52,7 @@ extern "C" { * * @note This number versions both OpenThread platform and user APIs. */ -#define OPENTHREAD_API_VERSION (514) +#define OPENTHREAD_API_VERSION (515) /** * @addtogroup api-instance diff --git a/include/openthread/message.h b/include/openthread/message.h index 474d65532..b084d2290 100644 --- a/include/openthread/message.h +++ b/include/openthread/message.h @@ -400,7 +400,8 @@ int otMessageWrite(otMessage *aMessage, uint16_t aOffset, const void *aBuf, uint */ typedef struct { - void *mData; ///< Opaque data used by the implementation. + void *mData; ///< Opaque data used by the implementation. + void *mData2; ///< Opaque data used by the implementation. } otMessageQueue; /** diff --git a/src/core/api/message_api.cpp b/src/core/api/message_api.cpp index 298c3db85..004324bff 100644 --- a/src/core/api/message_api.cpp +++ b/src/core/api/message_api.cpp @@ -122,12 +122,7 @@ int otMessageWrite(otMessage *aMessage, uint16_t aOffset, const void *aBuf, uint return aLength; } -void otMessageQueueInit(otMessageQueue *aQueue) -{ - AssertPointerIsNotNull(aQueue); - - aQueue->mData = nullptr; -} +void otMessageQueueInit(otMessageQueue *aQueue) { AsCoreType(aQueue).Clear(); } void otMessageQueueEnqueue(otMessageQueue *aQueue, otMessage *aMessage) { @@ -148,11 +143,11 @@ otMessage *otMessageQueueGetHead(otMessageQueue *aQueue) { return AsCoreType(aQu otMessage *otMessageQueueGetNext(otMessageQueue *aQueue, const otMessage *aMessage) { + OT_UNUSED_VARIABLE(aQueue); + Message *next; VerifyOrExit(aMessage != nullptr, next = nullptr); - - VerifyOrExit(AsCoreType(aMessage).GetMessageQueue() == aQueue, next = nullptr); next = AsCoreType(aMessage).GetNext(); exit: diff --git a/src/core/common/message.cpp b/src/core/common/message.cpp index 406624cc4..ce4002ce7 100644 --- a/src/core/common/message.cpp +++ b/src/core/common/message.cpp @@ -75,6 +75,7 @@ Message *MessagePool::Allocate(Message::Type aType, uint16_t aReserveHeader, con message->SetLinkSecurityEnabled(aSettings.IsLinkSecurityEnabled()); message->SetLoopbackToHostAllowed(OPENTHREAD_CONFIG_IP6_ALLOW_LOOP_BACK_HOST_DATAGRAMS); message->SetOrigin(Message::kOriginHostTrusted); + message->MarkAsNotInAQueue(); SuccessOrExit(error = message->SetPriority(aSettings.GetPriority())); SuccessOrExit(error = message->SetLength(0)); @@ -98,7 +99,7 @@ Message *MessagePool::Allocate(Message::Type aType, uint16_t aReserveHeader) void MessagePool::Free(Message *aMessage) { - OT_ASSERT(aMessage->Next() == nullptr && aMessage->Prev() == nullptr); + OT_ASSERT(!aMessage->IsInAQueue()); FreeBuffers(static_cast(aMessage)); } @@ -260,30 +261,6 @@ void Message::Free(void) Get().Free(this); } -Message *Message::GetNext(void) const -{ - Message *next; - Message *tail; - - if (GetMetadata().mInPriorityQ) - { - PriorityQueue *priorityQueue = GetPriorityQueue(); - VerifyOrExit(priorityQueue != nullptr, next = nullptr); - tail = priorityQueue->GetTail(); - } - else - { - MessageQueue *messageQueue = GetMessageQueue(); - VerifyOrExit(messageQueue != nullptr, next = nullptr); - tail = messageQueue->GetTail(); - } - - next = (this == tail) ? nullptr : Next(); - -exit: - return next; -} - Error Message::SetLength(uint16_t aLength) { Error error = kErrorNone; @@ -871,16 +848,18 @@ bool Message::IsTimeSync(void) const #endif } -void Message::SetMessageQueue(MessageQueue *aMessageQueue) +void Message::MarkAsNotInAQueue(void) { - GetMetadata().mQueue = aMessageQueue; - GetMetadata().mInPriorityQ = false; -} + // To indicate that a message is no longer in a queue, we set + // its 'mPrev' pointer to point back to itself. This state is + // unique and won't occur if the message is part of a queue. We + // also set 'mNext' to 'nullptr' so that 'GetNext()' correctly + // returns 'nullptr' for a dequeued message. -void Message::SetPriorityQueue(PriorityQueue *aPriorityQueue) -{ - GetMetadata().mQueue = aPriorityQueue; - GetMetadata().mInPriorityQ = aPriorityQueue != nullptr; + Next() = nullptr; + Prev() = this; + + GetMetadata().mInPriorityQ = false; } //--------------------------------------------------------------------------------------------------------------------- @@ -889,56 +868,61 @@ void Message::SetPriorityQueue(PriorityQueue *aPriorityQueue) void MessageQueue::Enqueue(Message &aMessage, QueuePosition aPosition) { OT_ASSERT(!aMessage.IsInAQueue()); - OT_ASSERT((aMessage.Next() == nullptr) && (aMessage.Prev() == nullptr)); - aMessage.SetMessageQueue(this); + aMessage.GetMetadata().mInPriorityQ = false; - if (GetTail() == nullptr) + if (GetHead() == nullptr) { - aMessage.Next() = &aMessage; - aMessage.Prev() = &aMessage; + aMessage.Next() = nullptr; + aMessage.Prev() = nullptr; + SetHead(&aMessage); SetTail(&aMessage); } else { - Message *head = GetTail()->Next(); - - aMessage.Next() = head; - aMessage.Prev() = GetTail(); - - head->Prev() = &aMessage; - GetTail()->Next() = &aMessage; - - if (aPosition == kQueuePositionTail) + switch (aPosition) { + case kQueuePositionHead: + aMessage.Next() = GetHead(); + aMessage.Prev() = nullptr; + GetHead()->Prev() = &aMessage; + SetHead(&aMessage); + break; + + case kQueuePositionTail: + aMessage.Next() = nullptr; + aMessage.Prev() = GetTail(); + GetTail()->Next() = &aMessage; SetTail(&aMessage); + break; } } } void MessageQueue::Dequeue(Message &aMessage) { - OT_ASSERT(aMessage.GetMessageQueue() == this); - OT_ASSERT((aMessage.Next() != nullptr) && (aMessage.Prev() != nullptr)); + if (&aMessage == GetHead()) + { + SetHead(aMessage.Next()); + } if (&aMessage == GetTail()) { - SetTail(GetTail()->Prev()); - - if (&aMessage == GetTail()) - { - SetTail(nullptr); - } + SetTail(aMessage.Prev()); } - aMessage.Prev()->Next() = aMessage.Next(); - aMessage.Next()->Prev() = aMessage.Prev(); + if (aMessage.Prev() != nullptr) + { + aMessage.Prev()->Next() = aMessage.Next(); + } - aMessage.Prev() = nullptr; - aMessage.Next() = nullptr; + if (aMessage.Next() != nullptr) + { + aMessage.Next()->Prev() = aMessage.Prev(); + } - aMessage.SetMessageQueue(nullptr); + aMessage.MarkAsNotInAQueue(); } void MessageQueue::DequeueAndFree(Message &aMessage) @@ -983,86 +967,109 @@ void MessageQueue::AddQueueInfos(Info &aInfo, const Info &aOther) //--------------------------------------------------------------------------------------------------------------------- // PriorityQueue -const Message *PriorityQueue::FindFirstNonNullTail(Message::Priority aStartPriorityLevel) const +const Message *PriorityQueue::FindTailForPriorityOrHigher(uint8_t aPriority) const { - // Find the first non-`nullptr` tail starting from the given priority - // level and moving forward (wrapping from priority value - // `kNumPriorities` -1 back to 0). + // This method finds the tail (last message entry in the list) + // that has priority level that is greater than or equal to + // `aPriority` and currently has messages in the queue. + // + // The `PriorityQueue` uses the `mTails` array to store pointers + // to the last message for each priority level. If a specific + // priority level has no messages, its corresponding `mTails` + // entry will be `nullptr`. + // + // The method iterates from `aPriority` upwards through higher + // priority levels, returning the first non-null tail pointer it + // encounters. + // + // The returned `Message` pointer indicates where a new message + // with `aPriority` should be inserted: it should be placed + // immediately after this returned message. If `nullptr` is + // returned, it means the new message will be the first of its + // priority level (or any higher priority) in the queue, and + // should be placed at the head. const Message *tail = nullptr; - uint8_t priority; - priority = static_cast(aStartPriorityLevel); - - do + for (uint8_t priority = aPriority; priority < Message::kNumPriorities; priority++) { - if (mTails[priority] != nullptr) + tail = mTails[priority]; + + if (tail != nullptr) { - tail = mTails[priority]; break; } - - priority = PrevPriority(priority); - } while (priority != aStartPriorityLevel); + } return tail; } -const Message *PriorityQueue::GetHead(void) const -{ - return Message::NextOf(FindFirstNonNullTail(Message::kPriorityLow)); -} - const Message *PriorityQueue::GetHeadForPriority(Message::Priority aPriority) const { - const Message *head; - const Message *previousTail; + const Message *head = nullptr; + uint8_t priority = static_cast(aPriority); - if (mTails[aPriority] != nullptr) + if (mTails[priority] == nullptr) { - previousTail = FindFirstNonNullTail(static_cast(PrevPriority(aPriority))); - - OT_ASSERT(previousTail != nullptr); - - head = previousTail->Next(); + head = nullptr; + } + else if (mHead->GetPriority() == aPriority) + { + head = mHead; } else { - head = nullptr; + const Message *previousTail = FindTailForPriorityOrHigher(priority + 1); + + OT_ASSERT(previousTail != nullptr); + head = previousTail->Next(); } return head; } -const Message *PriorityQueue::GetTail(void) const { return FindFirstNonNullTail(Message::kPriorityLow); } +const Message *PriorityQueue::GetTail(void) const { return FindTailForPriorityOrHigher(Message::kPriorityLow); } void PriorityQueue::Enqueue(Message &aMessage) { - Message::Priority priority; - Message *tail; - Message *next; + uint8_t priority; OT_ASSERT(!aMessage.IsInAQueue()); - aMessage.SetPriorityQueue(this); + aMessage.GetMetadata().mInPriorityQ = true; priority = aMessage.GetPriority(); - tail = FindFirstNonNullTail(priority); + // We insert the new `aMessage` immediately after the message + // returned by `FindTailForPriorityOrHigher()`. + // + // If `FindTailForPriorityOrHigher()` returns `nullptr`, it means + // `aMessage` has the highest priority of all existing messages + // or is the first message in the queue, so we add it at the head + // and update `mHead` accordingly. + // + // We first set the `Prev` and `Next` pointers within `aMessage` + // itself. Afterward, we update the `Next()` pointer of the + // preceding message (if any) and the `Prev()` pointer of the + // succeeding message (if any) to point back to the newly + // inserted `aMessage`, maintaining the linked list. - if (tail != nullptr) + aMessage.Prev() = FindTailForPriorityOrHigher(priority); + + if (aMessage.Prev() == nullptr) { - next = tail->Next(); - - aMessage.Next() = next; - aMessage.Prev() = tail; - next->Prev() = &aMessage; - tail->Next() = &aMessage; + aMessage.Next() = mHead; + mHead = &aMessage; } else { - aMessage.Next() = &aMessage; - aMessage.Prev() = &aMessage; + aMessage.Next() = aMessage.Prev()->Next(); + aMessage.Prev()->Next() = &aMessage; + } + + if (aMessage.Next() != nullptr) + { + aMessage.Next()->Prev() = &aMessage; } mTails[priority] = &aMessage; @@ -1071,32 +1078,44 @@ void PriorityQueue::Enqueue(Message &aMessage) void PriorityQueue::Dequeue(Message &aMessage) { Message::Priority priority; - Message *tail; - OT_ASSERT(aMessage.GetPriorityQueue() == this); + OT_ASSERT(aMessage.IsInAPriorityQueue()); priority = aMessage.GetPriority(); - tail = mTails[priority]; + // If `aMessage` is the current tail for its priority, update + // `mTails[priority]`. The new tail becomes the preceding + // message entry. If the preceding message has a different + // (higher) priority, or if there's no preceding message, it + // means `aMessage` was the last of its priority, and the + // `mTails[priority]` is set to `nullptr`. - if (&aMessage == tail) + if (&aMessage == mTails[priority]) { - tail = tail->Prev(); + mTails[priority] = aMessage.Prev(); - if ((&aMessage == tail) || (tail->GetPriority() != priority)) + if ((mTails[priority] != nullptr) && (mTails[priority]->GetPriority() != priority)) { - tail = nullptr; + mTails[priority] = nullptr; } - - mTails[priority] = tail; } - aMessage.Next()->Prev() = aMessage.Prev(); - aMessage.Prev()->Next() = aMessage.Next(); - aMessage.Next() = nullptr; - aMessage.Prev() = nullptr; + if (&aMessage == mHead) + { + mHead = aMessage.Next(); + } - aMessage.SetPriorityQueue(nullptr); + if (aMessage.Next() != nullptr) + { + aMessage.Next()->Prev() = aMessage.Prev(); + } + + if (aMessage.Prev() != nullptr) + { + aMessage.Prev()->Next() = aMessage.Next(); + } + + aMessage.MarkAsNotInAQueue(); } void PriorityQueue::DequeueAndFree(Message &aMessage) diff --git a/src/core/common/message.hpp b/src/core/common/message.hpp index 838263724..f886fdf0b 100644 --- a/src/core/common/message.hpp +++ b/src/core/common/message.hpp @@ -235,7 +235,6 @@ protected: TimeMilli mTimestamp; // The message timestamp. Message *mNext; // Next message in a doubly linked list. Message *mPrev; // Previous message in a doubly linked list. - void *mQueue; // The queue where message is queued (if any). Queue type from `mInPriorityQ`. TxCallback mTxCallback; // The callback to inform message TX success or failure. void *mTxContext; // The arbitrary context associated with `mTxCallback`. RssAverager mRssAverager; // The averager maintaining the received signal strength (RSS) average. @@ -501,7 +500,7 @@ public: * * @returns A pointer to the next message in the list or `nullptr` if at the end of the list. */ - Message *GetNext(void) const; + Message *GetNext(void) const { return Next(); } /** * Returns the number of bytes in the message. @@ -1425,26 +1424,6 @@ public: */ void UpdateLinkInfoFrom(const ThreadLinkInfo &aLinkInfo); - /** - * Returns a pointer to the message queue (if any) where this message is queued. - * - * @returns A pointer to the message queue or `nullptr` if not in any message queue. - */ - MessageQueue *GetMessageQueue(void) const - { - return !GetMetadata().mInPriorityQ ? static_cast(GetMetadata().mQueue) : nullptr; - } - - /** - * Returns a pointer to the priority message queue (if any) where this message is queued. - * - * @returns A pointer to the priority queue or `nullptr` if not in any priority queue. - */ - PriorityQueue *GetPriorityQueue(void) const - { - return GetMetadata().mInPriorityQ ? static_cast(GetMetadata().mQueue) : nullptr; - } - /** * Indicates whether or not the message is also used for time sync purpose. * @@ -1603,18 +1582,17 @@ private: AsConst(this)->GetNextChunk(aLength, static_cast(aChunk)); } - bool IsInAQueue(void) const { return (GetMetadata().mQueue != nullptr); } + void MarkAsNotInAQueue(void); + bool IsInAQueue(void) const { return (Prev() != this); } bool IsInAPriorityQueue(void) const { return GetMetadata().mInPriorityQ; } - void SetMessageQueue(MessageQueue *aMessageQueue); - void SetPriorityQueue(PriorityQueue *aPriorityQueue); - void SetRssAverager(const RssAverager &aRssAverager) { GetMetadata().mRssAverager = aRssAverager; } void SetLqiAverager(const LqiAverager &aLqiAverager) { GetMetadata().mLqiAverager = aLqiAverager; } Message *&Next(void) { return GetMetadata().mNext; } Message *const &Next(void) const { return GetMetadata().mNext; } Message *&Prev(void) { return GetMetadata().mPrev; } + Message *const &Prev(void) const { return GetMetadata().mPrev; } static Message *NextOf(Message *aMessage) { return (aMessage != nullptr) ? aMessage->Next() : nullptr; } static const Message *NextOf(const Message *aMessage) { return (aMessage != nullptr) ? aMessage->Next() : nullptr; } @@ -1625,7 +1603,7 @@ private: /** * Implements a message queue. */ -class MessageQueue : public otMessageQueue, private NonCopyable +class MessageQueue : public otMessageQueue, public Clearable, private NonCopyable { friend class Message; friend class PriorityQueue; @@ -1646,7 +1624,7 @@ public: /** * Initializes the message queue. */ - MessageQueue(void) { SetTail(nullptr); } + MessageQueue(void) { Clear(); } #if OPENTHREAD_PLATFORM_NEXUS /** @@ -1660,14 +1638,14 @@ public: * * @returns A pointer to the first message. */ - Message *GetHead(void) { return Message::NextOf(GetTail()); } + Message *GetHead(void) { return static_cast(mData); } /** * Returns a pointer to the first message. * * @returns A pointer to the first message. */ - const Message *GetHead(void) const { return Message::NextOf(GetTail()); } + const Message *GetHead(void) const { return static_cast(mData); } /** * Adds a message to the end of the list. @@ -1733,9 +1711,10 @@ public: Message::ConstIterator end(void) const { return Message::ConstIterator(); } private: - Message *GetTail(void) { return static_cast(mData); } - const Message *GetTail(void) const { return static_cast(mData); } - void SetTail(Message *aMessage) { mData = aMessage; } + void SetHead(Message *aMessage) { mData = aMessage; } + Message *GetTail(void) { return static_cast(mData2); } + const Message *GetTail(void) const { return static_cast(mData2); } + void SetTail(Message *aMessage) { mData2 = aMessage; } }; /** @@ -1768,14 +1747,14 @@ public: * * @returns A pointer to the first message. */ - Message *GetHead(void) { return AsNonConst(AsConst(this)->GetHead()); } + Message *GetHead(void) { return mHead; } /** * Returns a pointer to the first message. * * @returns A pointer to the first message. */ - const Message *GetHead(void) const; + const Message *GetHead(void) const { return mHead; } /** * Returns a pointer to the first message for a given priority level. @@ -1864,18 +1843,14 @@ public: Message::ConstIterator end(void) const { return Message::ConstIterator(); } private: - uint8_t PrevPriority(uint8_t aPriority) const + const Message *FindTailForPriorityOrHigher(uint8_t aPriority) const; + + Message *FindTailForPriorityOrHigher(uint8_t aPriority) { - return (aPriority == Message::kNumPriorities - 1) ? 0 : (aPriority + 1); - } - - const Message *FindFirstNonNullTail(Message::Priority aStartPriorityLevel) const; - - Message *FindFirstNonNullTail(Message::Priority aStartPriorityLevel) - { - return AsNonConst(AsConst(this)->FindFirstNonNullTail(aStartPriorityLevel)); + return AsNonConst(AsConst(this)->FindTailForPriorityOrHigher(aPriority)); } + Message *mHead; Message *mTails[Message::kNumPriorities]; // Tail pointers associated with different priority levels. }; diff --git a/tests/unit/test_message_queue.cpp b/tests/unit/test_message_queue.cpp index a1c2b5821..1612f13d3 100644 --- a/tests/unit/test_message_queue.cpp +++ b/tests/unit/test_message_queue.cpp @@ -133,6 +133,46 @@ void TestMessageQueue(void) messageQueue.Dequeue(*messages[0]); VerifyMessageQueueContent(messageQueue, 0); + // Enqueue 2 messages and remove them in the same order added. + messageQueue.Enqueue(*messages[0]); + VerifyMessageQueueContent(messageQueue, 1, messages[0]); + messageQueue.Enqueue(*messages[1]); + VerifyMessageQueueContent(messageQueue, 2, messages[0], messages[1]); + messageQueue.Dequeue(*messages[0]); + VerifyMessageQueueContent(messageQueue, 1, messages[1]); + messageQueue.Dequeue(*messages[1]); + VerifyMessageQueueContent(messageQueue, 0); + + // Enqueue 2 messages and remove them in reverse order added. + messageQueue.Enqueue(*messages[0]); + VerifyMessageQueueContent(messageQueue, 1, messages[0]); + messageQueue.Enqueue(*messages[1]); + VerifyMessageQueueContent(messageQueue, 2, messages[0], messages[1]); + messageQueue.Dequeue(*messages[1]); + VerifyMessageQueueContent(messageQueue, 1, messages[0]); + messageQueue.Dequeue(*messages[0]); + VerifyMessageQueueContent(messageQueue, 0); + + // Enqueue 2 messages at the head and remove them in the same order added. + messageQueue.Enqueue(*messages[0], MessageQueue::kQueuePositionHead); + VerifyMessageQueueContent(messageQueue, 1, messages[0]); + messageQueue.Enqueue(*messages[1], MessageQueue::kQueuePositionHead); + VerifyMessageQueueContent(messageQueue, 2, messages[1], messages[0]); + messageQueue.Dequeue(*messages[0]); + VerifyMessageQueueContent(messageQueue, 1, messages[1]); + messageQueue.Dequeue(*messages[1]); + VerifyMessageQueueContent(messageQueue, 0); + + // Enqueue 2 messages at the head and remove them in the reverse order added. + messageQueue.Enqueue(*messages[0], MessageQueue::kQueuePositionHead); + VerifyMessageQueueContent(messageQueue, 1, messages[0]); + messageQueue.Enqueue(*messages[1], MessageQueue::kQueuePositionHead); + VerifyMessageQueueContent(messageQueue, 2, messages[1], messages[0]); + messageQueue.Dequeue(*messages[1]); + VerifyMessageQueueContent(messageQueue, 1, messages[0]); + messageQueue.Dequeue(*messages[0]); + VerifyMessageQueueContent(messageQueue, 0); + // Enqueue 5 messages messageQueue.Enqueue(*messages[0]); VerifyMessageQueueContent(messageQueue, 1, messages[0]); @@ -333,8 +373,6 @@ void TestMessageQueueOtApis(void) message = otMessageQueueGetNext(&queue2, messages[0]); VerifyOrQuit(message == messages[1], "otMessageQueueGetNext() failed"); - message = otMessageQueueGetNext(&queue, messages[0]); - VerifyOrQuit(message == nullptr, "otMessageQueueGetNext() did not return nullptr for message not in the queue."); // Remove all element and make sure queue is empty otMessageQueueDequeue(&queue, messages[2]); diff --git a/tests/unit/test_priority_queue.cpp b/tests/unit/test_priority_queue.cpp index 5cbf39334..e4a3e795c 100644 --- a/tests/unit/test_priority_queue.cpp +++ b/tests/unit/test_priority_queue.cpp @@ -37,10 +37,6 @@ namespace ot { -#define kNumNewPriorityTestMessages 2 -#define kNumSetPriorityTestMessages 2 -#define kNumTestMessages (kNumNewPriorityTestMessages + kNumSetPriorityTestMessages) - // This function verifies the content of the priority queue to match the passed in messages void VerifyPriorityQueueContent(PriorityQueue &aPriorityQueue, int aExpectedLength, ...) { @@ -135,140 +131,541 @@ void VerifyPriorityQueueContent(PriorityQueue &aPriorityQueue, int aExpectedLeng VerifyOrQuit(message == nullptr, "`for` loop iteration resulted in fewer entries than expected"); } +// NOLINTBEGIN(modernize-loop-convert) void TestPriorityQueue(void) { + static constexpr uint16_t kNumNewPriorityTestMessages = 2; + static constexpr uint16_t kNumSetPriorityTestMessages = 2; + static constexpr uint16_t kNumTestMessages = (kNumNewPriorityTestMessages + kNumSetPriorityTestMessages); + + // Use two char abbreviated names for different priority levels; + static constexpr uint8_t kNw = Message::kPriorityNet; // Network level (highest priority) + static constexpr uint8_t kHi = Message::kPriorityHigh; // High priority + static constexpr uint8_t kMd = Message::kPriorityNormal; // Middle (or Normal) priority + static constexpr uint8_t kLo = Message::kPriorityLow; // Low priority. + static constexpr uint8_t kNumPriorities = Message::kNumPriorities; + Instance *instance; MessagePool *messagePool; PriorityQueue queue; - Message *msgNet[kNumTestMessages]; - Message *msgHigh[kNumTestMessages]; - Message *msgNor[kNumTestMessages]; - Message *msgLow[kNumTestMessages]; + Message *msg[kNumPriorities][kNumTestMessages]; instance = testInitInstance(); VerifyOrQuit(instance != nullptr, "Null OpenThread instance"); messagePool = &instance->Get(); - // Use the function "Allocate()" to allocate messages with different priorities - for (int i = 0; i < kNumNewPriorityTestMessages; i++) + for (uint8_t prio = 0; prio < kNumPriorities; prio++) { - msgNet[i] = messagePool->Allocate(Message::kTypeIp6, 0, Message::Settings(Message::kPriorityNet)); - VerifyOrQuit(msgNet[i] != nullptr); - msgHigh[i] = messagePool->Allocate(Message::kTypeIp6, 0, Message::Settings(Message::kPriorityHigh)); - VerifyOrQuit(msgHigh[i] != nullptr); - msgNor[i] = messagePool->Allocate(Message::kTypeIp6, 0, Message::Settings(Message::kPriorityNormal)); - VerifyOrQuit(msgNor[i] != nullptr); - msgLow[i] = messagePool->Allocate(Message::kTypeIp6, 0, Message::Settings(Message::kPriorityLow)); - VerifyOrQuit(msgLow[i] != nullptr); - } + Message::Priority priority = static_cast(prio); - // Use the function "SetPriority()" to allocate messages with different priorities - for (int i = kNumNewPriorityTestMessages; i < kNumTestMessages; i++) - { - msgNet[i] = messagePool->Allocate(Message::kTypeIp6); - VerifyOrQuit(msgNet[i] != nullptr); - SuccessOrQuit(msgNet[i]->SetPriority(Message::kPriorityNet)); - msgHigh[i] = messagePool->Allocate(Message::kTypeIp6); - VerifyOrQuit(msgHigh[i] != nullptr); - SuccessOrQuit(msgHigh[i]->SetPriority(Message::kPriorityHigh)); - msgNor[i] = messagePool->Allocate(Message::kTypeIp6); - VerifyOrQuit(msgNor[i] != nullptr); - SuccessOrQuit(msgNor[i]->SetPriority(Message::kPriorityNormal)); - msgLow[i] = messagePool->Allocate(Message::kTypeIp6); - VerifyOrQuit(msgLow[i] != nullptr); - SuccessOrQuit(msgLow[i]->SetPriority(Message::kPriorityLow)); + // Use the function "Allocate()" to allocate messages with different priorities + for (int i = 0; i < kNumNewPriorityTestMessages; i++) + { + msg[prio][i] = messagePool->Allocate(Message::kTypeIp6, 0, Message::Settings(priority)); + VerifyOrQuit(msg[prio][i] != nullptr); + } + + // Use the function "SetPriority()" to allocate messages with different priorities + for (int i = kNumNewPriorityTestMessages; i < kNumTestMessages; i++) + { + msg[prio][i] = messagePool->Allocate(Message::kTypeIp6); + VerifyOrQuit(msg[prio][i] != nullptr); + SuccessOrQuit(msg[prio][i]->SetPriority(priority)); + } } // Check the `GetPriority()` for (int i = 0; i < kNumTestMessages; i++) { - VerifyOrQuit(msgLow[i]->GetPriority() == Message::kPriorityLow); - VerifyOrQuit(msgNor[i]->GetPriority() == Message::kPriorityNormal); - VerifyOrQuit(msgHigh[i]->GetPriority() == Message::kPriorityHigh); - VerifyOrQuit(msgNet[i]->GetPriority() == Message::kPriorityNet); + VerifyOrQuit(msg[kLo][i]->GetPriority() == Message::kPriorityLow); + VerifyOrQuit(msg[kMd][i]->GetPriority() == Message::kPriorityNormal); + VerifyOrQuit(msg[kHi][i]->GetPriority() == Message::kPriorityHigh); + VerifyOrQuit(msg[kNw][i]->GetPriority() == Message::kPriorityNet); } // Verify case of an empty queue. VerifyPriorityQueueContent(queue, 0); + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Messages with the same priority only. + + for (uint8_t prio = 0; prio < kNumPriorities; prio++) + { + // Add and remove one message only + queue.Enqueue(*msg[prio][0]); + VerifyPriorityQueueContent(queue, 1, msg[prio][0]); + queue.Dequeue(*msg[prio][0]); + VerifyPriorityQueueContent(queue, 0); + + // Add three messages and then dequeue them in different orders. + + for (uint8_t test = 0; test < 3; test++) + { + queue.Enqueue(*msg[prio][0]); + VerifyPriorityQueueContent(queue, 1, msg[prio][0]); + queue.Enqueue(*msg[prio][1]); + VerifyPriorityQueueContent(queue, 2, msg[prio][0], msg[prio][1]); + queue.Enqueue(*msg[prio][2]); + VerifyPriorityQueueContent(queue, 3, msg[prio][0], msg[prio][1], msg[prio][2]); + + switch (test) + { + case 0: + // Remove the messages in the same order added. + queue.Dequeue(*msg[prio][0]); + VerifyPriorityQueueContent(queue, 2, msg[prio][1], msg[prio][2]); + queue.Dequeue(*msg[prio][1]); + VerifyPriorityQueueContent(queue, 1, msg[prio][2]); + queue.Dequeue(*msg[prio][2]); + break; + + case 1: + // Remove the message in the reverse order added + queue.Dequeue(*msg[prio][2]); + VerifyPriorityQueueContent(queue, 2, msg[prio][0], msg[prio][1]); + queue.Dequeue(*msg[prio][1]); + VerifyPriorityQueueContent(queue, 1, msg[prio][0]); + queue.Dequeue(*msg[prio][0]); + break; + + case 2: + // Remove the message in random order added. + queue.Dequeue(*msg[prio][1]); + VerifyPriorityQueueContent(queue, 2, msg[prio][0], msg[prio][2]); + queue.Dequeue(*msg[prio][0]); + VerifyPriorityQueueContent(queue, 1, msg[prio][2]); + queue.Dequeue(*msg[prio][2]); + break; + } + + VerifyPriorityQueueContent(queue, 0); + } + } + + VerifyPriorityQueueContent(queue, 0); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Messages with the two different priorities (`prio1` lower than `prio2`) + + for (uint8_t prio1 = 0; prio1 < kNumPriorities - 1; prio1++) + { + for (uint8_t prio2 = prio1 + 1; prio2 < kNumPriorities; prio2++) + { + // Add one message with `prio1` and one with `prio2` and + // then remove them. Cover all possible combinations + // (order to add and remove). + + for (uint8_t test = 0; test < 4; test++) + { + switch (test) + { + case 0: + case 1: + // Add lower priority first, then higher priority + queue.Enqueue(*msg[prio1][0]); + VerifyPriorityQueueContent(queue, 1, msg[prio1][0]); + queue.Enqueue(*msg[prio2][0]); + break; + + case 2: + case 3: + // Add higher priority first, then lower priority + queue.Enqueue(*msg[prio2][0]); + VerifyPriorityQueueContent(queue, 1, msg[prio2][0]); + queue.Enqueue(*msg[prio1][0]); + break; + } + + VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio1][0]); + + switch (test) + { + case 0: + case 2: + // Remove lower priority first, then higher priority. + queue.Dequeue(*msg[prio1][0]); + VerifyPriorityQueueContent(queue, 1, msg[prio2][0]); + queue.Dequeue(*msg[prio2][0]); + break; + + case 1: + case 3: + // Remove higher priority first, then lower priority + queue.Dequeue(*msg[prio2][0]); + VerifyPriorityQueueContent(queue, 1, msg[prio1][0]); + queue.Dequeue(*msg[prio1][0]); + break; + } + + VerifyPriorityQueueContent(queue, 0); + } + + // Add two messages with `prio1` (lower) and one with + // `prio2` (higher) and then remove them. Cover all + // possible combinations to add and remove. + + for (uint8_t test = 0; test < 6; test++) + { + switch (test) + { + case 0: + case 1: + // Add two lower priority messages first, then one higher priority + queue.Enqueue(*msg[prio1][0]); + VerifyPriorityQueueContent(queue, 1, msg[prio1][0]); + queue.Enqueue(*msg[prio1][1]); + VerifyPriorityQueueContent(queue, 2, msg[prio1][0], msg[prio1][1]); + queue.Enqueue(*msg[prio2][0]); + break; + + case 2: + case 3: + // Add one higher priority first, then two lower priority messages. + queue.Enqueue(*msg[prio2][0]); + VerifyPriorityQueueContent(queue, 1, msg[prio2][0]); + queue.Enqueue(*msg[prio1][0]); + VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio1][0]); + queue.Enqueue(*msg[prio1][1]); + break; + + case 4: + case 5: + // Add one lower priority first, then a higher priority, finally one lower priority. + queue.Enqueue(*msg[prio1][0]); + VerifyPriorityQueueContent(queue, 1, msg[prio1][0]); + queue.Enqueue(*msg[prio2][0]); + VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio1][0]); + queue.Enqueue(*msg[prio1][1]); + break; + } + + VerifyPriorityQueueContent(queue, 3, msg[prio2][0], msg[prio1][0], msg[prio1][1]); + + switch (test) + { + case 0: + queue.Dequeue(*msg[prio1][0]); + VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio1][1]); + queue.Dequeue(*msg[prio1][1]); + VerifyPriorityQueueContent(queue, 1, msg[prio2][0]); + queue.Dequeue(*msg[prio2][0]); + break; + + case 1: + queue.Dequeue(*msg[prio1][0]); + VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio1][1]); + queue.Dequeue(*msg[prio2][0]); + VerifyPriorityQueueContent(queue, 1, msg[prio1][1]); + queue.Dequeue(*msg[prio1][1]); + break; + + case 2: + queue.Dequeue(*msg[prio1][1]); + VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio1][0]); + queue.Dequeue(*msg[prio1][0]); + VerifyPriorityQueueContent(queue, 1, msg[prio2][0]); + queue.Dequeue(*msg[prio2][0]); + break; + + case 3: + queue.Dequeue(*msg[prio1][1]); + VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio1][0]); + queue.Dequeue(*msg[prio2][0]); + VerifyPriorityQueueContent(queue, 1, msg[prio1][0]); + queue.Dequeue(*msg[prio1][0]); + break; + + case 4: + queue.Dequeue(*msg[prio2][0]); + VerifyPriorityQueueContent(queue, 2, msg[prio1][0], msg[prio1][1]); + queue.Dequeue(*msg[prio1][0]); + VerifyPriorityQueueContent(queue, 1, msg[prio1][1]); + queue.Dequeue(*msg[prio1][1]); + break; + + case 5: + queue.Dequeue(*msg[prio2][0]); + VerifyPriorityQueueContent(queue, 2, msg[prio1][0], msg[prio1][1]); + queue.Dequeue(*msg[prio1][1]); + VerifyPriorityQueueContent(queue, 1, msg[prio1][0]); + queue.Dequeue(*msg[prio1][0]); + break; + } + } + + VerifyPriorityQueueContent(queue, 0); + + // Add two messages with `prio2` (higher) and one with + // `prio1` (lower) and then remove them. Cover all + // possible combinations to add and remove. + + for (uint8_t test = 0; test < 6; test++) + { + switch (test) + { + case 0: + case 1: + // Add two higher priority messages first, then one lower priority + queue.Enqueue(*msg[prio2][0]); + VerifyPriorityQueueContent(queue, 1, msg[prio2][0]); + queue.Enqueue(*msg[prio2][1]); + VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio2][1]); + queue.Enqueue(*msg[prio1][0]); + break; + + case 2: + case 3: + // Add one lower priority first, then two higher priority messages. + queue.Enqueue(*msg[prio1][0]); + VerifyPriorityQueueContent(queue, 1, msg[prio1][0]); + queue.Enqueue(*msg[prio2][0]); + VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio1][0]); + queue.Enqueue(*msg[prio2][1]); + break; + + case 4: + case 5: + // Add one higher priority first, then a lower priority, finally one higher priority. + queue.Enqueue(*msg[prio2][0]); + VerifyPriorityQueueContent(queue, 1, msg[prio2][0]); + queue.Enqueue(*msg[prio1][0]); + VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio1][0]); + queue.Enqueue(*msg[prio2][1]); + break; + } + + VerifyPriorityQueueContent(queue, 3, msg[prio2][0], msg[prio2][1], msg[prio1][0]); + + switch (test) + { + case 0: + queue.Dequeue(*msg[prio2][0]); + VerifyPriorityQueueContent(queue, 2, msg[prio2][1], msg[prio1][0]); + queue.Dequeue(*msg[prio2][1]); + VerifyPriorityQueueContent(queue, 1, msg[prio1][0]); + queue.Dequeue(*msg[prio1][0]); + break; + + case 1: + queue.Dequeue(*msg[prio2][0]); + VerifyPriorityQueueContent(queue, 2, msg[prio2][1], msg[prio1][0]); + queue.Dequeue(*msg[prio1][0]); + VerifyPriorityQueueContent(queue, 1, msg[prio2][1]); + queue.Dequeue(*msg[prio2][1]); + break; + + case 2: + queue.Dequeue(*msg[prio2][1]); + VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio1][0]); + queue.Dequeue(*msg[prio2][0]); + VerifyPriorityQueueContent(queue, 1, msg[prio1][0]); + queue.Dequeue(*msg[prio1][0]); + break; + + case 3: + queue.Dequeue(*msg[prio2][1]); + VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio1][0]); + queue.Dequeue(*msg[prio1][0]); + VerifyPriorityQueueContent(queue, 1, msg[prio2][0]); + queue.Dequeue(*msg[prio2][0]); + break; + + case 4: + queue.Dequeue(*msg[prio1][0]); + VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio2][1]); + queue.Dequeue(*msg[prio2][0]); + VerifyPriorityQueueContent(queue, 1, msg[prio2][1]); + queue.Dequeue(*msg[prio2][1]); + break; + + case 5: + queue.Dequeue(*msg[prio1][0]); + VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio2][1]); + queue.Dequeue(*msg[prio2][1]); + VerifyPriorityQueueContent(queue, 1, msg[prio2][0]); + queue.Dequeue(*msg[prio2][0]); + break; + } + + VerifyPriorityQueueContent(queue, 0); + } + } + } + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Messages with the three different priorities (prio1 < prio2 < prio3) + + for (uint8_t prio1 = 0; prio1 < kNumPriorities - 2; prio1++) + { + for (uint8_t prio2 = prio1 + 1; prio2 < kNumPriorities - 1; prio2++) + { + for (uint8_t prio3 = prio2 + 1; prio3 < kNumPriorities; prio3++) + { + for (uint8_t test = 0; test < 6; test++) + { + switch (test) + { + case 0: + queue.Enqueue(*msg[prio1][0]); + VerifyPriorityQueueContent(queue, 1, msg[prio1][0]); + queue.Enqueue(*msg[prio2][0]); + VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio1][0]); + queue.Enqueue(*msg[prio3][0]); + break; + + case 1: + queue.Enqueue(*msg[prio1][0]); + VerifyPriorityQueueContent(queue, 1, msg[prio1][0]); + queue.Enqueue(*msg[prio3][0]); + VerifyPriorityQueueContent(queue, 2, msg[prio3][0], msg[prio1][0]); + queue.Enqueue(*msg[prio2][0]); + break; + + case 2: + queue.Enqueue(*msg[prio2][0]); + VerifyPriorityQueueContent(queue, 1, msg[prio2][0]); + queue.Enqueue(*msg[prio1][0]); + VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio1][0]); + queue.Enqueue(*msg[prio3][0]); + break; + + case 3: + queue.Enqueue(*msg[prio2][0]); + VerifyPriorityQueueContent(queue, 1, msg[prio2][0]); + queue.Enqueue(*msg[prio3][0]); + VerifyPriorityQueueContent(queue, 2, msg[prio3][0], msg[prio2][0]); + queue.Enqueue(*msg[prio1][0]); + break; + + case 4: + queue.Enqueue(*msg[prio3][0]); + VerifyPriorityQueueContent(queue, 1, msg[prio3][0]); + queue.Enqueue(*msg[prio1][0]); + VerifyPriorityQueueContent(queue, 2, msg[prio3][0], msg[prio1][0]); + queue.Enqueue(*msg[prio2][0]); + break; + + case 5: + queue.Enqueue(*msg[prio3][0]); + VerifyPriorityQueueContent(queue, 1, msg[prio3][0]); + queue.Enqueue(*msg[prio2][0]); + VerifyPriorityQueueContent(queue, 2, msg[prio3][0], msg[prio2][0]); + queue.Enqueue(*msg[prio1][0]); + break; + } + + VerifyPriorityQueueContent(queue, 3, msg[prio3][0], msg[prio2][0], msg[prio1][0]); + + switch (test) + { + case 0: + case 1: + case 2: + queue.Dequeue(*msg[prio1][0]); + VerifyPriorityQueueContent(queue, 2, msg[prio3][0], msg[prio2][0]); + queue.Dequeue(*msg[prio2][0]); + VerifyPriorityQueueContent(queue, 1, msg[prio3][0]); + queue.Dequeue(*msg[prio3][0]); + break; + case 3: + case 4: + case 5: + queue.Dequeue(*msg[prio3][0]); + VerifyPriorityQueueContent(queue, 2, msg[prio2][0], msg[prio1][0]); + queue.Dequeue(*msg[prio1][0]); + VerifyPriorityQueueContent(queue, 1, msg[prio2][0]); + queue.Dequeue(*msg[prio2][0]); + break; + } + + VerifyPriorityQueueContent(queue, 0); + } + } + } + } + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Add msgs in different orders and check the content of queue. - queue.Enqueue(*msgHigh[0]); - VerifyPriorityQueueContent(queue, 1, msgHigh[0]); - queue.Enqueue(*msgHigh[1]); - VerifyPriorityQueueContent(queue, 2, msgHigh[0], msgHigh[1]); - queue.Enqueue(*msgNet[0]); - VerifyPriorityQueueContent(queue, 3, msgNet[0], msgHigh[0], msgHigh[1]); - queue.Enqueue(*msgNet[1]); - VerifyPriorityQueueContent(queue, 4, msgNet[0], msgNet[1], msgHigh[0], msgHigh[1]); - queue.Enqueue(*msgHigh[2]); - VerifyPriorityQueueContent(queue, 5, msgNet[0], msgNet[1], msgHigh[0], msgHigh[1], msgHigh[2]); - queue.Enqueue(*msgLow[0]); - VerifyPriorityQueueContent(queue, 6, msgNet[0], msgNet[1], msgHigh[0], msgHigh[1], msgHigh[2], msgLow[0]); - queue.Enqueue(*msgNor[0]); - VerifyPriorityQueueContent(queue, 7, msgNet[0], msgNet[1], msgHigh[0], msgHigh[1], msgHigh[2], msgNor[0], - msgLow[0]); - queue.Enqueue(*msgHigh[3]); - VerifyPriorityQueueContent(queue, 8, msgNet[0], msgNet[1], msgHigh[0], msgHigh[1], msgHigh[2], msgHigh[3], - msgNor[0], msgLow[0]); + + queue.Enqueue(*msg[kHi][0]); + VerifyPriorityQueueContent(queue, 1, msg[kHi][0]); + queue.Enqueue(*msg[kHi][1]); + VerifyPriorityQueueContent(queue, 2, msg[kHi][0], msg[kHi][1]); + queue.Enqueue(*msg[kNw][0]); + VerifyPriorityQueueContent(queue, 3, msg[kNw][0], msg[kHi][0], msg[kHi][1]); + queue.Enqueue(*msg[kNw][1]); + VerifyPriorityQueueContent(queue, 4, msg[kNw][0], msg[kNw][1], msg[kHi][0], msg[kHi][1]); + queue.Enqueue(*msg[kHi][2]); + VerifyPriorityQueueContent(queue, 5, msg[kNw][0], msg[kNw][1], msg[kHi][0], msg[kHi][1], msg[kHi][2]); + queue.Enqueue(*msg[kLo][0]); + VerifyPriorityQueueContent(queue, 6, msg[kNw][0], msg[kNw][1], msg[kHi][0], msg[kHi][1], msg[kHi][2], msg[kLo][0]); + queue.Enqueue(*msg[kMd][0]); + VerifyPriorityQueueContent(queue, 7, msg[kNw][0], msg[kNw][1], msg[kHi][0], msg[kHi][1], msg[kHi][2], msg[kMd][0], + msg[kLo][0]); + queue.Enqueue(*msg[kHi][3]); + VerifyPriorityQueueContent(queue, 8, msg[kNw][0], msg[kNw][1], msg[kHi][0], msg[kHi][1], msg[kHi][2], msg[kHi][3], + msg[kMd][0], msg[kLo][0]); // Remove messages in different order and check the content of queue in each step. - queue.Dequeue(*msgNet[0]); - VerifyPriorityQueueContent(queue, 7, msgNet[1], msgHigh[0], msgHigh[1], msgHigh[2], msgHigh[3], msgNor[0], - msgLow[0]); - queue.Dequeue(*msgHigh[2]); - VerifyPriorityQueueContent(queue, 6, msgNet[1], msgHigh[0], msgHigh[1], msgHigh[3], msgNor[0], msgLow[0]); - queue.Dequeue(*msgNor[0]); - VerifyPriorityQueueContent(queue, 5, msgNet[1], msgHigh[0], msgHigh[1], msgHigh[3], msgLow[0]); - queue.Dequeue(*msgHigh[1]); - VerifyPriorityQueueContent(queue, 4, msgNet[1], msgHigh[0], msgHigh[3], msgLow[0]); - queue.Dequeue(*msgLow[0]); - VerifyPriorityQueueContent(queue, 3, msgNet[1], msgHigh[0], msgHigh[3]); - queue.Dequeue(*msgNet[1]); - VerifyPriorityQueueContent(queue, 2, msgHigh[0], msgHigh[3]); - queue.Dequeue(*msgHigh[0]); - VerifyPriorityQueueContent(queue, 1, msgHigh[3]); - queue.Dequeue(*msgHigh[3]); + queue.Dequeue(*msg[kNw][0]); + VerifyPriorityQueueContent(queue, 7, msg[kNw][1], msg[kHi][0], msg[kHi][1], msg[kHi][2], msg[kHi][3], msg[kMd][0], + msg[kLo][0]); + queue.Dequeue(*msg[kHi][2]); + VerifyPriorityQueueContent(queue, 6, msg[kNw][1], msg[kHi][0], msg[kHi][1], msg[kHi][3], msg[kMd][0], msg[kLo][0]); + queue.Dequeue(*msg[kMd][0]); + VerifyPriorityQueueContent(queue, 5, msg[kNw][1], msg[kHi][0], msg[kHi][1], msg[kHi][3], msg[kLo][0]); + queue.Dequeue(*msg[kHi][1]); + VerifyPriorityQueueContent(queue, 4, msg[kNw][1], msg[kHi][0], msg[kHi][3], msg[kLo][0]); + queue.Dequeue(*msg[kLo][0]); + VerifyPriorityQueueContent(queue, 3, msg[kNw][1], msg[kHi][0], msg[kHi][3]); + queue.Dequeue(*msg[kNw][1]); + VerifyPriorityQueueContent(queue, 2, msg[kHi][0], msg[kHi][3]); + queue.Dequeue(*msg[kHi][0]); + VerifyPriorityQueueContent(queue, 1, msg[kHi][3]); + queue.Dequeue(*msg[kHi][3]); VerifyPriorityQueueContent(queue, 0); + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Validate that priority of an already queued message in a priority queue cannot change - queue.Enqueue(*msgNor[0]); - VerifyPriorityQueueContent(queue, 1, msgNor[0]); - queue.Enqueue(*msgHigh[0]); - VerifyPriorityQueueContent(queue, 2, msgHigh[0], msgNor[0]); - queue.Enqueue(*msgLow[0]); - VerifyPriorityQueueContent(queue, 3, msgHigh[0], msgNor[0], msgLow[0]); + queue.Enqueue(*msg[kMd][0]); + VerifyPriorityQueueContent(queue, 1, msg[kMd][0]); + queue.Enqueue(*msg[kHi][0]); + VerifyPriorityQueueContent(queue, 2, msg[kHi][0], msg[kMd][0]); + queue.Enqueue(*msg[kLo][0]); + VerifyPriorityQueueContent(queue, 3, msg[kHi][0], msg[kMd][0], msg[kLo][0]); - VerifyOrQuit(msgNor[0]->SetPriority(Message::kPriorityNet) == kErrorInvalidState); - VerifyOrQuit(msgLow[0]->SetPriority(Message::kPriorityLow) == kErrorInvalidState); - VerifyOrQuit(msgLow[0]->SetPriority(Message::kPriorityNormal) == kErrorInvalidState); - VerifyOrQuit(msgHigh[0]->SetPriority(Message::kPriorityNormal) == kErrorInvalidState); - VerifyPriorityQueueContent(queue, 3, msgHigh[0], msgNor[0], msgLow[0]); + VerifyOrQuit(msg[kMd][0]->SetPriority(Message::kPriorityNet) == kErrorInvalidState); + VerifyOrQuit(msg[kLo][0]->SetPriority(Message::kPriorityLow) == kErrorInvalidState); + VerifyOrQuit(msg[kLo][0]->SetPriority(Message::kPriorityNormal) == kErrorInvalidState); + VerifyOrQuit(msg[kHi][0]->SetPriority(Message::kPriorityNormal) == kErrorInvalidState); + VerifyPriorityQueueContent(queue, 3, msg[kHi][0], msg[kMd][0], msg[kLo][0]); // Remove messages from the queue - queue.Dequeue(*msgHigh[0]); - VerifyPriorityQueueContent(queue, 2, msgNor[0], msgLow[0]); - queue.Dequeue(*msgLow[0]); - VerifyPriorityQueueContent(queue, 1, msgNor[0]); - queue.Dequeue(*msgNor[0]); + queue.Dequeue(*msg[kHi][0]); + VerifyPriorityQueueContent(queue, 2, msg[kMd][0], msg[kLo][0]); + queue.Dequeue(*msg[kLo][0]); + VerifyPriorityQueueContent(queue, 1, msg[kMd][0]); + queue.Dequeue(*msg[kMd][0]); VerifyPriorityQueueContent(queue, 0); - for (Message *message : msgNor) + for (Message *message : msg[kMd]) { SuccessOrQuit(message->SetPriority(Message::kPriorityNormal)); } + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Range-based `for` and dequeue during iteration for (uint16_t removeIndex = 0; removeIndex < 4; removeIndex++) { uint16_t index = 0; - queue.Enqueue(*msgNor[0]); - queue.Enqueue(*msgNor[1]); - queue.Enqueue(*msgNor[2]); - queue.Enqueue(*msgNor[3]); - VerifyPriorityQueueContent(queue, 4, msgNor[0], msgNor[1], msgNor[2], msgNor[3]); + queue.Enqueue(*msg[kMd][0]); + queue.Enqueue(*msg[kMd][1]); + queue.Enqueue(*msg[kMd][2]); + queue.Enqueue(*msg[kMd][3]); + VerifyPriorityQueueContent(queue, 4, msg[kMd][0], msg[kMd][1], msg[kMd][2], msg[kMd][3]); // While iterating over the queue remove the entry at `removeIndex` for (Message &message : queue) @@ -278,7 +675,7 @@ void TestPriorityQueue(void) queue.Dequeue(message); } - VerifyOrQuit(&message == msgNor[index++]); + VerifyOrQuit(&message == msg[kMd][index++]); } index = 0; @@ -291,7 +688,7 @@ void TestPriorityQueue(void) index++; } - VerifyOrQuit(&message == msgNor[index++]); + VerifyOrQuit(&message == msg[kMd][index++]); queue.Dequeue(message); } @@ -300,6 +697,7 @@ void TestPriorityQueue(void) testFreeInstance(instance); } +// NOLINTEND(modernize-loop-convert) } // namespace ot