[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.
This commit is contained in:
Abtin Keshavarzian
2025-06-25 13:03:43 -07:00
committed by GitHub
parent 5d1d380012
commit c55098af5e
7 changed files with 694 additions and 268 deletions
+40 -2
View File
@@ -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]);
+494 -96
View File
@@ -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<MessagePool>();
// 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<Message::Priority>(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