1 /* 2 * Copyright (c) 2021, The OpenThread Authors. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. Neither the name of the copyright holder nor the 13 * names of its contributors may be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /** 30 * @file 31 * This file includes definitions for a generic array. 32 */ 33 34 #ifndef ARRAY_HPP_ 35 #define ARRAY_HPP_ 36 37 #include "openthread-core-config.h" 38 39 #include "common/code_utils.hpp" 40 #include "common/error.hpp" 41 #include "common/numeric_limits.hpp" 42 #include "common/type_traits.hpp" 43 44 namespace ot { 45 46 /** 47 * This template class represents an array of elements with a fixed max size. 48 * 49 * @tparam Type The array element type. 50 * @tparam kMaxSize Specifies the max array size (maximum number of elements in the array). 51 * @tparam SizeType The type to be used for array size, length, and index. If not specified, a default `uint` type 52 * is determined based on `kMaxSize`, i.e., if `kMaxSize <= 255` then `uint8_t` will be used, 53 * otherwise `uint16_t` will be used. 54 * 55 */ 56 template <typename Type, 57 uint16_t kMaxSize, 58 typename SizeType = 59 typename TypeTraits::Conditional<kMaxSize <= NumericLimits<uint8_t>::kMax, uint8_t, uint16_t>::Type> 60 class Array 61 { 62 static_assert(kMaxSize != 0, "Array `kMaxSize` cannot be zero"); 63 64 public: 65 /** 66 * This type represents the length or index in array. 67 * 68 * It is typically either `uint8_t` or `uint16_t` (determined based on the maximum array size (`kMaxSize`)). 69 * 70 */ 71 typedef SizeType IndexType; 72 73 /** 74 * This constructor initializes the array as empty. 75 * 76 */ Array(void)77 Array(void) 78 : mLength(0) 79 { 80 } 81 82 /** 83 * This constructor initializes the array by copying elements from another array. 84 * 85 * The method uses assignment `=` operator on `Type` to copy each element from @p aOtherArray into the elements of 86 * the array. 87 * 88 * @param[in] aOtherArray Another array to copy from. 89 * 90 */ Array(const Array & aOtherArray)91 Array(const Array &aOtherArray) { *this = aOtherArray; } 92 93 /** 94 * This method clears the array. 95 * 96 */ Clear(void)97 void Clear(void) { mLength = 0; } 98 99 /** 100 * This method indicates whether or not the array is empty. 101 * 102 * @retval TRUE when array is empty. 103 * @retval FALSE when array is not empty. 104 * 105 */ IsEmpty(void) const106 bool IsEmpty(void) const { return (mLength == 0); } 107 108 /** 109 * This method indicates whether or not the array is full. 110 * 111 * @retval TRUE when array is full. 112 * @retval FALSE when array is not full. 113 * 114 */ IsFull(void) const115 bool IsFull(void) const { return (mLength == GetMaxSize()); } 116 117 /** 118 * This method returns the maximum array size (max number of elements). 119 * 120 * @returns The maximum array size (max number of elements that can be added to the array). 121 * 122 */ GetMaxSize(void) const123 IndexType GetMaxSize(void) const { return static_cast<IndexType>(kMaxSize); } 124 125 /** 126 * This method returns the current length of array (number of elements). 127 * 128 * @returns The current array length. 129 * 130 */ GetLength(void) const131 IndexType GetLength(void) const { return mLength; } 132 133 /** 134 * This method overloads the `[]` operator to get the element at a given index. 135 * 136 * This method does not perform index bounds checking. Behavior is undefined if @p aIndex is not valid. 137 * 138 * @param[in] aIndex The index to get. 139 * 140 * @returns A reference to the element in array at @p aIndex. 141 * 142 */ operator [](IndexType aIndex)143 Type &operator[](IndexType aIndex) { return mElements[aIndex]; } 144 145 /** 146 * This method overloads the `[]` operator to get the element at a given index. 147 * 148 * This method does not perform index bounds checking. Behavior is undefined if @p aIndex is not valid. 149 * 150 * @param[in] aIndex The index to get. 151 * 152 * @returns A reference to the element in array at @p aIndex. 153 * 154 */ operator [](IndexType aIndex) const155 const Type &operator[](IndexType aIndex) const { return mElements[aIndex]; } 156 157 /** 158 * This method gets a pointer to the element at a given index. 159 * 160 * Unlike `operator[]`, this method checks @p aIndex to be valid and within the current length. 161 * 162 * @param[in] aIndex The index to get. 163 * 164 * @returns A pointer to element in array at @p aIndex or `nullptr` if @p aIndex is not valid. 165 * 166 */ At(IndexType aIndex)167 Type *At(IndexType aIndex) { return (aIndex < mLength) ? &mElements[aIndex] : nullptr; } 168 169 /** 170 * This method gets a pointer to the element at a given index. 171 * 172 * Unlike `operator[]`, this method checks @p aIndex to be valid and within the current length. 173 * 174 * @param[in] aIndex The index to get. 175 * 176 * @returns A pointer to element in array at @p aIndex or `nullptr` if @p aIndex is not valid. 177 * 178 */ At(IndexType aIndex) const179 const Type *At(IndexType aIndex) const { return (aIndex < mLength) ? &mElements[aIndex] : nullptr; } 180 181 /** 182 * This method gets a pointer to the element at the front of the array (first element). 183 * 184 * @returns A pointer to the front element or `nullptr` if array is empty. 185 * 186 */ Front(void)187 Type *Front(void) { return At(0); } 188 189 /** 190 * This method gets a pointer to the element at the front of the array (first element). 191 * 192 * @returns A pointer to the front element or `nullptr` if array is empty. 193 * 194 */ Front(void) const195 const Type *Front(void) const { return At(0); } 196 197 /** 198 * This method gets a pointer to the element at the back of the array (last element). 199 * 200 * @returns A pointer to the back element or `nullptr` if array is empty. 201 * 202 */ Back(void)203 Type *Back(void) { return At(mLength - 1); } 204 205 /** 206 * This method gets a pointer to the element at the back of the array (last element). 207 * 208 * @returns A pointer to the back element or `nullptr` if array is empty. 209 * 210 */ Back(void) const211 const Type *Back(void) const { return At(mLength - 1); } 212 213 /** 214 * This method appends a new entry to the end of the array. 215 * 216 * The method uses assignment `=` operator on `Type` to copy @p aEntry into the added array element. 217 * 218 * @param[in] aEntry The new entry to push back. 219 * 220 * @retval kErrorNone Successfully pushed back @p aEntry to the end of the array. 221 * @retval kErrorNoBufs Could not append the new element since array is full. 222 * 223 */ PushBack(const Type & aEntry)224 Error PushBack(const Type &aEntry) { return IsFull() ? kErrorNoBufs : (mElements[mLength++] = aEntry, kErrorNone); } 225 226 /** 227 * This method appends a new entry to the end of the array. 228 * 229 * On success, this method returns a pointer to the newly appended element in the array for the caller to 230 * initialize and use. 231 * 232 * @return A pointer to the newly appended element or `nullptr` if array is full. 233 * 234 */ PushBack(void)235 Type *PushBack(void) { return IsFull() ? nullptr : &mElements[mLength++]; } 236 237 /** 238 * This method removes the last element in the array. 239 * 240 * @returns A pointer to the removed element from the array, or `nullptr` if array is empty. 241 * 242 */ PopBack(void)243 Type *PopBack(void) { return IsEmpty() ? nullptr : &mElements[--mLength]; } 244 245 /** 246 * This method returns the index of an element in the array. 247 * 248 * The @p aElement MUST be from the array, otherwise the behavior of this method is undefined. 249 * 250 * @param[in] aElement A reference to an element in the array. 251 * 252 * @returns The index of @p aElement in the array. 253 * 254 */ IndexOf(const Type & aElement) const255 IndexType IndexOf(const Type &aElement) const { return static_cast<IndexType>(&aElement - &mElements[0]); } 256 257 /** 258 * This method finds the first match of a given entry in the array. 259 * 260 * This method uses `==` operator on `Type` to compare the array element with @p aEntry. 261 * 262 * @param[in] aEntry The entry to search for within the array. 263 * 264 * @returns A pointer to matched array element, or `nullptr` if a match could not be found. 265 * 266 */ Find(const Type & aEntry)267 Type *Find(const Type &aEntry) { return const_cast<Type *>(const_cast<const Array *>(this)->Find(aEntry)); } 268 269 /** 270 * This method finds the first match of a given entry in the array. 271 * 272 * This method uses `==` operator to compare the array elements with @p aEntry. 273 * 274 * @param[in] aEntry The entry to search for within the array. 275 * 276 * @returns A pointer to matched array element, or `nullptr` if a match could not be found. 277 * 278 */ Find(const Type & aEntry) const279 const Type *Find(const Type &aEntry) const 280 { 281 const Type *matched = nullptr; 282 283 for (const Type &element : *this) 284 { 285 if (element == aEntry) 286 { 287 matched = &element; 288 break; 289 } 290 } 291 292 return matched; 293 } 294 295 /** 296 * This method indicates whether or not a match to given entry exists in the array. 297 * 298 * This method uses `==` operator on `Type` to compare the array elements with @p aEntry. 299 * 300 * @param[in] aEntry The entry to search for within the array. 301 * 302 * @retval TRUE The array contains a matching element with @p aEntry. 303 * @retval FALSE The array does not contain a matching element with @p aEntry. 304 * 305 */ Contains(const Type & aEntry) const306 bool Contains(const Type &aEntry) const { return Find(aEntry) != nullptr; } 307 308 /** 309 * This template method finds the first element in the array matching a given indicator. 310 * 311 * The template type `Indicator` specifies the type of @p aIndicator object which is used to match against elements 312 * in the array. To check that an element matches the given indicator, the `Matches()` method is invoked on each 313 * `Type` element in the array. The `Matches()` method should be provided by `Type` class accordingly: 314 * 315 * bool Type::Matches(const Indicator &aIndicator) const 316 * 317 * @param[in] aIndicator An indicator to match with elements in the array. 318 * 319 * @returns A pointer to the matched array element, or nullptr if a match could not be found. 320 * 321 */ FindMatching(const Indicator & aIndicator)322 template <typename Indicator> Type *FindMatching(const Indicator &aIndicator) 323 { 324 return const_cast<Type *>(const_cast<const Array *>(this)->FindMatching(aIndicator)); 325 } 326 327 /** 328 * This template method finds the first element in the array matching a given indicator. 329 * 330 * The template type `Indicator` specifies the type of @p aIndicator object which is used to match against elements 331 * in the array. To check that an element matches the given indicator, the `Matches()` method is invoked on each 332 * `Type` element in the array. The `Matches()` method should be provided by `Type` class accordingly: 333 * 334 * bool Type::Matches(const Indicator &aIndicator) const 335 * 336 * @param[in] aIndicator An indicator to match with elements in the array. 337 * 338 * @returns A pointer to the matched array element, or nullptr if a match could not be found. 339 * 340 */ FindMatching(const Indicator & aIndicator) const341 template <typename Indicator> const Type *FindMatching(const Indicator &aIndicator) const 342 { 343 const Type *matched = nullptr; 344 345 for (const Type &element : *this) 346 { 347 if (element.Matches(aIndicator)) 348 { 349 matched = &element; 350 break; 351 } 352 } 353 354 return matched; 355 } 356 357 /** 358 * This template method indicates whether or not the array contains an element matching a given indicator. 359 * 360 * The template type `Indicator` specifies the type of @p aIndicator object which is used to match against elements 361 * in the array. To check that an element matches the given indicator, the `Matches()` method is invoked on each 362 * `Type` element in the array. The `Matches()` method should be provided by `Type` class accordingly: 363 * 364 * bool Type::Matches(const Indicator &aIndicator) const 365 * 366 * @param[in] aIndicator An indicator to match with elements in the array. 367 * 368 * @retval TRUE The array contains a matching element with @p aIndicator. 369 * @retval FALSE The array does not contain a matching element with @p aIndicator. 370 * 371 */ ContainsMatching(const Indicator & aIndicator) const372 template <typename Indicator> bool ContainsMatching(const Indicator &aIndicator) const 373 { 374 return FindMatching(aIndicator) != nullptr; 375 } 376 377 /** 378 * This method overloads assignment `=` operator to copy elements from another array into the array. 379 * 380 * The method uses assignment `=` operator on `Type` to copy each element from @p aOtherArray into the elements of 381 * the array. 382 * 383 * @param[in] aOtherArray Another array to copy from. 384 * 385 */ operator =(const Array & aOtherArray)386 Array &operator=(const Array &aOtherArray) 387 { 388 Clear(); 389 390 for (const Type &otherElement : aOtherArray) 391 { 392 IgnoreError(PushBack(otherElement)); 393 } 394 395 return *this; 396 } 397 398 // The following methods are intended to support range-based `for` 399 // loop iteration over the array elements and should not be used 400 // directly. 401 begin(void)402 Type * begin(void) { return &mElements[0]; } end(void)403 Type * end(void) { return &mElements[mLength]; } begin(void) const404 const Type *begin(void) const { return &mElements[0]; } end(void) const405 const Type *end(void) const { return &mElements[mLength]; } 406 407 private: 408 Type mElements[kMaxSize]; 409 IndexType mLength; 410 }; 411 412 } // namespace ot 413 414 #endif // ARRAY_HPP_ 415