Skip to content

Commit

Permalink
Prototype semantic tags implementation as well, to see if code size s…
Browse files Browse the repository at this point in the history
…tarts decreasing
  • Loading branch information
andy31415 committed Dec 18, 2024
1 parent d1a87c5 commit 0d0f93c
Show file tree
Hide file tree
Showing 9 changed files with 58 additions and 148 deletions.
5 changes: 2 additions & 3 deletions src/app/clusters/descriptor/descriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,10 @@ CHIP_ERROR DescriptorAttrAccess::ReadFeatureMap(EndpointId endpoint, AttributeVa
CHIP_ERROR DescriptorAttrAccess::ReadTagListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder)
{
return aEncoder.EncodeList([&endpoint](const auto & encoder) -> CHIP_ERROR {
auto tag = InteractionModelEngine::GetInstance()->GetDataModelProvider()->GetFirstSemanticTag(endpoint);
while (tag.has_value())
auto it = InteractionModelEngine::GetInstance()->GetDataModelProvider()->GetSemanticTags(endpoint);
for (auto tag = it->Next(); tag.has_value(); tag = it->Next())
{
ReturnErrorOnFailure(encoder.Encode(tag.value()));
tag = InteractionModelEngine::GetInstance()->GetDataModelProvider()->GetNextSemanticTag(endpoint, tag.value());
}
return CHIP_NO_ERROR;
});
Expand Down
9 changes: 1 addition & 8 deletions src/app/data-model-provider/MetadataTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,10 +208,7 @@ class ProviderMetadataTree
return std::make_unique<NullMetadataIterator<EndpointId, EndpointInfo>>();
}
virtual std::unique_ptr<ElementIterator<DeviceTypeEntry>> GetDeviceTypes(EndpointId endpointId) = 0;
virtual std::unique_ptr<ElementIterator<SemanticTag>> GetSemanticTags(EndpointId endpointId)
{
return std::make_unique<NullElementIterator<SemanticTag>>();
}
virtual std::unique_ptr<ElementIterator<SemanticTag>> GetSemanticTags(EndpointId endpointId) = 0;

virtual std::unique_ptr<MetaDataIterator<ClusterId, ClusterInfo>> GetServerClusters(EndpointId endpointId)
{
Expand Down Expand Up @@ -242,10 +239,6 @@ class ProviderMetadataTree
virtual std::optional<EndpointInfo> GetEndpointInfo(EndpointId id) = 0;
virtual bool EndpointExists(EndpointId id);

// This iteration describes semantic tags registered on an endpoint
virtual std::optional<SemanticTag> GetFirstSemanticTag(EndpointId endpoint) = 0;
virtual std::optional<SemanticTag> GetNextSemanticTag(EndpointId endpoint, const SemanticTag & previous) = 0;

// This iteration will list all server clusters on a given endpoint
virtual ClusterEntry FirstServerCluster(EndpointId endpoint) = 0;
virtual ClusterEntry NextServerCluster(const ConcreteClusterPath & before) = 0;
Expand Down
11 changes: 0 additions & 11 deletions src/app/tests/test-interaction-model-api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,17 +164,6 @@ std::optional<DataModel::EndpointInfo> TestImCustomDataModel::GetEndpointInfo(En
return CodegenDataModelProviderInstance(nullptr /* delegate */)->GetEndpointInfo(endpoint);
}

std::optional<DataModel::Provider::SemanticTag> TestImCustomDataModel::GetFirstSemanticTag(EndpointId endpoint)
{
return std::nullopt;
}

std::optional<DataModel::Provider::SemanticTag> TestImCustomDataModel::GetNextSemanticTag(EndpointId endpoint,
const SemanticTag & previous)
{
return std::nullopt;
}

ClusterEntry TestImCustomDataModel::FirstServerCluster(EndpointId endpoint)
{
return CodegenDataModelProviderInstance(nullptr /* delegate */)->FirstServerCluster(endpoint);
Expand Down
7 changes: 5 additions & 2 deletions src/app/tests/test-interaction-model-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,6 @@ class TestImCustomDataModel : public DataModel::Provider
DataModel::EndpointEntry FirstEndpoint() override;
DataModel::EndpointEntry NextEndpoint(EndpointId before) override;
std::optional<DataModel::EndpointInfo> GetEndpointInfo(EndpointId endpoint) override;
std::optional<SemanticTag> GetFirstSemanticTag(EndpointId endpoint) override;
std::optional<SemanticTag> GetNextSemanticTag(EndpointId endpoint, const SemanticTag & previous) override;
DataModel::ClusterEntry FirstServerCluster(EndpointId endpoint) override;
DataModel::ClusterEntry NextServerCluster(const ConcreteClusterPath & before) override;
std::optional<DataModel::ClusterInfo> GetServerClusterInfo(const ConcreteClusterPath & path) override;
Expand All @@ -135,6 +133,11 @@ class TestImCustomDataModel : public DataModel::Provider
{
return std::make_unique<DataModel::NullElementIterator<DataModel::DeviceTypeEntry>>();
}

std::unique_ptr<DataModel::ElementIterator<SemanticTag>> GetSemanticTags(EndpointId endpointId) override
{
return std::make_unique<DataModel::NullElementIterator<SemanticTag>>();
}
};

} // namespace app
Expand Down
11 changes: 0 additions & 11 deletions src/controller/tests/data_model/DataModelFixtures.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -492,17 +492,6 @@ std::optional<DataModel::EndpointInfo> CustomDataModel::GetEndpointInfo(Endpoint
return CodegenDataModelProviderInstance(nullptr /* delegate */)->GetEndpointInfo(endpoint);
}

