@@ -26,8 +26,8 @@ namespace app {
26
26
27
27
AttributePathExpandIterator::AttributePathExpandIterator (DataModel::Provider * provider,
28
28
SingleLinkedListNode<AttributePathParams> * attributePath) :
29
- mDataModelProvider (provider),
30
- mpAttributePath (attributePath), mOutputPath (kInvalidEndpointId , kInvalidClusterId , kInvalidAttributeId )
29
+ mDataModelProvider (provider), mpAttributePath(attributePath),
30
+ mOutputPath (kInvalidEndpointId , kInvalidClusterId , kInvalidAttributeId )
31
31
32
32
{
33
33
mOutputPath .mExpanded = true ; // this is reset in 'next' if needed
@@ -165,7 +165,6 @@ void AttributePathExpandIterator::ResetCurrentCluster()
165
165
mOutputPath .mExpanded = true ; // we know this is a wildcard attribute
166
166
Next ();
167
167
}
168
-
169
168
bool AttributePathExpandIterator::AdvanceOutputPath ()
170
169
{
171
170
if (!mpAttributePath->mValue .IsWildcardPath ())
@@ -227,14 +226,204 @@ bool AttributePathExpandIterator::Next()
227
226
{
228
227
return true ;
229
228
}
230
- mpAttributePath = mpAttributePath->mpNext ;
231
- mOutputPath = ConcreteReadAttributePath (kInvalidEndpointId , kInvalidClusterId , kInvalidAttributeId );
229
+ mpAttributePath = mpAttributePath->mpNext ;
230
+ mOutputPath = ConcreteReadAttributePath (kInvalidEndpointId , kInvalidClusterId , kInvalidAttributeId );
231
+
232
232
mOutputPath .mExpanded = true ; // this is reset to false on advancement if needed
233
233
}
234
234
235
235
mOutputPath = ConcreteReadAttributePath ();
236
236
return false ;
237
237
}
238
238
239
+ // /// 2nd implementation
240
+
241
+ bool AttributePathExpandIterator2::AdvanceOutputPath ()
242
+ {
243
+ if (!mState .mAttributePath ->mValue .IsWildcardPath ())
244
+ {
245
+ if (mState .mLastOutputPath .mEndpointId != kInvalidEndpointId )
246
+ {
247
+ return false ; // cannot expand non-wildcard path
248
+ }
249
+
250
+ mState .mLastOutputPath .mEndpointId = mState .mAttributePath ->mValue .mEndpointId ;
251
+ mState .mLastOutputPath .mClusterId = mState .mAttributePath ->mValue .mClusterId ;
252
+ mState .mLastOutputPath .mAttributeId = mState .mAttributePath ->mValue .mAttributeId ;
253
+ mState .mLastOutputPath .mExpanded = false ;
254
+ return true ;
255
+ }
256
+
257
+ while (true )
258
+ {
259
+ if (mState .mLastOutputPath .mClusterId != kInvalidClusterId )
260
+ {
261
+
262
+ std::optional<AttributeId> nextAttribute = NextAttributeId ();
263
+ if (nextAttribute.has_value ())
264
+ {
265
+ mState .mLastOutputPath .mAttributeId = *nextAttribute;
266
+ return true ;
267
+ }
268
+ }
269
+
270
+ // no valid attribute, try to advance the cluster, see if a suitable one exists
271
+ if (mState .mLastOutputPath .mEndpointId != kInvalidEndpointId )
272
+ {
273
+ std::optional<ClusterId> nextCluster = NextClusterId ();
274
+ if (nextCluster.has_value ())
275
+ {
276
+ mState .mLastOutputPath .mClusterId = *nextCluster;
277
+ mState .mLastOutputPath .mAttributeId = kInvalidAttributeId ; // restarts attributes
278
+ continue ;
279
+ }
280
+ }
281
+
282
+ // no valid cluster, try advance the endpoint, see if a suitable on exists
283
+ std::optional<EndpointId> nextEndpoint = NextEndpointId ();
284
+ if (nextEndpoint.has_value ())
285
+ {
286
+ mState .mLastOutputPath .mEndpointId = *nextEndpoint;
287
+ mState .mLastOutputPath .mClusterId = kInvalidClusterId ; // restarts clusters
288
+ continue ;
289
+ }
290
+ return false ;
291
+ }
292
+ }
293
+
294
+ bool AttributePathExpandIterator2::Next (ConcreteAttributePath & path)
295
+ {
296
+ while (mState .mAttributePath != nullptr )
297
+ {
298
+ if (AdvanceOutputPath ())
299
+ {
300
+ path = mState .mLastOutputPath ;
301
+ return true ;
302
+ }
303
+ mState .mAttributePath = mState .mAttributePath ->mpNext ;
304
+ mState .mLastOutputPath = ConcreteReadAttributePath (kInvalidEndpointId , kInvalidClusterId , kInvalidAttributeId );
305
+ mState .mLastOutputPath .mExpanded = true ; // this is reset to false on advancement if needed
306
+ }
307
+
308
+ return false ;
309
+ }
310
+
311
+ bool AttributePathExpandIterator2::IsValidAttributeId (AttributeId attributeId)
312
+ {
313
+ switch (attributeId)
314
+ {
315
+ case Clusters::Globals::Attributes::GeneratedCommandList::Id:
316
+ case Clusters::Globals::Attributes::AcceptedCommandList::Id:
317
+ case Clusters::Globals::Attributes::AttributeList::Id:
318
+ return true ;
319
+ default :
320
+ break ;
321
+ }
322
+
323
+ const ConcreteAttributePath attributePath (mState .mLastOutputPath .mEndpointId , mState .mLastOutputPath .mClusterId , attributeId);
324
+ return mDataModelProvider ->GetAttributeInfo (attributePath).has_value ();
325
+ }
326
+
327
+ std::optional<AttributeId> AttributePathExpandIterator2::NextAttributeId ()
328
+ {
329
+ if (mState .mLastOutputPath .mAttributeId == kInvalidAttributeId )
330
+ {
331
+ if (mState .mAttributePath ->mValue .HasWildcardAttributeId ())
332
+ {
333
+ AttributeEntry entry = mDataModelProvider ->FirstAttribute (mState .mLastOutputPath );
334
+ return entry.IsValid () //
335
+ ? entry.path .mAttributeId //
336
+ : Clusters::Globals::Attributes::GeneratedCommandList::Id; //
337
+ }
338
+
339
+ // We allow fixed attribute IDs if and only if they are valid:
340
+ // - they may be GLOBAL attributes OR
341
+ // - they are valid attributes for this cluster
342
+ if (IsValidAttributeId (mState .mAttributePath ->mValue .mAttributeId ))
343
+ {
344
+ return mState .mAttributePath ->mValue .mAttributeId ;
345
+ }
346
+
347
+ return std::nullopt;
348
+ }
349
+
350
+ // advance the existing attribute id if it can be advanced
351
+ VerifyOrReturnValue (mState .mAttributePath ->mValue .HasWildcardAttributeId (), std::nullopt);
352
+
353
+ // Ensure (including ordering) that GlobalAttributesNotInMetadata is reported as needed
354
+ for (unsigned i = 0 ; i < ArraySize (GlobalAttributesNotInMetadata); i++)
355
+ {
356
+ if (GlobalAttributesNotInMetadata[i] != mState .mLastOutputPath .mAttributeId )
357
+ {
358
+ continue ;
359
+ }
360
+
361
+ unsigned nextAttributeIndex = i + 1 ;
362
+ if (nextAttributeIndex < ArraySize (GlobalAttributesNotInMetadata))
363
+ {
364
+ return GlobalAttributesNotInMetadata[nextAttributeIndex];
365
+ }
366
+
367
+ // reached the end of global attributes
368
+ return std::nullopt;
369
+ }
370
+
371
+ AttributeEntry entry = mDataModelProvider ->NextAttribute (mState .mLastOutputPath );
372
+ if (entry.IsValid ())
373
+ {
374
+ return entry.path .mAttributeId ;
375
+ }
376
+
377
+ // Finished the data model, start with global attributes
378
+ static_assert (ArraySize (GlobalAttributesNotInMetadata) > 0 );
379
+ return GlobalAttributesNotInMetadata[0 ];
380
+ }
381
+
382
+ std::optional<ClusterId> AttributePathExpandIterator2::NextClusterId ()
383
+ {
384
+
385
+ if (mState .mLastOutputPath .mClusterId == kInvalidClusterId )
386
+ {
387
+ if (mState .mAttributePath ->mValue .HasWildcardClusterId ())
388
+ {
389
+ ClusterEntry entry = mDataModelProvider ->FirstServerCluster (mState .mLastOutputPath .mEndpointId );
390
+ return entry.IsValid () ? std::make_optional (entry.path .mClusterId ) : std::nullopt;
391
+ }
392
+
393
+ // only return a cluster if it is valid
394
+ const ConcreteClusterPath clusterPath (mState .mLastOutputPath .mEndpointId , mState .mAttributePath ->mValue .mClusterId );
395
+ if (!mDataModelProvider ->GetServerClusterInfo (clusterPath).has_value ())
396
+ {
397
+ return std::nullopt;
398
+ }
399
+
400
+ return mState .mAttributePath ->mValue .mClusterId ;
401
+ }
402
+
403
+ VerifyOrReturnValue (mState .mAttributePath ->mValue .HasWildcardClusterId (), std::nullopt);
404
+
405
+ ClusterEntry entry = mDataModelProvider ->NextServerCluster (mState .mLastOutputPath );
406
+ return entry.IsValid () ? std::make_optional (entry.path .mClusterId ) : std::nullopt;
407
+ }
408
+
409
+ std::optional<ClusterId> AttributePathExpandIterator2::NextEndpointId ()
410
+ {
411
+ if (mState .mLastOutputPath .mEndpointId == kInvalidEndpointId )
412
+ {
413
+ if (mState .mAttributePath ->mValue .HasWildcardEndpointId ())
414
+ {
415
+ EndpointEntry ep = mDataModelProvider ->FirstEndpoint ();
416
+ return (ep.id != kInvalidEndpointId ) ? std::make_optional (ep.id ) : std::nullopt;
417
+ }
418
+
419
+ return mState .mAttributePath ->mValue .mEndpointId ;
420
+ }
421
+
422
+ VerifyOrReturnValue (mState .mAttributePath ->mValue .HasWildcardEndpointId (), std::nullopt);
423
+
424
+ EndpointEntry ep = mDataModelProvider ->NextEndpoint (mState .mLastOutputPath .mEndpointId );
425
+ return (ep.id != kInvalidEndpointId ) ? std::make_optional (ep.id ) : std::nullopt;
426
+ }
427
+
239
428
} // namespace app
240
429
} // namespace chip
0 commit comments