Skip to content

Commit 8211b69

Browse files
authoredOct 29, 2024
Factor out common parts of list iterators into shared super-classes. (project-chip#36279)
* Factor out common parts of list iterators into shared super-classes. Saves some codesize. Fixes project-chip#36264 * Remove unused variables.
1 parent 1285f6b commit 8211b69

File tree

3 files changed

+132
-62
lines changed

3 files changed

+132
-62
lines changed
 

‎src/app/data-model/DecodableList.h

+128-56
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,103 @@ class DecodableListBase
8383
}
8484

8585
protected:
86+
class Iterator
87+
{
88+
public:
89+
Iterator(const TLV::TLVReader & reader)
90+
{
91+
mStatus = CHIP_NO_ERROR;
92+
mReader.Init(reader);
93+
}
94+
95+
bool Next()
96+
{
97+
if (mReader.GetContainerType() == TLV::kTLVType_NotSpecified)
98+
{
99+
return false;
100+
}
101+
102+
if (mStatus == CHIP_NO_ERROR)
103+
{
104+
mStatus = mReader.Next();
105+
}
106+
107+
return (mStatus == CHIP_NO_ERROR);
108+
}
109+
110+
/*
111+
* Returns the result of all previous operations on this iterator.
112+
*
113+
* Notably, if the end-of-list was encountered in a previous call to Next,
114+
* the status returned shall be CHIP_NO_ERROR.
115+
*/
116+
CHIP_ERROR GetStatus() const
117+
{
118+
if (mStatus == CHIP_END_OF_TLV)
119+
{
120+
return CHIP_NO_ERROR;
121+
}
122+
123+
return mStatus;
124+
}
125+
126+
protected:
127+
CHIP_ERROR mStatus;
128+
TLV::TLVReader mReader;
129+
};
130+
86131
TLV::TLVReader mReader;
87-
chip::Optional<FabricIndex> mFabricIndex;
132+
};
133+
134+
template <bool IsFabricScoped>
135+
class FabricIndexListMemberMixin
136+
{
137+
};
138+
139+
template <>
140+
class FabricIndexListMemberMixin<true>
141+
{
142+
public:
143+
void SetFabricIndex(FabricIndex fabricIndex) { mFabricIndex.SetValue(fabricIndex); }
144+
145+
protected:
146+
Optional<FabricIndex> mFabricIndex;
147+
};
148+
149+
template <bool IsFabricScoped>
150+
class FabricIndexIteratorMemberMixin
151+
{
152+
};
153+
154+
template <>
155+
class FabricIndexIteratorMemberMixin<true>
156+
{
157+
public:
158+
FabricIndexIteratorMemberMixin(const Optional<FabricIndex> & fabricindex) : mFabricIndex(fabricindex) {}
159+
160+
protected:
161+
const Optional<FabricIndex> mFabricIndex;
162+
};
163+
164+
template <bool IsFabricScoped>
165+
class DecodableMaybeFabricScopedList : public DecodableListBase, public FabricIndexListMemberMixin<IsFabricScoped>
166+
{
167+
public:
168+
static constexpr bool kIsFabricScoped = IsFabricScoped;
169+
170+
protected:
171+
class Iterator : public DecodableListBase::Iterator, public FabricIndexIteratorMemberMixin<IsFabricScoped>
172+
{
173+
public:
174+
template <bool IsActuallyFabricScoped = IsFabricScoped, std::enable_if_t<IsActuallyFabricScoped, bool> = true>
175+
Iterator(const TLV::TLVReader & reader, const Optional<FabricIndex> & fabricIndex) :
176+
DecodableListBase::Iterator(reader), FabricIndexIteratorMemberMixin<IsFabricScoped>(fabricIndex)
177+
{}
178+
179+
template <bool IsActuallyFabricScoped = IsFabricScoped, std::enable_if_t<!IsActuallyFabricScoped, bool> = true>
180+
Iterator(const TLV::TLVReader & reader) : DecodableListBase::Iterator(reader)
181+
{}
182+
};
88183
};
89184

