Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch DataModel::Provider to a span-based list iterator - flash and ram savings, simpler interface #37033

Merged
merged 192 commits into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from 181 commits
Commits
Show all changes
192 commits
Select commit Hold shift + click to select a range
222d5fc
Copied over the new AttributePathExpandIterator and will incrementall…
andreilitvin Jan 7, 2025
8edc026
Rename AttributePathExpandIterator to legacy
andreilitvin Jan 7, 2025
2d4e3ad
Prepare for using new style iterators ... checking NOT YET enabled th…
andreilitvin Jan 7, 2025
3b2c14d
Enabled checks ... and unit tests fail, but this now can be debugged
andreilitvin Jan 7, 2025
27f6fdc
Fix some of the underlying bugs: read handling logic assumes we are o…
andreilitvin Jan 7, 2025
a458140
Unit tests pass now
andreilitvin Jan 7, 2025
26a5b69
Restyle
andreilitvin Jan 7, 2025
b72fc9b
Use new iterator in IME
andreilitvin Jan 7, 2025
e764906
Update logic to use the new iterator on testRead
andreilitvin Jan 7, 2025
bb3be30
more updates
andreilitvin Jan 7, 2025
5b5a612
Restyle
andreilitvin Jan 7, 2025
c566826
Remove the legacy attribute path expand iterator
andreilitvin Jan 7, 2025
04d6626
Update naming
andreilitvin Jan 7, 2025
fef425f
Restyle
andreilitvin Jan 7, 2025
56b1307
Remove extra argument for ReadHandler constructor
andreilitvin Jan 7, 2025
bf8c4ba
Restyle
andreilitvin Jan 7, 2025
7d4475b
Slight flash improvement
andreilitvin Jan 7, 2025
652e389
Fix up includes
andreilitvin Jan 7, 2025
4fa0fc8
Removed empty line
andreilitvin Jan 7, 2025
4a4ec3e
added comment on why state is a friend class
andreilitvin Jan 7, 2025
bc52596
Comment updates
andreilitvin Jan 7, 2025
93079a2
Restyle, add some comments and add extra checks on validity check onl…
andreilitvin Jan 7, 2025
c05d9f9
Merge branch 'master' into attribute-path-expand-state
andy31415 Jan 8, 2025
75bb1c1
Remove an include
andy31415 Jan 8, 2025
851928a
Comment updates, renamed mLastOutputPath to mOutputPath
andy31415 Jan 8, 2025
5024a4a
Fix one typo
andy31415 Jan 8, 2025
6266f96
Re-arrange members of ReadHandler to optimize for memory layout. This…
andy31415 Jan 8, 2025
a080dcf
Restyle
andy31415 Jan 8, 2025
b9a5d1d
Rename State to Position
andy31415 Jan 8, 2025
6fe8461
One more rename
andy31415 Jan 8, 2025
255cffe
Remove redundant assigment ...we are at a net 0 txt increase now on qpg
andy31415 Jan 8, 2025
ed950cf
Add more unit tests for non-obvious requirement that wildcard expansi…
andy31415 Jan 8, 2025
2e2ebd3
Update src/app/AttributePathExpandIterator.cpp
andy31415 Jan 8, 2025
130c1f6
Update src/app/AttributePathExpandIterator.h
andy31415 Jan 8, 2025
a610782
Update src/app/AttributePathExpandIterator.h
andy31415 Jan 8, 2025
e30ae74
Update src/app/AttributePathExpandIterator.h
andy31415 Jan 8, 2025
f9cd8f5
Update src/app/ReadHandler.h
andy31415 Jan 8, 2025
aeecc5c
Update src/app/ReadHandler.cpp
andy31415 Jan 8, 2025
57198a6
Update src/app/AttributePathExpandIterator.h
andy31415 Jan 8, 2025
75173d3
Use different values for the cluster ids for testing
andy31415 Jan 8, 2025
0bbdee6
Merge branch 'attribute-path-expand-state' of github.com:andy31415/co…
andy31415 Jan 8, 2025
04d27ba
One more state to position change
andy31415 Jan 8, 2025
75564bf
mExpanded is now set during output path returning. Removed 2 more set…
andy31415 Jan 8, 2025
8fce5b2
Merge branch 'attribute-path-expand-state' into list-metadata-prototype
andreilitvin Jan 9, 2025
3abc7e7
Import metadatalist class and test
andreilitvin Jan 9, 2025
f2470b6
Merge branch 'master' into attribute-path-expand-state
andreilitvin Jan 9, 2025
91e8547
Remove some tests that seem redundant, keep only one
andreilitvin Jan 9, 2025
bc8f162
Merge branch 'attribute-path-expand-state' into list-metadata-prototype
andreilitvin Jan 9, 2025
28ab9e3
Start with generated commands, see if we can replace its usage...
andreilitvin Jan 9, 2025
ccd52a1
Unit tests for GeneratedCommands pass
andreilitvin Jan 9, 2025
fe441f0
Start with an implementation of accepted commands (no testing yet)
andreilitvin Jan 9, 2025
a29ae90
More tests pass
andreilitvin Jan 9, 2025
1245fd8
Updated AcceptedCommands as well .. unit tests pass
andreilitvin Jan 9, 2025
e45093a
Restyle
andreilitvin Jan 9, 2025
d8f1cfd
Fix namespaces
andreilitvin Jan 9, 2025
1bae4c6
Slight refactor. Code is still very much ugly
andreilitvin Jan 9, 2025
0966d48
A bit of refactor, code looks better and tests pass now
andreilitvin Jan 9, 2025
72f2940
Code compile for semantic tag ... made std::optional support non-triv…
andreilitvin Jan 9, 2025
1e115a4
Update test
andreilitvin Jan 9, 2025
1d5e718
Make chip::Optional be trivially destructible if the underlying type is.
andreilitvin Jan 9, 2025
f96d388
Update src/app/AttributePathExpandIterator.cpp
andy31415 Jan 10, 2025
5962c1c
Update src/app/AttributePathExpandIterator.cpp
andy31415 Jan 10, 2025
3b6557d
Update src/app/AttributePathExpandIterator.cpp
andy31415 Jan 10, 2025
c2e23a2
Update src/app/AttributePathExpandIterator.cpp
andy31415 Jan 10, 2025
740d1c7
Update src/app/InteractionModelEngine.cpp
andy31415 Jan 10, 2025
321bfc3
Update src/app/ReadHandler.h
andy31415 Jan 10, 2025
a131e01
Update src/app/AttributePathExpandIterator.h
andy31415 Jan 10, 2025
78bdf32
Update src/app/ReadHandler.h
andy31415 Jan 10, 2025
1c0cf18
Use mCompletePosition
andy31415 Jan 10, 2025
efa903f
Another rename
andy31415 Jan 10, 2025
5310cf8
Merge branch 'master' into attribute-path-expand-state
andy31415 Jan 10, 2025
b06a268
Undo submodule update
andy31415 Jan 10, 2025
917d4a8
Restyle
andy31415 Jan 10, 2025
e6e42f1
Remove extra char
andy31415 Jan 10, 2025
6f3b85e
Remove unused variable
andy31415 Jan 10, 2025
a503615
Merge branch 'master' into optional-trivial-destructible
andy31415 Jan 10, 2025
a4f3d29
Update comment text to not sound like graph parsing
andy31415 Jan 10, 2025
e6b8003
Rename method to be more descriptive
andy31415 Jan 10, 2025
6eb101b
Remove one more unused variable
andy31415 Jan 10, 2025
9de15ec
Update peek attribute iterator to rollback and update code logic a bi…
andy31415 Jan 10, 2025
99bc8a8
Merge branch 'optional-trivial-destructible' into list-metadata-proto…
andy31415 Jan 10, 2025
7c2ada4
Semantic tags conversion is done
andy31415 Jan 10, 2025
33d1faa
Restyle
andy31415 Jan 10, 2025
a5c5321
Migrate device types to the new format
andy31415 Jan 10, 2025
5f82494
update comment a bit
andy31415 Jan 10, 2025
9add2d3
Add unused marker for chip errors used for logging only
andy31415 Jan 10, 2025
5a53b64
Fix descriptor cluster
andy31415 Jan 10, 2025
a29016e
Fix microwave oven
andy31415 Jan 10, 2025
0247195
Merge branch 'master' into list-metadata-prototype
andy31415 Jan 10, 2025
9d6e69d
Restyle
andy31415 Jan 10, 2025
ee12400
Fix intentional bugprone-use-after-move
andy31415 Jan 10, 2025
0fca820
Merge branch 'master' into attribute-path-expand-state
andy31415 Jan 11, 2025
f845b45
Merge branch 'master' into optional-trivial-destructible
andy31415 Jan 11, 2025
604b8a1
Merge branch 'attribute-path-expand-state' into list-metadata-prototype
andy31415 Jan 11, 2025
cc1f57b
Merge branch 'optional-trivial-destructible' into list-metadata-proto…
andy31415 Jan 11, 2025
8d9a20c
Fix intentional bugprone-use-after-move
andy31415 Jan 11, 2025
ae5a112
Restyle
andy31415 Jan 11, 2025
217be3a
Merge branch 'master' into list-metadata-prototype
andy31415 Jan 11, 2025
c660c1b
Fix based on clang feedback
andy31415 Jan 13, 2025
e7f1f9c
Move endpoints to the new style of iteration
andy31415 Jan 13, 2025
140b2cd
Fix includes
andy31415 Jan 13, 2025
e8acd39
Fix includes
andy31415 Jan 13, 2025
4a71ae1
Fix includes
andy31415 Jan 13, 2025
5aee545
make it standard that test Providers are for now CodegenDataModelProv…
andy31415 Jan 13, 2025
8155339
Restyle
andy31415 Jan 13, 2025
f6c2d79
Minor update in logic: do the endpoint selection when next is called
andy31415 Jan 13, 2025
36a65b8
Allow startup to try to mark attributes dirty even if no provider exi…
andy31415 Jan 13, 2025
d15b0d2
Fix typo
andy31415 Jan 13, 2025
91181fc
Merge branch 'master' into list-metadata-prototype
andreilitvin Jan 14, 2025
33c9156
start implementing client clusters
andreilitvin Jan 14, 2025
beedb4b
Update ClientCluster logic
andreilitvin Jan 14, 2025
80790db
Restyle
andreilitvin Jan 14, 2025
6d834ea
Start defining the server cluster query
andreilitvin Jan 14, 2025
5b319f7
Actually use the new server cluster functionality
andreilitvin Jan 14, 2025
726349b
Fix an include
andreilitvin Jan 14, 2025
ddeab07
More include fixes
andreilitvin Jan 14, 2025
b227388
implement the get attributes and adapt unit tests
andreilitvin Jan 14, 2025
4858fbc
Restyle
andreilitvin Jan 14, 2025
63dd9a9
more updates to cleanup code. I am a bit concerned about O(n^2) attri…
andreilitvin Jan 14, 2025
6013fa6
Merge branch 'list-metadata-prototype' of github.com:andy31415/connec…
andy31415 Jan 14, 2025
3d20e14
Merge branch 'master' into list-metadata-prototype
andy31415 Jan 14, 2025
3cd9728
A rename and moved finder methods out of inline. Saves 650 bytes of f…
andy31415 Jan 15, 2025
a94080c
Update logic to centralize metadata list code with less templating
andy31415 Jan 15, 2025
dcc871e
move the generic metadata list to detail, add an assert on trivial de…
andy31415 Jan 15, 2025
d7ee8ef
Fix namespace prefix
andy31415 Jan 15, 2025
90bc88e
Save 70 bytes by using references in condensed for loops
andy31415 Jan 15, 2025
e7d7b52
Replace count-if because it seems to result in smaller code (46 bytes)
andy31415 Jan 15, 2025
431bc3d
Another find_if replacement
andy31415 Jan 15, 2025
0c9bac0
Replaced some find_if...we are down to 92 bytes on qpg
andy31415 Jan 15, 2025
9e06eaf
Replaced one more find-if, saving another 88 bytes of flash
andy31415 Jan 15, 2025
b83a3bb
Removed algorithm includes: these are slow and would like compile to …
andy31415 Jan 15, 2025
764095f
Save more flash ... we should be at a net negative now
andy31415 Jan 15, 2025
7f4308f
This seems to save even more
andy31415 Jan 15, 2025
adf8ced
More savings by more encode overrides ... this is silly...
andy31415 Jan 15, 2025
cc4583e
Fix typos
andy31415 Jan 15, 2025
ff84571
More explicit casting, removed 64-bit overrides
andy31415 Jan 15, 2025
dcaf229
Added one more check for freeing memory .Still need to track a leak t…
andy31415 Jan 15, 2025
7829cc9
Fix memory leak in assignment
andy31415 Jan 15, 2025
a8955b7
Self-review: fix includes
andy31415 Jan 15, 2025
01dc8b8
Self-review: fix includes
andy31415 Jan 15, 2025
63634ca
Self-review: fix includes
andy31415 Jan 15, 2025
ff0598b
Self-review: fix includes
andy31415 Jan 15, 2025
32346df
Update src/data-model-providers/codegen/CodegenDataModelProvider.cpp
andy31415 Jan 17, 2025
84a10fd
Update src/data-model-providers/codegen/CodegenDataModelProvider.cpp
andy31415 Jan 17, 2025
b62c26e
Update src/app/AttributePathExpandIterator.h
andy31415 Jan 17, 2025
9b0fd87
Update src/app/AttributePathExpandIterator.h
andy31415 Jan 17, 2025
05bb27c
Update src/app/clusters/descriptor/descriptor.cpp
andy31415 Jan 17, 2025
0cd941e
Update src/app/clusters/descriptor/descriptor.cpp
andy31415 Jan 17, 2025
3c1f695
Update src/app/data-model-provider/MetadataList.cpp
andy31415 Jan 17, 2025
6f9b3af
Fix spelling for acquire
andy31415 Jan 17, 2025
32701f4
Update src/app/data-model-provider/MetadataList.h
andy31415 Jan 17, 2025
7b1be5f
Update src/app/data-model-provider/MetadataList.h
andy31415 Jan 17, 2025
7cc6dce
Update src/app/data-model-provider/MetadataList.h
andy31415 Jan 17, 2025
78c6e37
Fix is_trivially_destructible
andy31415 Jan 17, 2025
271db45
Update src/app/data-model-provider/MetadataSearch.h
andy31415 Jan 17, 2025
e415b35
More fixes
andy31415 Jan 17, 2025
8368d11
Merge branch 'list-metadata-prototype' of github.com:andy31415/connec…
andy31415 Jan 17, 2025
a0377ac
Fix includes
andy31415 Jan 17, 2025
7b1bad8
Fix invalid check typo
andy31415 Jan 17, 2025
6c0cd2e
Fix comment
andy31415 Jan 17, 2025
ace5e21
Correct comment
andy31415 Jan 17, 2025
f91ca92
Updated comment
andy31415 Jan 17, 2025
cc10a80
Make logic between clusters/attributes/endpoints the same regarding n…
andy31415 Jan 17, 2025
9447bfe
Restyle
andy31415 Jan 17, 2025
36e048e
Update logic for IsDescentantof
andy31415 Jan 17, 2025
f38661b
Help compiler generate efficient code as we keep reusing the same poi…
andy31415 Jan 17, 2025
1c19e1b
clearer logic that we handle all cases
andy31415 Jan 17, 2025
f0ce7c6
Fixes
andy31415 Jan 17, 2025
444baab
Use calloc
andy31415 Jan 17, 2025
72ca0d7
Update comment
andy31415 Jan 17, 2025
2ae576a
Fix include
andy31415 Jan 17, 2025
70319f3
Fix casting
andy31415 Jan 17, 2025
7eeff88
Make cluster count functions from ember public API since they seem re…
andy31415 Jan 17, 2025
3e0915e
Also fix dynamic dispatch
andy31415 Jan 17, 2025
2f4289b
Merge branch 'master' into list-metadata-prototype
andy31415 Jan 17, 2025
99d891f
update enumeration entry
andy31415 Jan 17, 2025
194e0e5
another comment update
andy31415 Jan 17, 2025
252c6ca
Undo submodule update
andy31415 Jan 17, 2025
b734cd0
Rename metadata search to metadta lookup
andy31415 Jan 17, 2025
ba47516
Update metadata list methods to be all uppercase
andy31415 Jan 17, 2025
12ad52c
Fix more renames
andy31415 Jan 17, 2025
a7de4f1
Fix invalid cast
andy31415 Jan 18, 2025
e7e02d7
Update src/data-model-providers/codegen/CodegenDataModelProvider.cpp
andy31415 Jan 18, 2025
5e44d69
Update src/data-model-providers/codegen/CodegenDataModelProvider.cpp
andy31415 Jan 18, 2025
ad1c7a7
Update src/data-model-providers/codegen/CodegenDataModelProvider.cpp
andy31415 Jan 18, 2025
64555ab
Update src/app/data-model-provider/MetadataList.h
andy31415 Jan 18, 2025
1c9d034
Address comments
andy31415 Jan 18, 2025
5730e6f
fix bug
andy31415 Jan 18, 2025
58ab136
Update src/app/AttributePathExpandIterator.cpp
andy31415 Jan 20, 2025
4ebdca1
Update src/app/WriteHandler.cpp
andy31415 Jan 20, 2025
e1a1414
Update src/app/AttributePathExpandIterator.cpp
andy31415 Jan 20, 2025
4b0b73a
Restyle and include update
andy31415 Jan 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion examples/common/pigweed/rpc_services/Attributes.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <app/InteractionModelEngine.h>
#include <app/MessageDef/AttributeReportIBs.h>
#include <app/data-model-provider/ActionReturnStatus.h>
#include <app/data-model-provider/MetadataLookup.h>
#include <app/data-model-provider/OperationTypes.h>
#include <app/data-model-provider/Provider.h>
#include <app/util/attribute-storage.h>
Expand Down Expand Up @@ -221,7 +222,9 @@ class Attributes : public pw_rpc::nanopb::Attributes::Service<Attributes>
request.operationFlags.Set(app::DataModel::OperationFlags::kInternal);
request.subjectDescriptor = &subjectDescriptor;

