diff --git a/src/core/BUILD.gn b/src/core/BUILD.gn index d3f800bc0..03e4da63c 100644 --- a/src/core/BUILD.gn +++ b/src/core/BUILD.gn @@ -370,6 +370,7 @@ openthread_core_files = [ "common/extension.hpp", "common/instance.cpp", "common/instance.hpp", + "common/iterator_utils.hpp", "common/linked_list.hpp", "common/locator-getters.hpp", "common/locator.hpp", diff --git a/src/core/Makefile.am b/src/core/Makefile.am index fa1958d30..db17fc1c0 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -364,6 +364,7 @@ HEADERS_COMMON = \ common/equatable.hpp \ common/extension.hpp \ common/instance.hpp \ + common/iterator_utils.hpp \ common/linked_list.hpp \ common/locator.hpp \ common/locator-getters.hpp \ diff --git a/src/core/backbone_router/ndproxy_table.cpp b/src/core/backbone_router/ndproxy_table.cpp index d8f3a8873..b3466417b 100644 --- a/src/core/backbone_router/ndproxy_table.cpp +++ b/src/core/backbone_router/ndproxy_table.cpp @@ -95,9 +95,9 @@ NdProxyTable::Iterator::Iterator(Instance &aInstance, Filter aFilter) { NdProxyTable &table = GetInstance().Get(); - mCurrent = &table.mProxies[0]; + mItem = &table.mProxies[0]; - if (!MatchesFilter(*mCurrent, mFilter)) + if (!MatchesFilter(*mItem, mFilter)) { Advance(); } @@ -107,7 +107,7 @@ NdProxyTable::Iterator::Iterator(Instance &aInstance, NdProxyTable::Iterator::It : InstanceLocator(aInstance) { NdProxyTable &table = GetInstance().Get(); - mCurrent = OT_ARRAY_END(table.mProxies); + mItem = OT_ARRAY_END(table.mProxies); } void NdProxyTable::Iterator::Advance(void) @@ -116,8 +116,8 @@ void NdProxyTable::Iterator::Advance(void) do { - mCurrent++; - } while (mCurrent < OT_ARRAY_END(table.mProxies) && !MatchesFilter(*mCurrent, mFilter)); + mItem++; + } while (mItem < OT_ARRAY_END(table.mProxies) && !MatchesFilter(*mItem, mFilter)); } void NdProxyTable::Erase(NdProxy &aNdProxy) diff --git a/src/core/backbone_router/ndproxy_table.hpp b/src/core/backbone_router/ndproxy_table.hpp index ece89b901..22fefc676 100644 --- a/src/core/backbone_router/ndproxy_table.hpp +++ b/src/core/backbone_router/ndproxy_table.hpp @@ -40,6 +40,7 @@ #include #include "backbone_router/bbr_leader.hpp" +#include "common/iterator_utils.hpp" #include "common/locator.hpp" #include "common/non_copyable.hpp" #include "common/time.hpp" @@ -246,8 +247,9 @@ private: * This class represents an iterator for iterating through the NdProxy Table. * */ - class Iterator : public InstanceLocator + class Iterator : public InstanceLocator, public ItemPtrIterator { + friend class ItemPtrIterator; friend class NdProxyTable; friend class IteratorBuilder; @@ -260,18 +262,9 @@ private: Iterator(Instance &aInstance, Filter aFilter); Iterator(Instance &aInstance, IteratorType); - bool IsDone(void) const { return (mCurrent == nullptr); } - void Advance(void); - void operator++(void) { Advance(); } - void operator++(int) { Advance(); } - const NdProxy &operator*(void)const { return *mCurrent; } - bool operator==(const Iterator &aOther) const { return mCurrent == aOther.mCurrent; } - bool operator!=(const Iterator &aOther) const { return !(*this == aOther); } - NdProxy * operator->(void) { return mCurrent; } - NdProxy & operator*(void) { return *mCurrent; } + void Advance(void); - NdProxy *mCurrent; - Filter mFilter; + Filter mFilter; }; class IteratorBuilder : public InstanceLocator diff --git a/src/core/common/iterator_utils.hpp b/src/core/common/iterator_utils.hpp new file mode 100644 index 000000000..dbee0aad7 --- /dev/null +++ b/src/core/common/iterator_utils.hpp @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2020, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file includes definitions for a generic item-pointer iterator class. + */ + +#ifndef ITERATOR_UTILS_HPP_ +#define ITERATOR_UTILS_HPP_ + +namespace ot { + +/** + * @addtogroup core-iterator-utils + * + * @brief + * This module includes definitions for OpenThread generic item-pointer iterator class. + * + * @{ + * + */ + +/** + * This template class is used as a base class for those item-pointer iterators. + * + * These iterators have common methods and operators like `Advance()` and `++` and hold a pointer to the + * object. + * + * Users of this class should follow CRTP-style inheritance, i.e., `IteratorType` class itself should publicly inherit + * from `ItemPtrIterator`. + * + * @tparam ItemType The type of the object that the iterator points to. + * @tparam IteratorType The Iterator class that inherits this class. The class MUST have a method `Advance()` which + * moves the pointer to the next. `Advance()` SHALL NOT be called when `IsDone()` is `true` and + * would set the pointer to `nullptr` when there's no more elements. + * + */ +template class ItemPtrIterator +{ +public: + /** + * This method indicates whether there are no more items to be accessed (iterator has reached the end). + * + * @retval TRUE There are no more items to be accessed (iterator has reached the end). + * @retval FALSE The current item is valid. + * + */ + bool IsDone(void) const { return mItem == nullptr; } + + /** + * This method overloads `++` operator (pre-increment) to advance the iterator. + * + * The iterator is moved to point to the next item using IteratorType's `Advance` method. + * If there are no more items, the iterator becomes empty (i.e., `operator*` returns `nullptr` and `IsDone()` + * returns `true`). + * + */ + void operator++(void) { static_cast(this)->Advance(); } + + /** + * This method overloads `++` operator (post-increment) to advance the iterator. + * + * The iterator is moved to point to the next item using IteratorType's `Advance` method. + * If there are no more items, the iterator becomes empty (i.e., `operator*` returns `nullptr` and `IsDone()` + * returns `true`). + * + */ + void operator++(int) { static_cast(this)->Advance(); } + + /** + * This method overloads the `*` dereference operator and gets a reference to then item to which the iterator is + * currently pointing. + * + * This method MUST be used when the iterator is not empty/finished (i.e., `IsDone()` returns `false`). + * + * @returns A reference to the item currently pointed by the iterator. + * + */ + ItemType &operator*(void) { return *mItem; } + + /** + * This method overloads the `->` dereference operator and gets a pointer to the item to which the iterator is + * currently pointing. + * + * @returns A pointer to the item associated with the iterator, or `nullptr` if iterator is empty/done. + * + */ + ItemType *operator->(void) { return mItem; } + + /** + * This method overloads operator `==` to evaluate whether or not two `Iterator` instances point to the same + * item. + * + * @param[in] aOther The other `Iterator` to compare with. + * + * @retval TRUE If the two `Iterator` objects point to the same item or both are done. + * @retval FALSE If the two `Iterator` objects do not point to the same item. + * + */ + bool operator==(const IteratorType &aOther) const { return mItem == aOther.mItem; } + + /** + * This method overloads operator `!=` to evaluate whether or not two `Iterator` instances point to the same + * child entry. + * + * @param[in] aOther The other `Iterator` to compare with. + * + * @retval TRUE If the two `Iterator` objects do not point to the same item. + * @retval FALSE If the two `Iterator` objects point to the same item or both are done. + * + */ + bool operator!=(const IteratorType &aOther) const { return mItem != aOther.mItem; } + +protected: + /** + * Default constructor + * + */ + ItemPtrIterator(void) + : mItem(nullptr) + { + } + + /** + * Contructor with an Item pointer. + * + */ + explicit ItemPtrIterator(ItemType *item) + : mItem(item) + { + } + + ItemType *mItem; +}; + +/** + * @} + * + */ + +} // namespace ot + +#endif // ITERATOR_UTILS_HPP_ diff --git a/src/core/net/netif.hpp b/src/core/net/netif.hpp index ad2ef31fb..826255e5a 100644 --- a/src/core/net/netif.hpp +++ b/src/core/net/netif.hpp @@ -38,6 +38,7 @@ #include "common/clearable.hpp" #include "common/code_utils.hpp" +#include "common/iterator_utils.hpp" #include "common/linked_list.hpp" #include "common/locator.hpp" #include "common/message.hpp" @@ -273,7 +274,9 @@ public: * */ class ExternalMulticastAddressIterator + : public ItemPtrIterator { + friend class ItemPtrIterator; friend class ExternalMulticastAddressIteratorBuilder; public: @@ -286,88 +289,13 @@ public: * */ explicit ExternalMulticastAddressIterator(const Netif &aNetif, Address::TypeFilter aFilter = Address::kTypeAny) - : mNetif(aNetif) + : ItemPtrIterator(nullptr) + , mNetif(aNetif) , mFilter(aFilter) { AdvanceFrom(mNetif.GetMulticastAddresses()); } - /** - * This method indicates whether the iterator has reached end of the list. - * - * @retval TRUE There are no more entries in the list (reached end of the list). - * @retval FALSE The current address entry is valid. - * - */ - bool IsDone(void) const { return mCurrent != nullptr; } - - /** - * This method overloads `++` operator (pre-increment) to advance the iterator. - * - * The iterator is moved to point to the next entry. If there are no more entries matching the iterator becomes - * empty. - * - */ - void operator++(void) { AdvanceFrom(mCurrent->GetNext()); } - - /** - * This method overloads `++` operator (post-increment) to advance the iterator. - * - * The iterator is moved to point to the next entry. If there are no more entries matching the iterator becomes - * empty. - * - */ - void operator++(int) { AdvanceFrom(mCurrent->GetNext()); } - - /** - * This method overloads the `*` dereference operator and gets a reference to `ExternalNetifMulticastAddress` - * entry to which the iterator is currently pointing. - * - * This method MUST be used when the iterator is not empty. - * - * @returns A reference to the `ExternalNetifMulticastAddress` entry currently pointed by the iterator. - * - */ - ExternalNetifMulticastAddress &operator*(void) { return *mCurrent; } - - /** - * This method overloads the `->` dereference operator and gets a pointer to `ExternalNetifMulticastAddress` - * entry to which the iterator is current pointing. - * - * @returns A pointer to the `ExternalNetifMulticastAddress` entry associated with the iterator, or `nullptr` if - * iterator is empty. - * - */ - ExternalNetifMulticastAddress *operator->(void) { return mCurrent; } - - /** - * This method overloads operator `==` to evaluate whether or not two `ExternalMulticastAddressIterator` - * instances point to the same `ExternalNetifMulticastAddress` entry. - * - * @param[in] aOther The other `Iterator` to compare with. - * - * @retval TRUE If the two `ExternalMulticastAddressIterator` objects point to the same - * `ExternalNetifMulticastAddress` entry or both are done. - * @retval FALSE If the two `ExternalMulticastAddressIterator` objects do not point to the same - * `ExternalNetifMulticastAddress` entry. - * - */ - bool operator==(const ExternalMulticastAddressIterator &aOther) { return mCurrent == aOther.mCurrent; } - - /** - * This method overloads operator `!=` to evaluate whether or not two `ExternalMulticastAddressIterator` - * instances point to the same `ExternalNetifMulticastAddress` entry. - * - * @param[in] aOther The other `ExternalMulticastAddressIterator` to compare with. - * - * @retval TRUE If the two `ExternalMulticastAddressIterator` objects do not point to the same - * `ExternalNetifMulticastAddress` entry. - * @retval FALSE If the two `ExternalMulticastAddressIterator` objects point to the same - * `ExternalNetifMulticastAddress` entry or both are done. - * - */ - bool operator!=(const ExternalMulticastAddressIterator &aOther) { return mCurrent != aOther.mCurrent; } - private: enum IteratorType { @@ -376,7 +304,6 @@ public: ExternalMulticastAddressIterator(const Netif &aNetif, IteratorType) : mNetif(aNetif) - , mCurrent(nullptr) { } @@ -388,13 +315,14 @@ public: aAddr = aAddr->GetNext(); } - mCurrent = + mItem = const_cast(static_cast(aAddr)); } - const Netif & mNetif; - ExternalNetifMulticastAddress *mCurrent; - Address::TypeFilter mFilter; + void Advance(void) { AdvanceFrom(mItem->GetNext()); } + + const Netif & mNetif; + Address::TypeFilter mFilter; }; /** diff --git a/src/core/thread/child_table.cpp b/src/core/thread/child_table.cpp index 43f5cb548..63ed972da 100644 --- a/src/core/thread/child_table.cpp +++ b/src/core/thread/child_table.cpp @@ -43,17 +43,17 @@ namespace ot { ChildTable::Iterator::Iterator(Instance &aInstance, Child::StateFilter aFilter) : InstanceLocator(aInstance) + , ItemPtrIterator(nullptr) , mFilter(aFilter) - , mChild(nullptr) { Reset(); } void ChildTable::Iterator::Reset(void) { - mChild = &Get().mChildren[0]; + mItem = &Get().mChildren[0]; - if (!mChild->MatchesFilter(mFilter)) + if (!mItem->MatchesFilter(mFilter)) { Advance(); } @@ -61,13 +61,13 @@ void ChildTable::Iterator::Reset(void) void ChildTable::Iterator::Advance(void) { - VerifyOrExit(mChild != nullptr); + VerifyOrExit(mItem != nullptr); do { - mChild++; - VerifyOrExit(mChild < &Get().mChildren[Get().mMaxChildrenAllowed], mChild = nullptr); - } while (!mChild->MatchesFilter(mFilter)); + mItem++; + VerifyOrExit(mItem < &Get().mChildren[Get().mMaxChildrenAllowed], mItem = nullptr); + } while (!mItem->MatchesFilter(mFilter)); exit: return; diff --git a/src/core/thread/child_table.hpp b/src/core/thread/child_table.hpp index dfc9055cb..215cd5e95 100644 --- a/src/core/thread/child_table.hpp +++ b/src/core/thread/child_table.hpp @@ -38,6 +38,7 @@ #if OPENTHREAD_FTD +#include "common/iterator_utils.hpp" #include "common/locator.hpp" #include "common/non_copyable.hpp" #include "thread/topology.hpp" @@ -58,8 +59,9 @@ public: * This class represents an iterator for iterating through the child entries in the child table. * */ - class Iterator : public InstanceLocator + class Iterator : public InstanceLocator, public ItemPtrIterator { + friend class ItemPtrIterator; friend class IteratorBuilder; public: @@ -78,100 +80,24 @@ public: */ void Reset(void); - /** - * This method indicates whether there are no more `Child` entries in the list (iterator has reached end of - * the list). - * - * @retval TRUE There are no more entries in the list (reached end of the list). - * @retval FALSE The current entry is valid. - * - */ - bool IsDone(void) const { return (mChild == nullptr); } - - /** - * This method overloads `++` operator (pre-increment) to advance the iterator. - * - * The iterator is moved to point to the next `Child` entry matching the given state filter in the constructor. - * If there are no more `Child` entries matching the given filter, the iterator becomes empty (i.e., - * `GetChild()` returns `nullptr` and `IsDone()` returns `true`). - * - */ - void operator++(void) { Advance(); } - - /** - * This method overloads `++` operator (post-increment) to advance the iterator. - * - * The iterator is moved to point to the next `Child` entry matching the given state filter in the constructor. - * If there are no more `Child` entries matching the given filter, the iterator becomes empty (i.e., - * `GetChild()` returns `nullptr` and `IsDone()` returns `true`). - * - */ - void operator++(int) { Advance(); } - /** * This method gets the `Child` entry to which the iterator is currently pointing. * * @returns A pointer to the `Child` entry, or `nullptr` if the iterator is done and/or empty. * */ - Child *GetChild(void) { return mChild; } - - /** - * This method overloads the `*` dereference operator and gets a reference to `Child` entry to which the - * iterator is currently pointing. - * - * This method MUST be used when the iterator is not empty/finished (i.e., `IsDone()` returns `false`). - * - * @returns A reference to the `Child` entry currently pointed by the iterator. - * - */ - Child &operator*(void) { return *mChild; } - - /** - * This method overloads the `->` dereference operator and gets a pointer to `Child` entry to which the iterator - * is currently pointing. - * - * @returns A pointer to the `Child` entry associated with the iterator, or `nullptr` if iterator is empty/done. - * - */ - Child *operator->(void) { return mChild; } - - /** - * This method overloads operator `==` to evaluate whether or not two `Iterator` instances point to the same - * child entry. - * - * @param[in] aOther The other `Iterator` to compare with. - * - * @retval TRUE If the two `Iterator` objects point to the same child entry or both are done. - * @retval FALSE If the two `Iterator` objects do not point to the same child entry. - * - */ - bool operator==(const Iterator &aOther) const { return mChild == aOther.mChild; } - - /** - * This method overloads operator `!=` to evaluate whether or not two `Iterator` instances point to the same - * child entry. - * - * @param[in] aOther The other `Iterator` to compare with. - * - * @retval TRUE If the two `Iterator` objects do not point to the same child entry. - * @retval FALSE If the two `Iterator` objects point to the same child entry or both are done. - * - */ - bool operator!=(const Iterator &aOther) const { return mChild != aOther.mChild; } + Child *GetChild(void) { return mItem; } private: explicit Iterator(Instance &aInstance) : InstanceLocator(aInstance) , mFilter(Child::StateFilter::kInStateValid) - , mChild(nullptr) { } void Advance(void); Child::StateFilter mFilter; - Child * mChild; }; /** diff --git a/src/core/thread/router_table.cpp b/src/core/thread/router_table.cpp index ea2efec99..38e9296a7 100644 --- a/src/core/thread/router_table.cpp +++ b/src/core/thread/router_table.cpp @@ -44,13 +44,13 @@ namespace ot { RouterTable::Iterator::Iterator(Instance &aInstance) : InstanceLocator(aInstance) - , mRouter(Get().GetFirstEntry()) + , ItemPtrIterator(Get().GetFirstEntry()) { } void RouterTable::Iterator::Advance(void) { - mRouter = Get().GetNextEntry(mRouter); + mItem = Get().GetNextEntry(mItem); } RouterTable::RouterTable(Instance &aInstance) diff --git a/src/core/thread/router_table.hpp b/src/core/thread/router_table.hpp index c798a4f9a..ad3263fc5 100644 --- a/src/core/thread/router_table.hpp +++ b/src/core/thread/router_table.hpp @@ -34,6 +34,7 @@ #if OPENTHREAD_FTD #include "common/encoding.hpp" +#include "common/iterator_utils.hpp" #include "common/locator.hpp" #include "common/non_copyable.hpp" #include "mac/mac_types.hpp" @@ -53,8 +54,9 @@ public: * This class represents an iterator for iterating through entries in the router table. * */ - class Iterator : public InstanceLocator + class Iterator : public InstanceLocator, public ItemPtrIterator { + friend class ItemPtrIterator; friend class IteratorBuilder; public: @@ -66,78 +68,6 @@ public: */ explicit Iterator(Instance &aInstance); - /** - * This method indicates if the iterator has reached the end of the list, i.e., iterator is empty. - * - * @retval TRUE The iterator has reached the end of the list. - * @retval FALSE The iterator currently points to a valid entry. - * - */ - bool IsDone(void) const { return (mRouter == nullptr); } - - /** - * This method overloads `++` operator (pre-increment) to advance the iterator. - * - * The iterator is moved to point to the next entry. If there are no more entries matching the iterator - * becomes empty (i.e., `IsDone()` returns `true`). - * - */ - void operator++(void) { Advance(); } - - /** - * This method overloads `++` operator (post-increment) to advance the iterator. - * - * The iterator is moved to point to the next entry. If there are no more entries matching the iterator - * becomes empty (i.e., `IsDone()` returns `true`). - * - */ - void operator++(int) { Advance(); } - - /** - * This method overloads the `*` dereference operator and gets a reference to `Router` entry to which the - * iterator is currently pointing. - * - * This method MUST be used when the iterator is not empty/finished (i.e., `IsDone()` returns `false`). - * - * @returns A reference to the `Router` entry currently pointed by the iterator. - * - */ - Router &operator*(void) { return *mRouter; } - - /** - * This method overloads the `->` dereference operator and gets a pointer to `Router` entry to which the - * iterator is currently pointing. - * - * @returns A pointer to the `Router` entry associated with the iterator, or `nullptr` if iterator is - * empty/done. - * - */ - Router *operator->(void) { return mRouter; } - - /** - * This method overloads operator `==` to evaluate whether or not two `Iterator` instances point to the same - * router entry. - * - * @param[in] aOther The other `Iterator` to compare with. - * - * @retval TRUE If the two `Iterator` objects point to the same router entry or both are done. - * @retval FALSE If the two `Iterator` objects do not point to the same router entry. - * - */ - bool operator==(const Iterator &aOther) { return mRouter == aOther.mRouter; } - - /** - * This method overloads operator `!=` to evaluate whether or not two `Iterator` instances point to the same - * router entry. - * - * @param[in] aOther The other `Iterator` to compare with. - * - * @retval TRUE If the two `Iterator` objects do not point to the same router entry. - * @retval FALSE If the two `Iterator` objects point to the same router entry or both are done. - * - */ - bool operator!=(const Iterator &aOther) { return mRouter != aOther.mRouter; } - private: enum IteratorType { @@ -146,13 +76,10 @@ public: Iterator(Instance &aInstance, IteratorType) : InstanceLocator(aInstance) - , mRouter(nullptr) { } void Advance(void); - - Router *mRouter; }; /**