90185
} // namespace detail
@@ -109,21 +204,15 @@ class DecodableListBase
109204
*
110205
*/
111206
template <typename T>
112-
class DecodableList : public detail::DecodableListBase
207+
class DecodableList : public detail::DecodableMaybeFabricScopedList<DataModel::IsFabricScoped<T>::value>
113208
{
114209
public:
115210
DecodableList() {}
116211

117-
static constexpr bool kIsFabricScoped = DataModel::IsFabricScoped<T>::value;
118-
119-
template <typename T0 = T, std::enable_if_t<DataModel::IsFabricScoped<T0>::value, bool> = true>
120-
void SetFabricIndex(FabricIndex fabricIndex)
212+
class Iterator : public detail::DecodableMaybeFabricScopedList<DataModel::IsFabricScoped<T>::value>::Iterator
121213
{
122-
mFabricIndex.SetValue(fabricIndex);
123-
}
214+
using IteratorBase = typename detail::DecodableMaybeFabricScopedList<DataModel::IsFabricScoped<T>::value>::Iterator;
124215

125-
class Iterator
126-
{
127216
public:
128217
/*
129218
* Initialize the iterator with a reference to a reader.
@@ -133,11 +222,13 @@ class DecodableList : public detail::DecodableListBase
133222
* have a `kTLVType_NotSpecified` container type if there is
134223
* no list.
135224
*/
136-
Iterator(const TLV::TLVReader & reader, Optional<FabricIndex> fabricIndex) : mFabricIndex(fabricIndex)
137-
{
138-
mStatus = CHIP_NO_ERROR;
139-
mReader.Init(reader);
140-
}
225+
template <typename T0 = T, std::enable_if_t<DataModel::IsFabricScoped<T0>::value, bool> = true>
226+
Iterator(const TLV::TLVReader & reader, Optional<FabricIndex> fabricIndex) : IteratorBase(reader, fabricIndex)
227+
{}
228+
229+
template <typename T0 = T, std::enable_if_t<!DataModel::IsFabricScoped<T0>::value, bool> = true>
230+
Iterator(const TLV::TLVReader & reader) : IteratorBase(reader)
231+
{}
141232

142233
/*
143234
* Increments the iterator to point to the next list element
@@ -157,17 +248,17 @@ class DecodableList : public detail::DecodableListBase
157248
template <typename T0 = T, std::enable_if_t<!DataModel::IsFabricScoped<T0>::value, bool> = true>
158249
bool Next()
159250
{
160-
return DoNext();
251+
return IteratorBase::Next() && DecodeValue();
161252
}
162253

163254
template <typename T0 = T, std::enable_if_t<DataModel::IsFabricScoped<T0>::value, bool> = true>
164255
bool Next()
165256
{
166-
bool hasNext = DoNext();
257+
bool hasNext = IteratorBase::Next() && DecodeValue();
167258

168-
if (hasNext && mFabricIndex.HasValue())
259+
if (hasNext && this->mFabricIndex.HasValue())
169260
{
170-
mValue.SetFabricIndex(mFabricIndex.Value());
261+
mValue.SetFabricIndex(this->mFabricIndex.Value());
171262
}
172263

173264
return hasNext;
@@ -179,36 +270,10 @@ class DecodableList : public detail::DecodableListBase
179270
*/
180271
const T & GetValue() const { return mValue; }
181272

182-
/*
183-
* Returns the result of all previous operations on this iterator.
184-
*
185-
* Notably, if the end-of-list was encountered in a previous call to Next,
186-
* the status returned shall be CHIP_NO_ERROR.
187-
*/
188-
CHIP_ERROR GetStatus() const
189-
{
190-
if (mStatus == CHIP_END_OF_TLV)
191-
{
192-
return CHIP_NO_ERROR;
193-
}
194-
195-
return mStatus;
196-
}
197-
198273
private:
199-
bool DoNext()
274+
bool DecodeValue()
200275
{
201-
if (mReader.GetContainerType() == TLV::kTLVType_NotSpecified)
202-
{
203-
return false;
204-
}
205-
206-
if (mStatus == CHIP_NO_ERROR)
207-
{
208-
mStatus = mReader.Next();
209-
}
210-
211-
if (mStatus == CHIP_NO_ERROR)
276+
if (this->mStatus == CHIP_NO_ERROR)
212277
{
213278
//
214279
// Re-construct mValue to reset its state back to cluster object defaults.
@@ -218,22 +283,29 @@ class DecodableList : public detail::DecodableListBase
218283
// data from previous decode attempts will continue to linger and give
219284
// an incorrect view of the state as seen from a client.
220285
//
221-
mValue = T();
222-
mStatus = DataModel::Decode(mReader, mValue);
286+
mValue = T();
287+
this->mStatus = DataModel::Decode(this->mReader, mValue);
223288
}
224289

225-
return (mStatus == CHIP_NO_ERROR);
290+
return (this->mStatus == CHIP_NO_ERROR);
226291
}
227292

228293
T mValue;
229-
CHIP_ERROR mStatus;
230-
TLV::TLVReader mReader;
231-
// TODO: Consider some setup where this field does not exist when T
232-
// is not a fabric scoped struct.
233-
const Optional<FabricIndex> mFabricIndex;
234294
};
235295

236-
Iterator begin() const { return Iterator(mReader, mFabricIndex); }
296+
// Need this->mReader and this->mFabricIndex for the name lookup to realize
297+
// those can be found in our superclasses.
298+
template <typename T0 = T, std::enable_if_t<DataModel::IsFabricScoped<T0>::value, bool> = true>
299+
Iterator begin() const
300+
{
301+
return Iterator(this->mReader, this->mFabricIndex);
302+
}
303+
304+
template <typename T0 = T, std::enable_if_t<!DataModel::IsFabricScoped<T0>::value, bool> = true>
305+
Iterator begin() const
306+
{
307+
return Iterator(this->mReader);
308+
}
237309
};
238310