std::optional<app::DataModel::ClusterInfo> info = provider->GetServerClusterInfo(path);
app::DataModel::ServerClusterFinder serverClusterFinder(provider);
auto info = serverClusterFinder.Find(path);

if (!info.has_value())
{
return ::pw::Status::NotFound();
Expand Down
6 changes: 3 additions & 3 deletions src/access/ProviderDeviceTypeResolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ class DynamicProviderDeviceTypeResolver : public chip::Access::AccessControl::De

bool IsDeviceTypeOnEndpoint(chip::DeviceTypeId deviceType, chip::EndpointId endpoint) override
{
app::DataModel::Provider * model = mModelGetter();
for (auto type = model->FirstDeviceType(endpoint); type.has_value(); type = model->NextDeviceType(endpoint, *type))
auto deviceTypes = mModelGetter()->DeviceTypes(endpoint);
for (auto & type : deviceTypes.GetSpanValidForLifetime())
{
if (type->deviceTypeId == deviceType)
if (type.deviceTypeId == deviceType)
{
return true;
}
Expand Down
167 changes: 126 additions & 41 deletions src/app/AttributePathExpandIterator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
#include <app/AttributePathExpandIterator.h>

#include <app/GlobalAttributes.h>
#include <app/data-model-provider/MetadataLookup.h>
#include <app/data-model-provider/MetadataTypes.h>
#include <lib/core/DataModelTypes.h>
#include <lib/support/CodeUtils.h>

#include <optional>
Expand All @@ -26,6 +29,10 @@ using namespace chip::app::DataModel;
namespace chip {
namespace app {

AttributePathExpandIterator::AttributePathExpandIterator(DataModel::Provider * dataModel, Position & position) :
mDataModelProvider(dataModel), mPosition(position)
{}

bool AttributePathExpandIterator::AdvanceOutputPath()
{
/// Output path invariants
Expand Down Expand Up @@ -113,34 +120,58 @@ bool AttributePathExpandIterator::IsValidAttributeId(AttributeId attributeId)
break;
}

DataModel::AttributeFinder finder(mDataModelProvider);

const ConcreteAttributePath attributePath(mPosition.mOutputPath.mEndpointId, mPosition.mOutputPath.mClusterId, attributeId);
return mDataModelProvider->GetAttributeInfo(attributePath).has_value();
return finder.Find(attributePath).has_value();
}

std::optional<AttributeId> AttributePathExpandIterator::NextAttributeId()
{
if (mPosition.mOutputPath.mAttributeId == kInvalidAttributeId)
{
if (mPosition.mAttributePath->mValue.HasWildcardAttributeId())
mAttributeIndex = kInvalidIndex;
}

if (mAttributeIndex == kInvalidIndex)
{
// start a new iteration of attributes on the current cluster path.
mAttributes = mDataModelProvider->Attributes(mPosition.mOutputPath);

if (mPosition.mOutputPath.mAttributeId != kInvalidAttributeId)
{
AttributeEntry entry = mDataModelProvider->FirstAttribute(mPosition.mOutputPath);
return entry.IsValid() //
? entry.path.mAttributeId //
: Clusters::Globals::Attributes::GeneratedCommandList::Id; //
// Position on the correct attribute if we have a start point
mAttributeIndex = 0;
while ((mAttributeIndex < mAttributes.Size()) &&
(mAttributes[mAttributeIndex].attributeId != mPosition.mOutputPath.mAttributeId))
{
mAttributeIndex++;
}
}
}

// At this point, the attributeID is NOT a wildcard (i.e. it is fixed).
//
// For wildcard expansion, we validate that this is a valid attribute for the given
// cluster on the given endpoint. If not a wildcard expansion, return it as-is.
if (mPosition.mAttributePath->mValue.IsWildcardPath())
if (mPosition.mOutputPath.mAttributeId == kInvalidAttributeId)
{
if (!mPosition.mAttributePath->mValue.HasWildcardAttributeId())
{
if (!IsValidAttributeId(mPosition.mAttributePath->mValue.mAttributeId))
// The attributeID is NOT a wildcard (i.e. it is fixed).
//
// For wildcard expansion, we validate that this is a valid attribute for the given
// cluster on the given endpoint. If not a wildcard expansion, return it as-is.
if (mPosition.mAttributePath->mValue.IsWildcardPath())
{
return std::nullopt;
if (!IsValidAttributeId(mPosition.mAttributePath->mValue.mAttributeId))
{
return std::nullopt;
}
}
return mPosition.mAttributePath->mValue.mAttributeId;
}
return mPosition.mAttributePath->mValue.mAttributeId;
mAttributeIndex = 0;
}
else
{
mAttributeIndex++;
}

// Advance the existing attribute id if it can be advanced.
Expand All @@ -165,10 +196,9 @@ std::optional<AttributeId> AttributePathExpandIterator::NextAttributeId()
return std::nullopt;
}

AttributeEntry entry = mDataModelProvider->NextAttribute(mPosition.mOutputPath);
if (entry.IsValid())
if (mAttributeIndex < mAttributes.Size())
{
return entry.path.mAttributeId;
return mAttributes[mAttributeIndex].attributeId;
}

// Finished the data model, start with global attributes
Expand All @@ -178,55 +208,110 @@ std::optional<AttributeId> AttributePathExpandIterator::NextAttributeId()

std::optional<ClusterId> AttributePathExpandIterator::NextClusterId()
{

if (mPosition.mOutputPath.mClusterId == kInvalidClusterId)
{
if (mPosition.mAttributePath->mValue.HasWildcardClusterId())
mClusterIndex = kInvalidIndex;
}

if (mClusterIndex == kInvalidIndex)
{
// start a new iteration on the current endpoint
mClusters = mDataModelProvider->ServerClusters(mPosition.mOutputPath.mEndpointId);

if (mPosition.mOutputPath.mClusterId != kInvalidClusterId)
{
ClusterEntry entry = mDataModelProvider->FirstServerCluster(mPosition.mOutputPath.mEndpointId);
return entry.IsValid() ? std::make_optional(entry.path.mClusterId) : std::nullopt;
// Position on the correct cluster if we have a start point
mClusterIndex = 0;
while ((mClusterIndex < mClusters.Size()) && (mClusters[mClusterIndex].clusterId != mPosition.mOutputPath.mClusterId))
{
mClusterIndex++;
}
}
}

// At this point, the clusterID is NOT a wildcard (i.e. is fixed).
//
// For wildcard expansion, we validate that this is a valid cluster for the endpoint.
// If non-wildcard expansion, we return as-is.
if (mPosition.mAttributePath->mValue.IsWildcardPath())
if (mPosition.mOutputPath.mClusterId == kInvalidClusterId)
{

if (!mPosition.mAttributePath->mValue.HasWildcardClusterId())
{
const ConcreteClusterPath clusterPath(mPosition.mOutputPath.mEndpointId, mPosition.mAttributePath->mValue.mClusterId);
if (!mDataModelProvider->GetServerClusterInfo(clusterPath).has_value())
// The clusterID is NOT a wildcard (i.e. is fixed).
//
// For wildcard expansion, we validate that this is a valid cluster for the endpoint.
// If non-wildcard expansion, we return as-is.
if (mPosition.mAttributePath->mValue.IsWildcardPath())
{
return std::nullopt;
const ClusterId clusterId = mPosition.mAttributePath->mValue.mClusterId;

auto span = mClusters.GetSpanValidForLifetime();

bool found = false;
for (auto & entry : span)
{
if (entry.clusterId == clusterId)
{
found = true;
break;
}
}

if (!found)
{
return std::nullopt;
}
}
}

return mPosition.mAttributePath->mValue.mClusterId;
return mPosition.mAttributePath->mValue.mClusterId;
}
mClusterIndex = 0;
}
else
{
mClusterIndex++;
}

VerifyOrReturnValue(mPosition.mAttributePath->mValue.HasWildcardClusterId(), std::nullopt);
VerifyOrReturnValue(mClusterIndex < mClusters.Size(), std::nullopt);

ClusterEntry entry = mDataModelProvider->NextServerCluster(mPosition.mOutputPath);
return entry.IsValid() ? std::make_optional(entry.path.mClusterId) : std::nullopt;
return mClusters[mClusterIndex].clusterId;
}

std::optional<ClusterId> AttributePathExpandIterator::NextEndpointId()
std::optional<EndpointId> AttributePathExpandIterator::NextEndpointId()
{
if (mEndpointIndex == kInvalidIndex)
{
// index is missing, have to start a new iteration
mEndpoints = mDataModelProvider->Endpoints();

if (mPosition.mOutputPath.mEndpointId != kInvalidEndpointId)
{
// Position on the correct endpoint if we have a start point
mEndpointIndex = 0;
while ((mEndpointIndex < mEndpoints.Size()) && (mEndpoints[mEndpointIndex].id != mPosition.mOutputPath.mEndpointId))
{
mEndpointIndex++;
}
}
}

if (mPosition.mOutputPath.mEndpointId == kInvalidEndpointId)
{
if (mPosition.mAttributePath->mValue.HasWildcardEndpointId())
if (!mPosition.mAttributePath->mValue.HasWildcardEndpointId())
{
EndpointEntry ep = mDataModelProvider->FirstEndpoint();
return (ep.id != kInvalidEndpointId) ? std::make_optional(ep.id) : std::nullopt;
return mPosition.mAttributePath->mValue.mEndpointId;
}

return mPosition.mAttributePath->mValue.mEndpointId;
// start from the beginning
mEndpointIndex = 0;
}
else
{
mEndpointIndex++;
}

// Expand endpoints only if it is a wildcard on the endpoint specifically.
VerifyOrReturnValue(mPosition.mAttributePath->mValue.HasWildcardEndpointId(), std::nullopt);
VerifyOrReturnValue(mEndpointIndex < mEndpoints.Size(), std::nullopt);

EndpointEntry ep = mDataModelProvider->NextEndpoint(mPosition.mOutputPath.mEndpointId);
return (ep.id != kInvalidEndpointId) ? std::make_optional(ep.id) : std::nullopt;
return mEndpoints[mEndpointIndex].id;
}

} // namespace app
Expand Down
22 changes: 18 additions & 4 deletions src/app/AttributePathExpandIterator.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,14 @@

#include <app/AttributePathParams.h>
#include <app/ConcreteAttributePath.h>
#include <app/data-model-provider/MetadataList.h>
#include <app/data-model-provider/MetadataTypes.h>
#include <app/data-model-provider/Provider.h>
#include <lib/core/DataModelTypes.h>
#include <lib/support/LinkedList.h>
#include <lib/support/Span.h>

#include <limits>

namespace chip {
namespace app {
Expand Down Expand Up @@ -96,9 +101,7 @@ class AttributePathExpandIterator
ConcreteAttributePath mOutputPath;
};

AttributePathExpandIterator(DataModel::Provider * dataModel, Position & position) :
mDataModelProvider(dataModel), mPosition(position)
{}
AttributePathExpandIterator(DataModel::Provider * dataModel, Position & position);

// This class may not be copied. A new one should be created when needed and they
// should not overlap.
Expand All @@ -113,9 +116,20 @@ class AttributePathExpandIterator
bool Next(ConcreteAttributePath & path);

private:
static constexpr size_t kInvalidIndex = std::numeric_limits<size_t>::max();

DataModel::Provider * mDataModelProvider;
Position & mPosition;

DataModel::MetadataList<DataModel::EndpointEntry> mEndpoints; // all endpoints
size_t mEndpointIndex = kInvalidIndex;

DataModel::MetadataList<DataModel::ServerClusterEntry> mClusters; // all clusters ON THE CURRENT endpoint
size_t mClusterIndex = kInvalidIndex;

DataModel::MetadataList<DataModel::AttributeEntry> mAttributes; // all attributes ON THE CURRENT cluster
size_t mAttributeIndex = kInvalidIndex;

/// Move to the next endpoint/cluster/attribute triplet that is valid given
/// the current mOutputPath and mpAttributePath.
///
Expand All @@ -140,7 +154,7 @@ class AttributePathExpandIterator
/// Will start from the beginning if current mOutputPath.mEndpointId is kInvalidEndpointId
///
/// Respects path expansion/values in mpAttributePath
std::optional<ClusterId> NextEndpointId();
std::optional<EndpointId> NextEndpointId();

/// Checks if the given attributeId is valid for the current mOutputPath(endpoint/cluster)
///
Expand Down
28 changes: 28 additions & 0 deletions src/app/AttributeValueEncoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,34 @@ class AttributeValueEncoder
return mAttributeValueEncoder.EncodeListItem(mCheckpoint, aArg);
}

// overrides that save flash: no need to care about the extra const
// Without this, we have a usage of:
// chip::ChipError chip::app::AttributeValueEncoder::EncodeListItem<unsigned long const&>
// Overall we tend to have very similar code expand (from nm):
// chip::ChipError chip::app::AttributeValueEncoder::Encode<unsigned char>(unsigned char&&)
// chip::ChipError chip::app::AttributeValueEncoder::Encode<unsigned char&>(unsigned char&)
// chip::ChipError chip::app::AttributeValueEncoder::Encode<unsigned char const&>(unsigned char const&)
// chip::ChipError chip::app::AttributeValueEncoder::Encode<unsigned short const&>(unsigned short const&)
// chip::ChipError chip::app::AttributeValueEncoder::Encode<unsigned long&>(unsigned long&)
// chip::ChipError chip::app::AttributeValueEncoder::Encode<unsigned short&>(unsigned short&)
// chip::ChipError chip::app::AttributeValueEncoder::Encode<unsigned long long&>(unsigned long long&)
// chip::ChipError chip::app::AttributeValueEncoder::Encode<unsigned short>(unsigned short&&)
// chip::ChipError chip::app::AttributeValueEncoder::Encode<unsigned long long>(unsigned long long&&)
// that we try to reduce
//
// TODO:
// - we should figure where the extra const override is used
// - we should try to avoid having such footguns. This list template-explosion seems
// dangerous for flash.
//
// This relies on TLV numbers always being encoded as 64-bit value
inline CHIP_ERROR Encode(uint32_t const & aArg) const { return Encode<uint64_t>(aArg); }
inline CHIP_ERROR Encode(uint32_t & aArg) const { return Encode<uint64_t>(aArg); }
inline CHIP_ERROR Encode(uint16_t const & aArg) const { return Encode<uint64_t>(aArg); }
inline CHIP_ERROR Encode(uint16_t & aArg) const { return Encode<uint64_t>(aArg); }
inline CHIP_ERROR Encode(uint8_t const & aArg) const { return Encode<uint64_t>(aArg); }
inline CHIP_ERROR Encode(uint8_t & aArg) const { return Encode<uint64_t>(aArg); }

private:
AttributeValueEncoder & mAttributeValueEncoder;
// Avoid calling the TLVWriter constructor for every instantiation of
Expand Down
Loading
Loading