[linked-list] allow use of Matches() with variable number of arguments (#11065)

This commit updates `LinkedList` and `OwningList` to enhance
`FindMatching()`, `RemoveMatching()`, and related methods to use
`Matches()` with a variable number of arguments. The implementation
uses a variadic template function and forwarding references.
This commit is contained in:
Abtin Keshavarzian
2024-12-23 18:23:06 -08:00
committed by GitHub
parent e9f45cb997
commit 588e93cd15
8 changed files with 92 additions and 100 deletions
+52 -60
View File
@@ -251,22 +251,21 @@ public:
}
/**
* Indicates whether the linked list contains an entry matching a given entry indicator.
* Indicates whether the linked list contains an entry matching a set of conditions.
*
* 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:
* To check that an entry matches, the `Matches()` method is invoked on each `Type` entry in the list. The
* `Matches()` method with the same set of `Args` input types should be provided by the `Type` class accordingly:
*
* bool Type::Matches(const Indicator &aIndicator) const
* bool Type::Matches(const Args &...) const
*
* @param[in] aIndicator An entry indicator to match against entries in the list.
* @param[in] aArgs The args to pass to `Matches()`.
*
* @retval TRUE The linked list contains an entry matching @p aIndicator.
* @retval FALSE The linked list contains no entry matching @p aIndicator.
* @retval TRUE The linked list contains a matching entry.
* @retval FALSE The linked list does not contain a matching entry.
*/
template <typename Indicator> bool ContainsMatching(const Indicator &aIndicator) const
template <typename... Args> bool ContainsMatching(const Args &...aArgs) const
{
return FindMatching(aIndicator) != nullptr;
return FindMatching(aArgs...) != nullptr;
}
/**
@@ -318,27 +317,25 @@ public:
}
/**
* Removes an entry matching a given entry indicator from the linked list.
* Removes an entry matching a given set of conditions from the linked 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:
* To check that an entry matches, the `Matches()` method is invoked on each `Type` entry in the list. The
* `Matches()` method with the same set of `Args` input types should be provided by the `Type` class accordingly:
*
* bool Type::Matches(const Indicator &aIndicator) const
* bool Type::Matches(const Args &...) const
*
* @note This method does not change the removed entry itself (which is returned in case of success), i.e., the
* entry next pointer stays as before.
*
*
* @param[in] aIndicator An entry indicator to match against entries in the list.
* @param[in] aArgs The args to pass to `Matches()`.
*
* @returns A pointer to the removed matching entry if one could be found, or `nullptr` if no matching entry is
* found.
*/
template <typename Indicator> Type *RemoveMatching(const Indicator &aIndicator)
template <typename... Args> Type *RemoveMatching(const Args &...aArgs)
{
Type *prev;
Type *entry = FindMatchingWithPrev(prev, aIndicator);
Type *entry = FindMatchingWithPrev(prev, aArgs...);
if (entry != nullptr)
{
@@ -352,16 +349,15 @@ public:
* 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:
* To check that an entry matches, the `Matches()` method is invoked on each `Type` entry in the list. The
* `Matches()` method with the same set of `Args` input types should be provided by the `Type` class accordingly:
*
* bool Type::Matches(const Indicator &aIndicator) const
* bool Type::Matches(const Args &...) 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.
* @param[in] aArgs The args to pass to `Matches()`.
*/
template <typename Indicator> void RemoveAllMatching(const Indicator &aIndicator, LinkedList &aRemovedList)
template <typename... Args> void RemoveAllMatching(LinkedList &aRemovedList, const Args &...aArgs)
{
Type *entry;
Type *prev;
@@ -371,7 +367,7 @@ public:
{
next = entry->GetNext();
if (entry->Matches(aIndicator))
if (entry->Matches(aArgs...))
{
PopAfter(prev);
aRemovedList.Push(*entry);
@@ -432,24 +428,23 @@ public:
}
/**
* Searches within the linked list to find an entry matching a given indicator.
* Searches within the linked list to find an entry matching a set of conditions, and if found also returns a
* pointer to its previous entry in the 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:
* To check that an entry matches, the `Matches()` method is invoked on each `Type` entry in the list. The
* `Matches()` method with the same set of `Args` input types should be provided by the `Type` class accordingly:
*
* bool Type::Matches(const Indicator &aIndicator) const
* bool Type::Matches(const Args &...) const
*
* @param[out] aPrevEntry A pointer to output the previous entry on success (when a match is found in the list).
* @p aPrevEntry is set to `nullptr` if the matching entry is the head of the list.
* Otherwise it is updated to point to the previous entry before the matching entry in the
* list.
* @param[in] aIndicator An indicator to match with entries in the list.
* @param[in] aArgs The args to pass to `Matches()`.
*
* @returns A pointer to the matching entry if one is found, or `nullptr` if no matching entry was found.
*/
template <typename Indicator>
const Type *FindMatchingWithPrev(const Type *&aPrevEntry, const Indicator &aIndicator) const
template <typename... Args> const Type *FindMatchingWithPrev(const Type *&aPrevEntry, Args &&...aArgs) const
{
const Type *entry;
@@ -457,7 +452,7 @@ public:
for (entry = mHead; entry != nullptr; aPrevEntry = entry, entry = entry->GetNext())
{
if (entry->Matches(aIndicator))
if (entry->Matches(aArgs...))
{
break;
}
@@ -467,64 +462,61 @@ public:
}
/**
* Searches within the linked list to find an entry matching a given indicator, and if found
* returns a pointer to its previous entry in the list.
* Searches within the linked list to find an entry matching a set of conditions, and if found also returns a
* pointer to its previous entry in the 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:
* To check that an entry matches, the `Matches()` method is invoked on each `Type` entry in the list. The
* `Matches()` method with the same set of `Args` input types should be provided by the `Type` class accordingly:
*
* bool Type::Matches(const Indicator &aIndicator) const
* bool Type::Matches(const Args &...) const
*
* @param[out] aPrevEntry A pointer to output the previous entry on success (when a match is found in the list).
* @p aPrevEntry is set to `nullptr` if the matching entry is the head of the list.
* Otherwise it is updated to point to the previous entry before the matching entry in the
* list.
* @param[in] aIndicator An indicator to match with entries in the list.
* @param[in] aArgs The args to pass to `Matches()`.
*
* @returns A pointer to the matching entry if one is found, or `nullptr` if no matching entry was found.
*/
template <typename Indicator> Type *FindMatchingWithPrev(Type *&aPrevEntry, const Indicator &aIndicator)
template <typename... Args> Type *FindMatchingWithPrev(Type *&aPrevEntry, Args &&...aArgs)
{
return AsNonConst(AsConst(this)->FindMatchingWithPrev(const_cast<const Type *&>(aPrevEntry), aIndicator));
return AsNonConst(AsConst(this)->FindMatchingWithPrev(const_cast<const Type *&>(aPrevEntry), aArgs...));
}
/**
* Searches within the linked list to find an entry matching a given indicator.
* Searches within the linked list to find an entry matching a set of conditions.
*
* 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:
* To check that an entry matches, the `Matches()` method is invoked on each `Type` entry in the list. The
* `Matches()` method with the same set of `Args` input types should be provided by the `Type` class accordingly:
*
* bool Type::Matches(const Indicator &aIndicator) const
* bool Type::Matches(const Args &...) const
*
* @param[in] aIndicator An indicator to match with entries in the list.
* @param[in] aArgs The args to pass to `Matches()`.
*
* @returns A pointer to the matching entry if one is found, or `nullptr` if no matching entry was found.
*/
template <typename Indicator> const Type *FindMatching(const Indicator &aIndicator) const
template <typename... Args> const Type *FindMatching(const Args &...aArgs) const
{
const Type *prev;
return FindMatchingWithPrev(prev, aIndicator);
return FindMatchingWithPrev(prev, aArgs...);
}
/**
* Searches within the linked list to find an entry matching a given indicator.
* Searches within the linked list to find an entry matching a set of conditions.
*
* 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:
* To check that an entry matches, the `Matches()` method is invoked on each `Type` entry in the list. The
* `Matches()` method with the same set of `Args` input types should be provided by the `Type` class accordingly:
*
* bool Type::Matches(const Indicator &aIndicator) const
* bool Type::Matches(const Args &...) const
*
* @param[in] aIndicator An indicator to match with entries in the list.
* @param[in] aArgs The args to pass to `Matches()`.
*
* @returns A pointer to the matching entry if one is found, or `nullptr` if no matching entry was found.
*/
template <typename Indicator> Type *FindMatching(const Indicator &aIndicator)
template <typename... Args> Type *FindMatching(const Args &...aArgs)
{
return AsNonConst(AsConst(this)->FindMatching(aIndicator));
return AsNonConst(AsConst(this)->FindMatching(aArgs...));
}
/**
+21 -25
View File
@@ -101,65 +101,61 @@ public:
OwnedPtr<Type> PopAfter(Type *aPrevEntry) { return OwnedPtr<Type>(LinkedList<Type>::PopAfter(aPrevEntry)); }
/**
* Removes an entry matching a given entry indicator from the linked list.
* Removes an entry matching a given set of conditions from the linked 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:
* To check that an entry matches, the `Matches()` method is invoked on each `Type` entry in the list. The
* `Matches()` method with the same set of `Args` input types should be provided by the `Type` class accordingly:
*
* bool Type::Matches(const Indicator &aIndicator) const
* bool Type::Matches(const Args &...) const
*
* @note This method does not change the removed entry itself (which is returned in case of success), i.e., the
* entry next pointer stays as before.
*
* @param[in] aIndicator An entry indicator to match against entries in the list.
* @param[in] aArgs The args to pass to `Matches()`.
*
* @returns An `OwnedPtr` to the entry that was removed (set to null if there is no matching entry to remove).
*/
template <typename Indicator> OwnedPtr<Type> RemoveMatching(const Indicator &aIndicator)
template <typename... Args> OwnedPtr<Type> RemoveMatching(const Args &...aArgs)
{
return OwnedPtr<Type>(LinkedList<Type>::RemoveMatching(aIndicator));
return OwnedPtr<Type>(LinkedList<Type>::RemoveMatching(aArgs...));
}
/**
* Removes all entries in the list matching a given entry indicator from the list and adds
* them to a new list.
* Removes all entries in the list matching given set of conditions 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:
* To check that an entry matches, the `Matches()` method is invoked on each `Type` entry in the list. The
* `Matches()` method with the same set of `Args` input types should be provided by the `Type` class accordingly:
*
* bool Type::Matches(const Indicator &aIndicator) const
* bool Type::Matches(const Args &...) 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.
* @param[in] aArgs The args to pass to `Matches()`.
*/
template <typename Indicator> void RemoveAllMatching(const Indicator &aIndicator, OwningList &aRemovedList)
template <typename... Args> void RemoveAllMatching(OwningList &aRemovedList, const Args &...aArgs)
{
LinkedList<Type>::RemoveAllMatching(aIndicator, aRemovedList);
LinkedList<Type>::RemoveAllMatching(aRemovedList, aArgs...);
}
/**
* Removes and frees all entries in the list matching a given entry indicator.
* Removes and frees all entries in the list matching a given set of conditions.
*
* 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:
* To check that an entry matches, the `Matches()` method is invoked on each `Type` entry in the list. The
* `Matches()` method with the same set of `Args` input types should be provided by the `Type` class accordingly:
*
* bool Type::Matches(const Indicator &aIndicator) const
* bool Type::Matches(const Args &...) const
*
* @param[in] aIndicator An entry indicator to match against entries in the list.
* @param[in] aArgs The args to pass to `Matches()`.
*
* @retval TRUE At least one matching entry was removed.
* @retval FALSE No matching entry was found.
*/
template <typename Indicator> bool RemoveAndFreeAllMatching(const Indicator &aIndicator)
template <typename... Args> bool RemoveAndFreeAllMatching(const Args &...aArgs)
{
OwningList removedList;
RemoveAllMatching(aIndicator, removedList);
RemoveAllMatching(removedList, aArgs...);
return !removedList.IsEmpty();
}
};
+2 -2
View File
@@ -4276,7 +4276,7 @@ void Core::MultiPacketRxMessages::HandleTimer(void)
NextFireTime nextTime;
OwningList<RxMsgEntry> expiredEntries;
mRxMsgEntries.RemoveAllMatching(ExpireChecker(nextTime.GetNow()), expiredEntries);
mRxMsgEntries.RemoveAllMatching(expiredEntries, ExpireChecker(nextTime.GetNow()));
for (RxMsgEntry &expiredEntry : expiredEntries)
{
@@ -5445,7 +5445,7 @@ void Core::BrowseCache::ProcessExpiredRecords(TimeMilli aNow)
{
OwningList<PtrEntry> expiredEntries;
mPtrEntries.RemoveAllMatching(ExpireChecker(aNow), expiredEntries);
mPtrEntries.RemoveAllMatching(expiredEntries, ExpireChecker(aNow));
for (PtrEntry &exiredEntry : expiredEntries)
{
+1 -1
View File
@@ -341,7 +341,7 @@ uint16_t Translator::ReleaseExpiredMappings(void)
{
LinkedList<AddressMapping> idleMappings;
mActiveAddressMappings.RemoveAllMatching(TimerMilli::GetNow(), idleMappings);
mActiveAddressMappings.RemoveAllMatching(idleMappings, TimerMilli::GetNow());
return ReleaseMappings(idleMappings);
}
+2 -2
View File
@@ -1252,7 +1252,7 @@ void AdvertisingProxy::HandleTimer(void)
VerifyOrExit(mState == kStateRunning);
mAdvInfoList.RemoveAllMatching(AdvInfo::ExpirationChecker(nextTime.GetNow()), expiredList);
mAdvInfoList.RemoveAllMatching(expiredList, AdvInfo::ExpirationChecker(nextTime.GetNow()));
for (AdvInfo &adv : mAdvInfoList)
{
@@ -1281,7 +1281,7 @@ void AdvertisingProxy::HandleTasklet(void)
{
OwningList<AdvInfo> completedList;
mAdvInfoList.RemoveAllMatching(AdvInfo::CompletionChecker(), completedList);
mAdvInfoList.RemoveAllMatching(completedList, AdvInfo::CompletionChecker());
VerifyOrExit(!completedList.IsEmpty());
+1 -1
View File
@@ -1959,7 +1959,7 @@ void Client::HandleUpdateDone(void)
void Client::GetRemovedServices(LinkedList<Service> &aRemovedServices)
{
mServices.RemoveAllMatching(kRemoved, aRemovedServices);
mServices.RemoveAllMatching(aRemovedServices, kRemoved);
}
Error Client::ReadResourceRecord(const Message &aMessage, uint16_t &aOffset, Dns::ResourceRecord &aRecord)
+1 -1
View File
@@ -151,7 +151,7 @@ void LinkMetricsManager::UpdateLinkMetricsStates(void)
{
LinkedList<Subject> staleSubjects;
mSubjectList.RemoveAllMatching(*this, staleSubjects);
mSubjectList.RemoveAllMatching(staleSubjects, *this);
while (!staleSubjects.IsEmpty())
{
+12 -8
View File
@@ -69,6 +69,7 @@ public:
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; }
bool Matches(Type aType, uint16_t aId) const { return (mType == aType) && (mId == aId); }
void Free(void) { mWasFreed = true; }
void ResetTestFlags(void) { mWasFreed = false; }
@@ -182,8 +183,11 @@ void TestLinkedList(void)
VerifyOrQuit(prev == &c);
VerifyOrQuit(list.FindMatchingWithPrev(prev, a.GetId()) == &a);
VerifyOrQuit(prev == &b);
VerifyOrQuit(list.FindMatchingWithPrev(prev, kAlphaType, b.GetId()) == &b);
VerifyOrQuit(prev == &c);
VerifyOrQuit(list.FindMatchingWithPrev(prev, e.GetId()) == nullptr, "succeeded for a missing entry");
VerifyOrQuit(list.FindMatchingWithPrev(prev, e.GetName()) == nullptr, "succeeded for a missing entry");
VerifyOrQuit(list.FindMatchingWithPrev(prev, kBetaType, 2) == nullptr, "succeeded for a missing entry");
list.SetHead(&e);
VerifyLinkedListContent(&list, &e, &d, &c, &b, &a, nullptr);
@@ -265,21 +269,21 @@ void TestLinkedList(void)
list.Push(a);
VerifyLinkedListContent(&list, &a, &b, &c, &d, &e, &f, nullptr);
list.RemoveAllMatching(kAlphaType, removedList);
list.RemoveAllMatching(removedList, kAlphaType);
VerifyLinkedListContent(&list, &c, &d, &f, nullptr);
VerifyLinkedListContent(&removedList, &e, &b, &a, nullptr);
removedList.Clear();
list.RemoveAllMatching(kAlphaType, removedList);
list.RemoveAllMatching(removedList, kAlphaType);
VerifyLinkedListContent(&list, &c, &d, &f, nullptr);
VerifyOrQuit(removedList.IsEmpty());
list.RemoveAllMatching(kBetaType, removedList);
list.RemoveAllMatching(removedList, kBetaType);
VerifyOrQuit(list.IsEmpty());
VerifyLinkedListContent(&removedList, &f, &d, &c, nullptr);
removedList.Clear();
list.RemoveAllMatching(kAlphaType, removedList);
list.RemoveAllMatching(removedList, kAlphaType);
VerifyOrQuit(list.IsEmpty());
VerifyOrQuit(removedList.IsEmpty());
@@ -291,7 +295,7 @@ void TestLinkedList(void)
list.Push(a);
VerifyLinkedListContent(&list, &a, &b, &c, &d, &e, &f, nullptr);
list.RemoveAllMatching(kBetaType, removedList);
list.RemoveAllMatching(removedList, kBetaType);
VerifyLinkedListContent(&list, &a, &b, &e, nullptr);
VerifyLinkedListContent(&removedList, &f, &d, &c, nullptr);
@@ -419,18 +423,18 @@ void TestOwningList(void)
list.Push(f);
VerifyLinkedListContent(&list, &f, &e, &d, &c, &b, &a, nullptr);
list.RemoveAllMatching(kAlphaType, removedList);
list.RemoveAllMatching(removedList, kAlphaType);
VerifyLinkedListContent(&list, &f, &d, &c, nullptr);
VerifyLinkedListContent(&removedList, &a, &b, &e, nullptr);
VerifyOrQuit(!a.WasFreed());
VerifyOrQuit(!c.WasFreed());
removedList.Clear();
list.RemoveAllMatching(kAlphaType, removedList);
list.RemoveAllMatching(removedList, kAlphaType);
VerifyOrQuit(removedList.IsEmpty());
VerifyLinkedListContent(&list, &f, &d, &c, nullptr);
list.RemoveAllMatching(kBetaType, removedList);
list.RemoveAllMatching(removedList, kBetaType);
VerifyOrQuit(list.IsEmpty());
VerifyLinkedListContent(&removedList, &c, &d, &f, nullptr);
VerifyOrQuit(!c.WasFreed());