mirror of
https://github.com/espressif/openthread.git
synced 2026-10-02 13:57:38 +00:00
[array] add Array::InsertAt() method (#13522)
This commit adds the `InsertAt(aIndex)` method to the `Array` template class to support inserting a new element at a specific index. Specifically: - Shifts existing elements to make room for the new entry when `aIndex <= mLength` and the array is not full. - Returns a pointer to the newly inserted element for caller initialization, or `nullptr` if the array is full or `aIndex` is invalid. - Adds unit test for the `InsertAt()` in `test_array.cpp`.
This commit is contained in:
@@ -349,6 +349,55 @@ public:
|
||||
*/
|
||||
Type *PopBack(void) OT_LIFETIME_BOUND { return IsEmpty() ? nullptr : &mElements[--mLength]; }
|
||||
|
||||
/**
|
||||
* Inserts a new entry at a given index in the array.
|
||||
*
|
||||
* The method uses assignment `=` operator on `Type` to copy @p aEntry into the inserted array element. Existing
|
||||
* elements at and after @p aIndex are shifted right.
|
||||
*
|
||||
* The @p aEntry can be from the array itself. The method safely copies @p aEntry before shifting existing
|
||||
* elements in the array.
|
||||
*
|
||||
* @param[in] aIndex The index at which to insert the new element.
|
||||
* @param[in] aEntry The new entry to insert.
|
||||
*
|
||||
* @retval kErrorNone Successfully inserted @p aEntry at @p aIndex in the array.
|
||||
* @retval kErrorNoBufs Could not insert the new element since array is full.
|
||||
* @retval kErrorInvalidArgs @p aIndex is invalid (`aIndex > GetLength()`).
|
||||
*/
|
||||
Error InsertAt(IndexType aIndex, const Type &aEntry)
|
||||
{
|
||||
Error error;
|
||||
Type entry = aEntry;
|
||||
|
||||
SuccessOrExit(error = ShiftFrom(aIndex));
|
||||
mElements[aIndex] = entry;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a new element at a given index in the array.
|
||||
*
|
||||
* On success, this method shifts existing elements to make room and returns a pointer to the inserted element
|
||||
* in the array for the caller to initialize and use.
|
||||
*
|
||||
* @param[in] aIndex The index at which to insert the new element.
|
||||
*
|
||||
* @returns A pointer to the newly inserted element, or `nullptr` if the array is full or @p aIndex is invalid.
|
||||
*/
|
||||
Type *InsertAt(IndexType aIndex) OT_LIFETIME_BOUND
|
||||
{
|
||||
Type *entry = nullptr;
|
||||
|
||||
SuccessOrExit(ShiftFrom(aIndex));
|
||||
entry = &mElements[aIndex];
|
||||
|
||||
exit:
|
||||
return entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of an element in the array.
|
||||
*
|
||||
@@ -628,6 +677,24 @@ public:
|
||||
const Type *end(void) const OT_LIFETIME_BOUND { return &mElements[mLength]; }
|
||||
|
||||
private:
|
||||
Error ShiftFrom(IndexType aIndex)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
VerifyOrExit(!IsFull(), error = kErrorNoBufs);
|
||||
VerifyOrExit(aIndex <= mLength, error = kErrorInvalidArgs);
|
||||
|
||||
for (IndexType index = mLength; index > aIndex; index--)
|
||||
{
|
||||
mElements[index] = mElements[index - 1];
|
||||
}
|
||||
|
||||
mLength++;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Type mElements[kMaxSize];
|
||||
IndexType mLength;
|
||||
};
|
||||
|
||||
@@ -407,6 +407,146 @@ void TestArrayCopyAndFindMatching(void)
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void TestArrayInsertAt(void)
|
||||
{
|
||||
constexpr uint16_t kMaxSize = 6;
|
||||
|
||||
Array<uint16_t, kMaxSize> array;
|
||||
uint16_t *entry;
|
||||
|
||||
// Verify invalid insert on empty array (out-of-bounds index)
|
||||
VerifyOrQuit(array.InsertAt(1) == nullptr);
|
||||
VerifyOrQuit(array.IsEmpty());
|
||||
|
||||
// Insert at index 0 in empty array (equivalent to `PushBack`)
|
||||
entry = array.InsertAt(0);
|
||||
VerifyOrQuit(entry != nullptr);
|
||||
*entry = 20;
|
||||
VerifyOrQuit(array.GetLength() == 1);
|
||||
VerifyOrQuit(array[0] == 20);
|
||||
|
||||
// Insert at index 0 (at the beginning): array becomes [10, 20]
|
||||
entry = array.InsertAt(0);
|
||||
VerifyOrQuit(entry != nullptr);
|
||||
*entry = 10;
|
||||
VerifyOrQuit(array.GetLength() == 2);
|
||||
VerifyOrQuit(array[0] == 10);
|
||||
VerifyOrQuit(array[1] == 20);
|
||||
|
||||
// Verify invalid insert on partially filled array (index > length)
|
||||
VerifyOrQuit(array.InsertAt(3) == nullptr);
|
||||
VerifyOrQuit(array.InsertAt(kMaxSize) == nullptr);
|
||||
VerifyOrQuit(array.GetLength() == 2);
|
||||
|
||||
// Insert at index 2 (at the end): array becomes [10, 20, 40]
|
||||
entry = array.InsertAt(2);
|
||||
VerifyOrQuit(entry != nullptr);
|
||||
*entry = 40;
|
||||
VerifyOrQuit(array.GetLength() == 3);
|
||||
VerifyOrQuit(array[0] == 10);
|
||||
VerifyOrQuit(array[1] == 20);
|
||||
VerifyOrQuit(array[2] == 40);
|
||||
|
||||
// Insert at index 2 (in the middle): array becomes [10, 20, 30, 40]
|
||||
entry = array.InsertAt(2);
|
||||
VerifyOrQuit(entry != nullptr);
|
||||
*entry = 30;
|
||||
VerifyOrQuit(array.GetLength() == 4);
|
||||
VerifyOrQuit(array[0] == 10);
|
||||
VerifyOrQuit(array[1] == 20);
|
||||
VerifyOrQuit(array[2] == 30);
|
||||
VerifyOrQuit(array[3] == 40);
|
||||
|
||||
// Insert at index 1 (in the middle): array becomes [10, 15, 20, 30, 40]
|
||||
entry = array.InsertAt(1);
|
||||
VerifyOrQuit(entry != nullptr);
|
||||
*entry = 15;
|
||||
VerifyOrQuit(array.GetLength() == 5);
|
||||
VerifyOrQuit(array[0] == 10);
|
||||
VerifyOrQuit(array[1] == 15);
|
||||
VerifyOrQuit(array[2] == 20);
|
||||
VerifyOrQuit(array[3] == 30);
|
||||
VerifyOrQuit(array[4] == 40);
|
||||
|
||||
// Insert at index 5 (at the end): array becomes [10, 15, 20, 30, 40, 50]
|
||||
entry = array.InsertAt(5);
|
||||
VerifyOrQuit(entry != nullptr);
|
||||
*entry = 50;
|
||||
VerifyOrQuit(array.GetLength() == 6);
|
||||
VerifyOrQuit(array.IsFull());
|
||||
VerifyOrQuit(array[0] == 10);
|
||||
VerifyOrQuit(array[1] == 15);
|
||||
VerifyOrQuit(array[2] == 20);
|
||||
VerifyOrQuit(array[3] == 30);
|
||||
VerifyOrQuit(array[4] == 40);
|
||||
VerifyOrQuit(array[5] == 50);
|
||||
|
||||
// Verify insertion fails when array is full
|
||||
VerifyOrQuit(array.InsertAt(0) == nullptr);
|
||||
VerifyOrQuit(array.InsertAt(3) == nullptr);
|
||||
VerifyOrQuit(array.InsertAt(6) == nullptr);
|
||||
VerifyOrQuit(array.InsertAt(7) == nullptr);
|
||||
VerifyOrQuit(array.GetLength() == 6);
|
||||
|
||||
// Test `Error InsertAt(IndexType, const Type &)` overload
|
||||
array.Clear();
|
||||
VerifyOrQuit(array.InsertAt(1, 100) == kErrorInvalidArgs);
|
||||
SuccessOrQuit(array.InsertAt(0, 200));
|
||||
SuccessOrQuit(array.InsertAt(0, 100));
|
||||
SuccessOrQuit(array.InsertAt(2, 400));
|
||||
SuccessOrQuit(array.InsertAt(2, 300));
|
||||
VerifyOrQuit(array.GetLength() == 4);
|
||||
VerifyOrQuit(array[0] == 100);
|
||||
VerifyOrQuit(array[1] == 200);
|
||||
VerifyOrQuit(array[2] == 300);
|
||||
VerifyOrQuit(array[3] == 400);
|
||||
|
||||
VerifyOrQuit(array.InsertAt(5, 500) == kErrorInvalidArgs);
|
||||
SuccessOrQuit(array.InsertAt(4, 500));
|
||||
SuccessOrQuit(array.InsertAt(5, 600));
|
||||
VerifyOrQuit(array.IsFull());
|
||||
VerifyOrQuit(array.InsertAt(0, 50) == kErrorNoBufs);
|
||||
VerifyOrQuit(array.InsertAt(3, 250) == kErrorNoBufs);
|
||||
VerifyOrQuit(array.InsertAt(6, 700) == kErrorNoBufs);
|
||||
VerifyOrQuit(array.InsertAt(7, 800) == kErrorNoBufs);
|
||||
|
||||
// Test inserting an element that is from the array itself,
|
||||
// ensuring it is safely copied before existing elements are shifted.
|
||||
array.Clear();
|
||||
SuccessOrQuit(array.PushBack(100));
|
||||
SuccessOrQuit(array.PushBack(200));
|
||||
SuccessOrQuit(array.PushBack(300));
|
||||
|
||||
// Insert `array[1]` (200) at index 0: `array[1]` gets shifted right during insertion
|
||||
SuccessOrQuit(array.InsertAt(0, array[1]));
|
||||
VerifyOrQuit(array.GetLength() == 4);
|
||||
VerifyOrQuit(array[0] == 200);
|
||||
VerifyOrQuit(array[1] == 100);
|
||||
VerifyOrQuit(array[2] == 200);
|
||||
VerifyOrQuit(array[3] == 300);
|
||||
|
||||
// Insert `array[3]` (300) at index 1: `array[3]` gets shifted right during insertion
|
||||
SuccessOrQuit(array.InsertAt(1, array[3]));
|
||||
VerifyOrQuit(array.GetLength() == 5);
|
||||
VerifyOrQuit(array[0] == 200);
|
||||
VerifyOrQuit(array[1] == 300);
|
||||
VerifyOrQuit(array[2] == 100);
|
||||
VerifyOrQuit(array[3] == 200);
|
||||
VerifyOrQuit(array[4] == 300);
|
||||
|
||||
// Insert `array[0]` (200) at index 0: self-insertion at the exact index
|
||||
SuccessOrQuit(array.InsertAt(0, array[0]));
|
||||
VerifyOrQuit(array.GetLength() == 6);
|
||||
VerifyOrQuit(array[0] == 200);
|
||||
VerifyOrQuit(array[1] == 200);
|
||||
VerifyOrQuit(array[2] == 300);
|
||||
VerifyOrQuit(array[3] == 100);
|
||||
VerifyOrQuit(array[4] == 200);
|
||||
VerifyOrQuit(array[5] == 300);
|
||||
|
||||
printf("TestArrayInsertAt PASSED\n\n");
|
||||
}
|
||||
|
||||
void TestArrayIndexType(void)
|
||||
{
|
||||
typedef Array<uint16_t, 255> Array1;
|
||||
@@ -424,6 +564,7 @@ int main(void)
|
||||
{
|
||||
ot::TestArray();
|
||||
ot::TestArrayCopyAndFindMatching();
|
||||
ot::TestArrayInsertAt();
|
||||
ot::TestArrayIndexType();
|
||||
|
||||
printf("All tests passed\n");
|
||||
|
||||
Reference in New Issue
Block a user