std::optional<DataModel::Provider::SemanticTag> CustomDataModel::GetFirstSemanticTag(EndpointId endpoint)
{
return std::nullopt;
}

std::optional<DataModel::Provider::SemanticTag> CustomDataModel::GetNextSemanticTag(EndpointId endpoint,
const SemanticTag & previous)
{
return std::nullopt;
}

ClusterEntry CustomDataModel::FirstServerCluster(EndpointId endpoint)
{
return CodegenDataModelProviderInstance(nullptr /* delegate */)->FirstServerCluster(endpoint);
Expand Down
7 changes: 5 additions & 2 deletions src/controller/tests/data_model/DataModelFixtures.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,6 @@ class CustomDataModel : public DataModel::Provider
DataModel::EndpointEntry FirstEndpoint() override;
DataModel::EndpointEntry NextEndpoint(EndpointId before) override;
std::optional<DataModel::EndpointInfo> GetEndpointInfo(EndpointId endpoint) override;
std::optional<SemanticTag> GetFirstSemanticTag(EndpointId endpoint) override;
std::optional<SemanticTag> GetNextSemanticTag(EndpointId endpoint, const SemanticTag & previous) override;
DataModel::ClusterEntry FirstServerCluster(EndpointId endpoint) override;
DataModel::ClusterEntry NextServerCluster(const ConcreteClusterPath & before) override;
std::optional<DataModel::ClusterInfo> GetServerClusterInfo(const ConcreteClusterPath & path) override;
Expand All @@ -147,6 +145,11 @@ class CustomDataModel : public DataModel::Provider
{
return std::make_unique<DataModel::NullElementIterator<DataModel::DeviceTypeEntry>>();
}

std::unique_ptr<DataModel::ElementIterator<SemanticTag>> GetSemanticTags(EndpointId endpointId) override
{
return std::make_unique<DataModel::NullElementIterator<SemanticTag>>();
}
};

} // namespace DataModelTests
Expand Down
99 changes: 26 additions & 73 deletions src/data-model-providers/codegen/CodegenDataModelProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include <lib/support/CodeUtils.h>
#include <lib/support/SpanSearchValue.h>

#include <memory>
#include <optional>
#include <variant>

Expand Down Expand Up @@ -320,58 +321,6 @@ DataModel::EndpointEntry FirstEndpointEntry(unsigned start_index, uint16_t & fou
return DataModel::EndpointEntry::kInvalid;
}

