[linked-list] add RemoveAllMatching() method (#7221)

This commit adds a new method `LinkedList::RemoveAllMatching()` which
removes all entries in the list matching a given entry indicator from
the list and adds them to a new "removed" list. A similar method is
also added in `OwningList`. This commit also updates the unit test
`test_linked_list` to validate the behavior of the new method.
This commit is contained in:
Abtin Keshavarzian
2021-12-07 14:43:01 -08:00
committed by Jonathan Hui
parent 8048839206
commit 8650e15a37
3 changed files with 116 additions and 2 deletions
+39
View File
@@ -349,6 +349,45 @@ public:
return entry;
}
/**
* This template method removes all entries in the list matching a given entry indicator from the list and adds
* them to a new list.
*
* The template type `Indicator` specifies the type of @p aIndicator object which is used to match against entries
* in the list. To check that an entry matches the given indicator, the `Matches()` method is invoked on each
* `Type` entry in the list. The `Matches()` method should be provided by `Type` class accordingly:
*
* bool Type::Matches(const Indicator &aIndicator) const
*
* @param[in] aIndicator An entry indicator to match against entries in the list.
* @param[in] aRemovedList The list to add the removed entries to.
*
*/
template <typename Indicator> void RemoveAllMatching(const Indicator &aIndicator, LinkedList &aRemovedList)
{
Type *entry;
Type *prev;
Type *next;
for (prev = nullptr, entry = GetHead(); entry != nullptr; entry = next)
{
next = entry->GetNext();
if (entry->Matches(aIndicator))
{
PopAfter(prev);
aRemovedList.Push(*entry);
// When the entry is removed from the list
// we keep the `prev` pointer same as before.
}
else
{
prev = entry;
}
}
}
/**
* This method searches within the linked list to find an entry and if found returns a pointer to previous entry.
*
+21
View File
@@ -128,6 +128,27 @@ public:
{
return OwnedPtr<Type>(LinkedList<Type>::RemoveMatching(aIndicator));
}
/**
* This template method removes all entries in the list matching a given entry indicator from the list and adds
* them to a new list.
*
* The template type `Indicator` specifies the type of @p aIndicator object which is used to match against entries
* in the list. To check that an entry matches the given indicator, the `Matches()` method is invoked on each
* `Type` entry in the list. The `Matches()` method should be provided by `Type` class accordingly:
*
* bool Type::Matches(const Indicator &aIndicator) const
*
* The ownership of the removed entries is transferred from the original list to the @p aRemovedList.
*
* @param[in] aIndicator An entry indicator to match against entries in the list.
* @param[in] aRemovedList The list to add the removed entries to.
*
*/
template <typename Indicator> void RemoveAllMatching(const Indicator &aIndicator, OwningList &aRemovedList)
{
RemoveAllMatching(aIndicator, aRemovedList);
}
};
} // namespace ot
+56 -2
View File
@@ -50,9 +50,16 @@ struct EntryBase
struct Entry : public EntryBase, LinkedListEntry<Entry>
{
public:
Entry(const char *aName, uint16_t aId)
enum class Type : uint8_t
{
kAlpha,
kBeta,
};
Entry(const char *aName, uint16_t aId, Type aType = Type::kAlpha)
: mName(aName)
, mId(aId)
, mType(aType)
, mWasFreed(false)
{
}
@@ -61,6 +68,7 @@ public:
uint16_t GetId(void) const { return mId; }
bool Matches(const char *aName) const { return strcmp(mName, aName) == 0; }
bool Matches(uint16_t aId) const { return mId == aId; }
bool Matches(Type aType) const { return mType == aType; }
void Free(void) { mWasFreed = true; }
void ResetTestFlags(void) { mWasFreed = false; }
@@ -69,9 +77,13 @@ public:
private:
const char *mName;
uint16_t mId;
Type mType;
bool mWasFreed;
};
constexpr Entry::Type kAlphaType = Entry::Type::kAlpha;
constexpr Entry::Type kBetaType = Entry::Type::kBeta;
// This function verifies the content of the linked list matches a given list of entries.
void VerifyLinkedListContent(const LinkedList<Entry> *aList, ...)
{
@@ -120,9 +132,11 @@ void VerifyLinkedListContent(const LinkedList<Entry> *aList, ...)
void TestLinkedList(void)
{
Entry a("a", 1), b("b", 2), c("c", 3), d("d", 4), e("e", 5);
Entry a("a", 1, kAlphaType), b("b", 2, kAlphaType), c("c", 3, kBetaType);
Entry d("d", 4, kBetaType), e("e", 5, kAlphaType), f("f", 6, kBetaType);
Entry * prev;
LinkedList<Entry> list;
LinkedList<Entry> removedList;
printf("TestLinkedList\n");
@@ -240,6 +254,46 @@ void TestLinkedList(void)
VerifyOrQuit(list.FindMatching(c.GetId(), prev) == nullptr, "succeeded when empty");
VerifyOrQuit(list.RemoveMatching(a.GetName()) == nullptr, "succeeded when empty");
VerifyOrQuit(list.Remove(a) == kErrorNotFound, "succeeded when empty");
list.Clear();
removedList.Clear();
list.Push(f);
list.Push(e);
list.Push(d);
list.Push(c);
list.Push(b);
list.Push(a);
VerifyLinkedListContent(&list, &a, &b, &c, &d, &e, &f, nullptr);
list.RemoveAllMatching(kAlphaType, removedList);
VerifyLinkedListContent(&list, &c, &d, &f, nullptr);
VerifyLinkedListContent(&removedList, &e, &b, &a, nullptr);
removedList.Clear();
list.RemoveAllMatching(kAlphaType, removedList);
VerifyLinkedListContent(&list, &c, &d, &f, nullptr);
VerifyOrQuit(removedList.IsEmpty());
list.RemoveAllMatching(kBetaType, removedList);
VerifyOrQuit(list.IsEmpty());
VerifyLinkedListContent(&removedList, &f, &d, &c, nullptr);
removedList.Clear();
list.RemoveAllMatching(kAlphaType, removedList);
VerifyOrQuit(list.IsEmpty());
VerifyOrQuit(removedList.IsEmpty());
list.Push(f);
list.Push(e);
list.Push(d);
list.Push(c);
list.Push(b);
list.Push(a);
VerifyLinkedListContent(&list, &a, &b, &c, &d, &e, &f, nullptr);
list.RemoveAllMatching(kBetaType, removedList);
VerifyLinkedListContent(&list, &a, &b, &e, nullptr);
VerifyLinkedListContent(&removedList, &f, &d, &c, nullptr);
}
void TestOwningList(void)