diff --git a/src/core/common/array.hpp b/src/core/common/array.hpp index ded006f93..9683dd619 100644 --- a/src/core/common/array.hpp +++ b/src/core/common/array.hpp @@ -310,6 +310,27 @@ public: */ IndexType IndexOf(const Type &aElement) const { return static_cast(&aElement - &mElements[0]); } + /** + * This method removes an element from the array. + * + * The @p aElement MUST be from the array, otherwise the behavior of this method is undefined. + * + * To remove @p aElement, it is replaced by the last element in array, so the order of items in the array can + * change after a call to this method. + * + * The method uses assignment `=` operator on `Type` to copy the last element in place of @p aElement. + * + */ + void Remove(Type &aElement) + { + Type *lastElement = PopBack(); + + if (lastElement != &aElement) + { + aElement = *lastElement; + } + } + /** * This method finds the first match of a given entry in the array. * @@ -430,6 +451,32 @@ public: return FindMatching(aIndicator) != nullptr; } + /** + * This template method removes the first element in the array matching a given indicator. + * + * This method behaves similar to `Remove()`, i.e., the matched element (if found) is replaced with the last element + * in the array (using `=` operator on `Type`). So the order of items in the array can change after a call to this + * method. + * + * The template type `Indicator` specifies the type of @p aIndicator object which is used to match against elements + * in the array. To check that an element matches the given indicator, the `Matches()` method is invoked on each + * `Type` element in the array. The `Matches()` method should be provided by `Type` class accordingly: + * + * bool Type::Matches(const Indicator &aIndicator) const + * + * @param[in] aIndicator An indicator to match with elements in the array. + * + */ + template void RemoveMatching(const Indicator &aIndicator) + { + Type *entry = FindMatching(aIndicator); + + if (entry != nullptr) + { + Remove(*entry); + } + } + /** * This method overloads assignment `=` operator to copy elements from another array into the array. * diff --git a/tests/unit/test_array.cpp b/tests/unit/test_array.cpp index 5b1e12783..a3fb1d5d9 100644 --- a/tests/unit/test_array.cpp +++ b/tests/unit/test_array.cpp @@ -35,6 +35,7 @@ #include "common/array.hpp" #include "common/debug.hpp" +#include "common/equatable.hpp" #include "common/instance.hpp" #include "common/type_traits.hpp" @@ -175,7 +176,7 @@ void TestArrayCopyAndFindMatching(void) { constexpr uint16_t kMaxSize = 10; - struct Entry + struct Entry : public Unequatable { Entry(void) = default; @@ -185,7 +186,7 @@ void TestArrayCopyAndFindMatching(void) { } - bool operator==(const Entry &aOther) { return (mName == aOther.mName) && (mYear == aOther.mYear); } + bool operator==(const Entry &aOther) const { return (mName == aOther.mName) && (mYear == aOther.mYear); } bool Matches(const char *aName) const { return strcmp(aName, mName) == 0; } bool Matches(uint16_t aYear) const { return aYear == mYear; } @@ -271,6 +272,51 @@ void TestArrayCopyAndFindMatching(void) VerifyOrQuit(array2.FindMatching(static_cast(2001)) == nullptr); VerifyOrQuit(!array2.ContainsMatching(static_cast(2001))); + // Test removing of entries at every index. + + array1 = array2; + + for (const Entry &entryToRemove : array1) + { + Entry *match; + + // Test `Remove()` + + array2 = array1; + match = array2.Find(entryToRemove); + VerifyOrQuit(match != nullptr); + array2.Remove(*match); + + VerifyOrQuit(array2.GetLength() == array1.GetLength() - 1); + + for (const Entry &entry : array2) + { + VerifyOrQuit(entry != entryToRemove); + VerifyOrQuit(array1.Contains(entry)); + } + + // Test `RemoveMatching()` + + array2 = array1; + array2.RemoveMatching(entryToRemove.mName); + + printf("\nArray after `RemoveMatching()` on entry %s\n", entryToRemove.mName); + + VerifyOrQuit(array2.GetLength() == array1.GetLength() - 1); + + for (const Entry &entry : array2) + { + printf("- Name:%-3s Year:%d\n", entry.mName, entry.mYear); + VerifyOrQuit(entry != entryToRemove); + VerifyOrQuit(array1.Contains(entry)); + } + + // Test `RemoveMatchin()` with a non-existing match + + array2.RemoveMatching(entryToRemove.mName); + VerifyOrQuit(array2.GetLength() == array1.GetLength() - 1); + } + printf("\n"); }