bool operator==(const DataModel::Provider::SemanticTag & tagA, const DataModel::Provider::SemanticTag & tagB)
{
// Label is an optional and nullable value of CharSpan. Optional and Nullable have overload for ==,
// But `==` is deleted for CharSpan. Here we only check whether the string is the same.
if (tagA.label.HasValue() != tagB.label.HasValue())
{
return false;
}
if (tagA.label.HasValue())
{
if (tagA.label.Value().IsNull() != tagB.label.Value().IsNull())
{
return false;
}
if (!tagA.label.Value().IsNull())
{
if (!tagA.label.Value().Value().data_equal(tagB.label.Value().Value()))
{
return false;
}
}
}
return (tagA.tag == tagB.tag) && (tagA.mfgCode == tagB.mfgCode) && (tagA.namespaceID == tagB.namespaceID);
}

std::optional<unsigned> FindNextSemanticTagIndex(EndpointId endpoint, const DataModel::Provider::SemanticTag & previous,
unsigned hintWherePreviousMayBe)
{
DataModel::Provider::SemanticTag hintTag;
// Check whether the hint is the previous tag
if (GetSemanticTagForEndpointAtIndex(endpoint, hintWherePreviousMayBe, hintTag) == CHIP_NO_ERROR)
{
if (previous == hintTag)
{
return std::make_optional(hintWherePreviousMayBe + 1);
}
}
// If the hint is not the previous tag, iterate over all the tags to find the index for the previous tag
unsigned index = 0;
// Ensure that the next index is in the range
while (GetSemanticTagForEndpointAtIndex(endpoint, index + 1, hintTag) == CHIP_NO_ERROR &&
GetSemanticTagForEndpointAtIndex(endpoint, index, hintTag) == CHIP_NO_ERROR)
{
if (previous == hintTag)
{
return std::make_optional(index + 1);
}
index++;
}
return std::nullopt;
}

class DeviceTypeEntryIterator : public DataModel::ElementIterator<DataModel::DeviceTypeEntry>
{
public:
Expand All @@ -396,6 +345,29 @@ class DeviceTypeEntryIterator : public DataModel::ElementIterator<DataModel::Dev
Span<const EmberAfDeviceType> mDeviceTypes;
};

class SemanticTagIterator : public DataModel::ElementIterator<DataModel::Provider::SemanticTag>
{
public:
SemanticTagIterator(EndpointId endpointId) : mEndpointId(endpointId) {}

std::optional<DataModel::Provider::SemanticTag> Next() override
{
DataModel::Provider::SemanticTag tag;

if (GetSemanticTagForEndpointAtIndex(mEndpointId, mIndex, tag) == CHIP_NO_ERROR)
{
mIndex++;
return tag;
}
return std::nullopt;
}

private:
const EndpointId mEndpointId;
size_t mIndex = 0;

};

DefaultAttributePersistenceProvider gDefaultAttributePersistence;

} // namespace
Expand Down Expand Up @@ -894,28 +866,9 @@ CodegenDataModelProvider::GetDeviceTypes(EndpointId endpointId)
return std::make_unique<DeviceTypeEntryIterator>(emberAfDeviceTypeListFromEndpointIndex(*endpoint_index, err));
}

std::optional<DataModel::Provider::SemanticTag> CodegenDataModelProvider::GetFirstSemanticTag(EndpointId endpoint)
{
Clusters::Descriptor::Structs::SemanticTagStruct::Type tag;
// we start at the beginning
mSemanticTagIterationHint = 0;
if (GetSemanticTagForEndpointAtIndex(endpoint, 0, tag) == CHIP_NO_ERROR)
{
return std::make_optional(tag);
}
return std::nullopt;
}

