[array] select the index/length uint type based on array size (#6872)

This commit enhances the template `Array` class implementation to
allow the `uint` type used for array size (which is also used for
length and index) to be specified as a template type parameter. If
not explicitly specified, a default `uint` type is selected based on
the array size `kMaxSize`, i.e., if `kMaxSize <= 255` then `uint8_t`
will be used, otherwise `uint16_t` will be used.
This commit is contained in:
Abtin Keshavarzian
2021-07-31 09:35:14 -07:00
committed by Jonathan Hui
parent cebba034c3
commit 75c525bac8
3 changed files with 69 additions and 15 deletions
+31 -12
View File
@@ -38,19 +38,38 @@
#include "common/code_utils.hpp"
#include "common/error.hpp"
#include "common/numeric_limits.hpp"
#include "common/type_traits.hpp"
namespace ot {
/**
* This template class represents an array of elements with a fixed max size.
*
* @tparam Type The array item type.
* @tparam Type The array element type.
* @tparam kMaxSize Specifies the max array size (maximum number of elements in the array).
* @tparam SizeType The type to be used for array size, length, and index. If not specified, a default `uint` type
* is determined based on `kMaxSize`, i.e., if `kMaxSize <= 255` then `uint8_t` will be used,
* otherwise `uint16_t` will be used.
*
*/
template <class Type, uint16_t kMaxSize> class Array
template <typename Type,
uint16_t kMaxSize,
typename SizeType =
typename TypeTraits::Conditional<kMaxSize <= NumericLimits<uint8_t>::kMax, uint8_t, uint16_t>::Type>
class Array
{
static_assert(kMaxSize != 0, "Array `kMaxSize` cannot be zero");
public:
/**
* This type represents the length or index in array.
*
* It is typically either `uint8_t` or `uint16_t` (determined based on the maximum array size (`kMaxSize`)).
*
*/
typedef SizeType IndexType;
/**
* This constructor initializes the array as empty.
*
@@ -93,7 +112,7 @@ public:
* @retval FALSE when array is not full.
*
*/
bool IsFull(void) const { return (mLength == kMaxSize); }
bool IsFull(void) const { return (mLength == GetMaxSize()); }
/**
* This method returns the maximum array size (max number of elements).
@@ -101,7 +120,7 @@ public:
* @returns The maximum array size (max number of elements that can be added to the array).
*
*/
uint16_t GetMaxSize(void) const { return kMaxSize; }
IndexType GetMaxSize(void) const { return static_cast<IndexType>(kMaxSize); }
/**
* This method returns the current length of array (number of elements).
@@ -109,7 +128,7 @@ public:
* @returns The current array length.
*
*/
uint16_t GetLength(void) const { return mLength; }
IndexType GetLength(void) const { return mLength; }
/**
* This method overloads the `[]` operator to get the element at a given index.
@@ -121,7 +140,7 @@ public:
* @returns A reference to the element in array at @p aIndex.
*
*/
Type &operator[](uint16_t aIndex) { return mElements[aIndex]; }
Type &operator[](IndexType aIndex) { return mElements[aIndex]; }
/**
* This method overloads the `[]` operator to get the element at a given index.
@@ -133,7 +152,7 @@ public:
* @returns A reference to the element in array at @p aIndex.
*
*/
const Type &operator[](uint16_t aIndex) const { return mElements[aIndex]; }
const Type &operator[](IndexType aIndex) const { return mElements[aIndex]; }
/**
* This method gets a pointer to the element at a given index.
@@ -145,7 +164,7 @@ public:
* @returns A pointer to element in array at @p aIndex or `nullptr` if @p aIndex is not valid.
*
*/
Type *At(uint16_t aIndex) { return (aIndex < mLength) ? &mElements[aIndex] : nullptr; }
Type *At(IndexType aIndex) { return (aIndex < mLength) ? &mElements[aIndex] : nullptr; }
/**
* This method gets a pointer to the element at a given index.
@@ -157,7 +176,7 @@ public:
* @returns A pointer to element in array at @p aIndex or `nullptr` if @p aIndex is not valid.
*
*/
const Type *At(uint16_t aIndex) const { return (aIndex < mLength) ? &mElements[aIndex] : nullptr; }
const Type *At(IndexType aIndex) const { return (aIndex < mLength) ? &mElements[aIndex] : nullptr; }
/**
* This method gets a pointer to the element at the front of the array (first element).
@@ -233,7 +252,7 @@ public:
* @returns The index of @p aElement in the array.
*
*/
uint16_t IndexOf(const Type &aElement) const { return static_cast<uint16_t>(&aElement - &mElements[0]); }
IndexType IndexOf(const Type &aElement) const { return static_cast<IndexType>(&aElement - &mElements[0]); }
/**
* This method finds the first match of a given entry in the array.
@@ -317,8 +336,8 @@ public:
const Type *end(void) const { return &mElements[mLength]; }
private:
Type mElements[kMaxSize];
uint16_t mLength;
Type mElements[kMaxSize];
IndexType mLength;
};
} // namespace ot
+21
View File
@@ -104,6 +104,27 @@ template <typename Type> struct IsSame<Type, Type> : public TrueValue
{
};
/**
* This type selects between two given types based on a boolean condition at compile time.
*
* It provides member type named `Type` which is defined as `TypeOnTrue` if `kCondition` is `true` at compile time, or
* as `TypeOnFalse` if `kCondition` is `false`.
*
* @tparam kCondition The boolean condition which is used to select between the two types.
* @tparam TypeOnTrue The type to select when `kCondition` is `true`.
* @tparam TypeOnFalse The type to select when `kCondition` is `false`.
*
*/
template <bool kCondition, typename TypeOnTrue, typename TypeOnFalse> struct Conditional
{
typedef TypeOnFalse Type; ///< The selected type based on `kCondition`.
};
template <typename TypeOnTrue, typename TypeOnFalse> struct Conditional<true, TypeOnTrue, TypeOnFalse>
{
typedef TypeOnTrue Type;
};
} // namespace TypeTraits
} // namespace ot
+17 -3
View File
@@ -36,6 +36,7 @@
#include "common/array.hpp"
#include "common/debug.hpp"
#include "common/instance.hpp"
#include "common/type_traits.hpp"
#include "test_util.h"
@@ -47,7 +48,7 @@ void TestArray(void)
constexpr uint16_t kStartValue = 100;
Array<uint16_t, kMaxSize> array;
uint16_t index;
uint8_t index;
uint16_t seed;
// All methods after constructor
@@ -62,7 +63,7 @@ void TestArray(void)
seed = kStartValue;
for (uint16_t len = 1; len <= kMaxSize; len++)
for (uint8_t len = 1; len <= kMaxSize; len++)
{
for (uint8_t iter = 0; iter < 2; iter++)
{
@@ -146,7 +147,7 @@ void TestArray(void)
VerifyOrQuit(array.PushBack(0) == kErrorNoBufs);
VerifyOrQuit(array.PushBack() == nullptr);
for (uint16_t len = kMaxSize; len >= 1; len--)
for (uint8_t len = kMaxSize; len >= 1; len--)
{
uint16_t *entry;
@@ -244,12 +245,25 @@ void TestArrayCopy(void)
}
}
void TestArrayIndexType(void)
{
typedef Array<uint16_t, 255> Array1;
typedef Array<uint16_t, 256> Array2;
typedef Array<uint16_t, 100, uint16_t> Array3;
static_assert(TypeTraits::IsSame<Array1::IndexType, uint8_t>::kValue, "Array1::IndexType is incorrect");
static_assert(TypeTraits::IsSame<Array2::IndexType, uint16_t>::kValue, "Array2::IndexType is incorrect");
static_assert(TypeTraits::IsSame<Array3::IndexType, uint16_t>::kValue, "Array3::IndexType is incorrect");
}
} // namespace ot
int main(void)
{
ot::TestArray();
ot::TestArrayCopy();
ot::TestArrayIndexType();
printf("All tests passed\n");
return 0;
}