[utils] implement a item-pointer iterator template for many iterators (#6025)

Many Iterators have the same pattern in our code: they have ++,
deference, equal operators, IsDone method and hold a pointer to the an
object. This commit extracts the common pattern into a template class
ItemPtrIterator and use it as a base class for those similar Iterator
classes.
This commit is contained in:
Li Cao
2021-01-09 09:10:09 -08:00
committed by GitHub
parent 771e0c39f6
commit 948ad52565
10 changed files with 207 additions and 262 deletions
+1
View File
@@ -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",
+1
View File
@@ -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 \
+5 -5
View File
@@ -95,9 +95,9 @@ NdProxyTable::Iterator::Iterator(Instance &aInstance, Filter aFilter)
{
NdProxyTable &table = GetInstance().Get<BackboneRouter::NdProxyTable>();
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<BackboneRouter::NdProxyTable>();
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)
+5 -12
View File
@@ -40,6 +40,7 @@
#include <openthread/backbone_router_ftd.h>
#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<NdProxy, Iterator>
{
friend class ItemPtrIterator<NdProxy, Iterator>;
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
+169
View File
@@ -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<ItemType, IteratorType>`.
*
* @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 ItemType, class IteratorType> 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<IteratorType *>(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<IteratorType *>(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_
+10 -82
View File
@@ -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<ExternalNetifMulticastAddress, ExternalMulticastAddressIterator>
{
friend class ItemPtrIterator<ExternalNetifMulticastAddress, ExternalMulticastAddressIterator>;
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<ExternalNetifMulticastAddress *>(static_cast<const ExternalNetifMulticastAddress *>(aAddr));
}
const Netif & mNetif;
ExternalNetifMulticastAddress *mCurrent;
Address::TypeFilter mFilter;
void Advance(void) { AdvanceFrom(mItem->GetNext()); }
const Netif & mNetif;
Address::TypeFilter mFilter;
};
/**
+7 -7
View File
@@ -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<ChildTable>().mChildren[0];
mItem = &Get<ChildTable>().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<ChildTable>().mChildren[Get<ChildTable>().mMaxChildrenAllowed], mChild = nullptr);
} while (!mChild->MatchesFilter(mFilter));
mItem++;
VerifyOrExit(mItem < &Get<ChildTable>().mChildren[Get<ChildTable>().mMaxChildrenAllowed], mItem = nullptr);
} while (!mItem->MatchesFilter(mFilter));
exit:
return;
+4 -78
View File
@@ -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<Child, Iterator>
{
friend class ItemPtrIterator<Child, Iterator>;
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;
};
/**
+2 -2
View File
@@ -44,13 +44,13 @@ namespace ot {
RouterTable::Iterator::Iterator(Instance &aInstance)
: InstanceLocator(aInstance)
, mRouter(Get<RouterTable>().GetFirstEntry())
, ItemPtrIterator(Get<RouterTable>().GetFirstEntry())
{
}
void RouterTable::Iterator::Advance(void)
{
mRouter = Get<RouterTable>().GetNextEntry(mRouter);
mItem = Get<RouterTable>().GetNextEntry(mItem);
}
RouterTable::RouterTable(Instance &aInstance)
+3 -76
View File
@@ -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<Router, Iterator>
{
friend class ItemPtrIterator<Router, Iterator>;
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;
};
/**