239311
} // namespace DataModel

‎src/controller/java/OTAProviderDelegateBridge.cpp

+4-5
Original file line numberDiff line numberDiff line change
@@ -154,11 +154,10 @@ void OTAProviderDelegateBridge::HandleQueryImage(CommandHandler * commandObj, co
154154
VendorId vendorId = commandData.vendorID;
155155
uint16_t productId = commandData.productID;
156156
uint32_t softwareVersion = commandData.softwareVersion;
157-
DataModel::DecodableList<OTADownloadProtocol> protocolsSupported = commandData.protocolsSupported;
158-
Optional<uint16_t> hardwareVersion = commandData.hardwareVersion;
159-
Optional<chip::CharSpan> location = commandData.location;
160-
Optional<bool> requestorCanConsent = commandData.requestorCanConsent;
161-
Optional<chip::ByteSpan> metadataForProvider = commandData.metadataForProvider;
157+
Optional<uint16_t> hardwareVersion = commandData.hardwareVersion;
158+
Optional<chip::CharSpan> location = commandData.location;
159+
Optional<bool> requestorCanConsent = commandData.requestorCanConsent;
160+
Optional<chip::ByteSpan> metadataForProvider = commandData.metadataForProvider;
162161

163162
bool isBDXProtocolSupported = false;
164163

‎src/controller/tests/TestEventChunking.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,6 @@ void TestReadCallback::OnAttributeData(const app::ConcreteDataAttributePath & aP
187187
{
188188
app::DataModel::DecodableList<ByteSpan> v;
189189
EXPECT_EQ(app::DataModel::Decode(*apData, v), CHIP_NO_ERROR);
190-
auto it = v.begin();
191190
size_t arraySize = 0;
192191
EXPECT_EQ(v.ComputeSize(&arraySize), CHIP_NO_ERROR);
193192
EXPECT_EQ(arraySize, 4u);

0 commit comments

Comments
 (0)