std::optional<DataModel::Provider::SemanticTag> CodegenDataModelProvider::GetNextSemanticTag(EndpointId endpoint,
const SemanticTag & previous)
std::unique_ptr<DataModel::ElementIterator<DataModel::Provider::SemanticTag>> CodegenDataModelProvider::GetSemanticTags(EndpointId endpointId)
{
Clusters::Descriptor::Structs::SemanticTagStruct::Type tag;
std::optional<unsigned> idx = FindNextSemanticTagIndex(endpoint, previous, mSemanticTagIterationHint);
if (idx.has_value() && GetSemanticTagForEndpointAtIndex(endpoint, *idx, tag) == CHIP_NO_ERROR)
{
return std::make_optional(tag);
}
return std::nullopt;
return std::make_unique<SemanticTagIterator>(endpointId);
}

} // namespace app
Expand Down
6 changes: 1 addition & 5 deletions src/data-model-providers/codegen/CodegenDataModelProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,15 +156,13 @@ class CodegenDataModelProvider : public DataModel::Provider

/// attribute tree iteration
std::unique_ptr<DataModel::ElementIterator<DataModel::DeviceTypeEntry>> GetDeviceTypes(EndpointId endpointId) override;
std::unique_ptr<DataModel::ElementIterator<SemanticTag>> GetSemanticTags(EndpointId endpointId) override;

DataModel::EndpointEntry FirstEndpoint() override;
DataModel::EndpointEntry NextEndpoint(EndpointId before) override;
std::optional<DataModel::EndpointInfo> GetEndpointInfo(EndpointId endpoint) override;
bool EndpointExists(EndpointId endpoint) override;

std::optional<SemanticTag> GetFirstSemanticTag(EndpointId endpoint) override;
std::optional<SemanticTag> GetNextSemanticTag(EndpointId endpoint, const SemanticTag & previous) override;

DataModel::ClusterEntry FirstServerCluster(EndpointId endpoint) override;
DataModel::ClusterEntry NextServerCluster(const ConcreteClusterPath & before) override;
std::optional<DataModel::ClusterInfo> GetServerClusterInfo(const ConcreteClusterPath & path) override;
Expand Down Expand Up @@ -198,8 +196,6 @@ class CodegenDataModelProvider : public DataModel::Provider
unsigned mServerClusterIterationHint = 0;
unsigned mClientClusterIterationHint = 0;
unsigned mAttributeIterationHint = 0;
unsigned mDeviceTypeIterationHint = 0;
unsigned mSemanticTagIterationHint = 0;
EmberCommandListIterator mAcceptedCommandsIterator;
EmberCommandListIterator mGeneratedCommandsIterator;

Expand Down
51 changes: 18 additions & 33 deletions src/data-model-providers/codegen/tests/TestCodegenModelViaMocks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2744,53 +2744,38 @@ TEST(TestCodegenModelViaMocks, SemanticTagIteration)
CodegenDataModelProviderWithContext model;

// Mock endpoint 1 has 3 semantic tags
std::optional<DataModel::Provider::SemanticTag> tag = model.GetFirstSemanticTag(kMockEndpoint1);
auto it = model.GetSemanticTags(kMockEndpoint1);
ASSERT_TRUE(it.get() != nullptr);

