From 75c525bac81b6f830bcfc910d13b9debb3ec582d Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Mon, 26 Jul 2021 11:57:50 -0700 Subject: [PATCH] [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. --- src/core/common/array.hpp | 43 ++++++++++++++++++++++++--------- src/core/common/type_traits.hpp | 21 ++++++++++++++++ tests/unit/test_array.cpp | 20 ++++++++++++--- 3 files changed, 69 insertions(+), 15 deletions(-) diff --git a/src/core/common/array.hpp b/src/core/common/array.hpp index b4c56b02b..dd485b299 100644 --- a/src/core/common/array.hpp +++ b/src/core/common/array.hpp @@ -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 Array +template ::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(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(&aElement - &mElements[0]); } + IndexType IndexOf(const Type &aElement) const { return static_cast(&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 diff --git a/src/core/common/type_traits.hpp b/src/core/common/type_traits.hpp index 105ff3fcf..4feb52a2a 100644 --- a/src/core/common/type_traits.hpp +++ b/src/core/common/type_traits.hpp @@ -104,6 +104,27 @@ template struct IsSame : 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 struct Conditional +{ + typedef TypeOnFalse Type; ///< The selected type based on `kCondition`. +}; + +template struct Conditional +{ + typedef TypeOnTrue Type; +}; + } // namespace TypeTraits } // namespace ot diff --git a/tests/unit/test_array.cpp b/tests/unit/test_array.cpp index 3a93724b3..2f1b68dc4 100644 --- a/tests/unit/test_array.cpp +++ b/tests/unit/test_array.cpp @@ -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 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 Array1; + typedef Array Array2; + typedef Array Array3; + + static_assert(TypeTraits::IsSame::kValue, "Array1::IndexType is incorrect"); + static_assert(TypeTraits::IsSame::kValue, "Array2::IndexType is incorrect"); + static_assert(TypeTraits::IsSame::kValue, "Array3::IndexType is incorrect"); +} + } // namespace ot int main(void) { ot::TestArray(); ot::TestArrayCopy(); + ot::TestArrayIndexType(); + printf("All tests passed\n"); return 0; }