std::optional<DataModel::Provider::SemanticTag> tag = it->Next();
ASSERT_TRUE(tag.has_value());
EXPECT_EQ(tag->mfgCode, MakeNullable(VendorId::TestVendor1)); // NOLINT(bugprone-unchecked-optional-access)
EXPECT_EQ(tag->namespaceID, kNamespaceID1); // NOLINT(bugprone-unchecked-optional-access)
EXPECT_EQ(tag->tag, kTag1); // NOLINT(bugprone-unchecked-optional-access)
ASSERT_TRUE(tag->label.HasValue() && (!tag->label.Value().IsNull())); // NOLINT(bugprone-unchecked-optional-access)
EXPECT_TRUE(
tag->label.Value().Value().data_equal(CharSpan::fromCharString(kLabel1))); // NOLINT(bugprone-unchecked-optional-access)
tag = model.GetNextSemanticTag(kMockEndpoint1, *tag); // NOLINT(bugprone-unchecked-optional-access)
ASSERT_TRUE(tag.has_value()); // NOLINT(bugprone-unchecked-optional-access)
EXPECT_TRUE(tag->mfgCode.IsNull()); // NOLINT(bugprone-unchecked-optional-access)
EXPECT_EQ(tag->namespaceID, kNamespaceID2); // NOLINT(bugprone-unchecked-optional-access)
EXPECT_EQ(tag->tag, kTag2); // NOLINT(bugprone-unchecked-optional-access)
ASSERT_TRUE(tag->label.HasValue() && (!tag->label.Value().IsNull())); // NOLINT(bugprone-unchecked-optional-access)
EXPECT_TRUE(
tag->label.Value().Value().data_equal(CharSpan::fromCharString(kLabel2))); // NOLINT(bugprone-unchecked-optional-access)
tag = model.GetNextSemanticTag(kMockEndpoint1, *tag); // NOLINT(bugprone-unchecked-optional-access)
ASSERT_TRUE(tag.has_value()); // NOLINT(bugprone-unchecked-optional-access)
EXPECT_EQ(tag->mfgCode, MakeNullable(VendorId::TestVendor3)); // NOLINT(bugprone-unchecked-optional-access)
EXPECT_EQ(tag->namespaceID, kNamespaceID3); // NOLINT(bugprone-unchecked-optional-access)
EXPECT_EQ(tag->tag, kTag3); // NOLINT(bugprone-unchecked-optional-access)
EXPECT_FALSE(tag->label.HasValue()); // NOLINT(bugprone-unchecked-optional-access)
tag = model.GetNextSemanticTag(kMockEndpoint1, *tag); // NOLINT(bugprone-unchecked-optional-access)
EXPECT_FALSE(tag.has_value());

// out of order query works
DataModel::Provider::SemanticTag existTag = {
.mfgCode = MakeNullable(VendorId::TestVendor1),
.namespaceID = kNamespaceID1,
.tag = kTag1,
.label = MakeOptional(MakeNullable(CharSpan::fromCharString(kLabel1))),
};
tag = model.GetNextSemanticTag(kMockEndpoint1, existTag);
ASSERT_TRUE(tag.has_value());

tag = it->Next();
ASSERT_TRUE(tag.has_value()); // NOLINT(bugprone-unchecked-optional-access)
EXPECT_TRUE(tag->mfgCode.IsNull()); // NOLINT(bugprone-unchecked-optional-access)
EXPECT_EQ(tag->namespaceID, kNamespaceID2); // NOLINT(bugprone-unchecked-optional-access)
EXPECT_EQ(tag->tag, kTag2); // NOLINT(bugprone-unchecked-optional-access)
ASSERT_TRUE(tag->label.HasValue() && (!tag->label.Value().IsNull())); // NOLINT(bugprone-unchecked-optional-access)
EXPECT_TRUE(
tag->label.Value().Value().data_equal(CharSpan::fromCharString(kLabel2))); // NOLINT(bugprone-unchecked-optional-access)

// invalid query fails
existTag.tag = kTag2;
tag = model.GetNextSemanticTag(kMockEndpoint1, existTag);
ASSERT_FALSE(tag.has_value());
tag = it->Next();
ASSERT_TRUE(tag.has_value()); // NOLINT(bugprone-unchecked-optional-access)
EXPECT_EQ(tag->mfgCode, MakeNullable(VendorId::TestVendor3)); // NOLINT(bugprone-unchecked-optional-access)
EXPECT_EQ(tag->namespaceID, kNamespaceID3); // NOLINT(bugprone-unchecked-optional-access)
EXPECT_EQ(tag->tag, kTag3); // NOLINT(bugprone-unchecked-optional-access)
EXPECT_FALSE(tag->label.HasValue()); // NOLINT(bugprone-unchecked-optional-access)

EXPECT_FALSE(it->Next().has_value());

// empty endpoint works
tag = model.GetFirstSemanticTag(kMockEndpoint2);
ASSERT_FALSE(tag.has_value());
it = model.GetSemanticTags(kMockEndpoint2);
ASSERT_TRUE(it.get() != nullptr);
EXPECT_FALSE(it->Next().has_value());
}

0 comments on commit 0d0f93c

Please sign in to comment.