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

Look for more flash space savings in cluster-objects.cpp #29561

Merged
merged 7 commits into from
Oct 5, 2023
38 changes: 17 additions & 21 deletions src/app/zap-templates/partials/cluster-objects-struct.zapt
Original file line number Diff line number Diff line change
Expand Up @@ -113,32 +113,28 @@ CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const
{{/if}}

CHIP_ERROR DecodableType::Decode(TLV::TLVReader &reader) {
CHIP_ERROR err = CHIP_NO_ERROR;
TLV::TLVType outer;
VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE);
err = reader.EnterContainer(outer);
ReturnErrorOnFailure(err);
while ((err = reader.Next()) == CHIP_NO_ERROR) {
if (!TLV::IsContextTag(reader.GetTag()))
detail::StructDecodeIterator __iterator(reader);
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
while (true) {
detail::StructDecodeIterator::EntryElement __element = __iterator.Next();
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
if (std::holds_alternative<CHIP_ERROR>(__element)) {
return std::get<CHIP_ERROR>(__element);
}

CHIP_ERROR err = CHIP_NO_ERROR;
[[maybe_unused]] const uint8_t __context_tag = std::get<uint8_t>(__element);
andy31415 marked this conversation as resolved.
Show resolved Hide resolved

{{#zcl_struct_items}}
if (__context_tag == to_underlying(Fields::k{{asUpperCamelCase label}}))
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
{
continue;
err = DataModel::Decode(reader, {{asLowerCamelCase label}});
}
switch (TLV::TagNumFromTag(reader.GetTag()))
else
{{/zcl_struct_items}}
{
{{#zcl_struct_items}}
case to_underlying(Fields::k{{asUpperCamelCase label}}):
ReturnErrorOnFailure(DataModel::Decode(reader, {{asLowerCamelCase label}}));
break;
{{/zcl_struct_items}}
default:
break;
}
}

VerifyOrReturnError(err == CHIP_END_OF_TLV, err);
ReturnErrorOnFailure(reader.ExitContainer(outer));

return CHIP_NO_ERROR;
ReturnErrorOnFailure(err);
}
}

} // namespace {{asUpperCamelCase name}}
Expand Down
132 changes: 69 additions & 63 deletions src/app/zap-templates/templates/app/cluster-objects-src.zapt
Original file line number Diff line number Diff line change
@@ -1,46 +1,54 @@
{{> header}}

#include <app-common/zap-generated/cluster-objects.h>
#include <variant>

namespace chip {
namespace app {
namespace Clusters {

namespace detail {

CHIP_ERROR FlightCheckDecodeAndEnterStruct(TLV::TLVReader & reader, TLV::TLVType & outer)
{
TLV::TLVReader temp_reader;
class StructDecodeIterator {
public:
// may return a context tag, a CHIP_ERROR (end iteration)
using EntryElement = std::variant<uint8_t, CHIP_ERROR>;

StructDecodeIterator(TLV::TLVReader &reader) : mReader(reader){}

// Iterate through structure elements. Returns one of:
// - uint8_t CONTEXT TAG (keep iterating)
// - CHIP_ERROR (including CHIP_NO_ERROR) which should be a final
// return value (stop iterating)
EntryElement Next() {
if (!mEntered) {
VerifyOrReturnError(TLV::kTLVType_Structure == mReader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE);
ReturnErrorOnFailure(mReader.EnterContainer(mOuter));
mEntered = true;
}

CHIP_ERROR err;
while ((err = mReader.Next()) == CHIP_NO_ERROR) {
const TLV::Tag tag = mReader.GetTag();
if (!TLV::IsContextTag(tag)) {
continue;
}

// Make a copy of the struct reader to do pre-checks.
temp_reader.Init(reader);
// we know context tags are 8-bit
return static_cast<uint8_t>(TLV::TagNumFromTag(tag));
}

// Ensure we have a single struct and that it's properly bounded.
CHIP_ERROR err = CHIP_NO_ERROR;
VerifyOrReturnError(TLV::kTLVType_Structure == temp_reader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE);
ReturnErrorOnFailure(temp_reader.EnterContainer(outer));
while ((err = temp_reader.Next()) == CHIP_NO_ERROR)
{
if (!TLV::IsContextTag(temp_reader.GetTag()))
{
continue;
}
// went through the entire structure, expect a END_OF_TLV
// this can NOT be CHIP_NO_ERROR
VerifyOrReturnError(err == CHIP_ERROR_END_OF_TLV, err);
return mReader.ExitContainer(mOuter);
}
VerifyOrReturnError(err == CHIP_END_OF_TLV, err);
ReturnErrorOnFailure(temp_reader.ExitContainer(outer));

// Guaranteed to work due to prior checks.
VerifyOrDie(reader.EnterContainer(outer) == CHIP_NO_ERROR);
return CHIP_NO_ERROR;
}

void ExitStructAfterDecode(TLV::TLVReader & reader, TLV::TLVType & outer)
{
// Ensure we exit the container. Will be OK since FlightCheckDecodeAndEnterStruct will have
// already been called, and generated code properly iterates over entire container.
VerifyOrDie(reader.Next() == CHIP_END_OF_TLV);
VerifyOrDie(reader.ExitContainer(outer) == CHIP_NO_ERROR);
}
private:
bool mEntered = false;
TLV::TLVType mOuter;
TLV::TLVReader &mReader;
};

// Structs shared across multiple clusters.
namespace Structs {
Expand Down Expand Up @@ -80,29 +88,28 @@ CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const{
}

CHIP_ERROR DecodableType::Decode(TLV::TLVReader &reader) {
TLV::TLVType outer;
ReturnErrorOnFailure(chip::app::Clusters::detail::FlightCheckDecodeAndEnterStruct(reader, outer));
detail::StructDecodeIterator __iterator(reader);
while (true) {
detail::StructDecodeIterator::EntryElement __element = __iterator.Next();
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
if (std::holds_alternative<CHIP_ERROR>(__element)) {
return std::get<CHIP_ERROR>(__element);
}

CHIP_ERROR err = CHIP_NO_ERROR;
[[maybe_unused]] const uint8_t __context_tag = std::get<uint8_t>(__element);

CHIP_ERROR err = CHIP_NO_ERROR;
while ((err = reader.Next()) == CHIP_NO_ERROR) {
if (!TLV::IsContextTag(reader.GetTag()))
{{#zcl_command_arguments}}
if (__context_tag == to_underlying(Fields::k{{asUpperCamelCase label}}))
{
continue;
err = DataModel::Decode(reader, {{asLowerCamelCase label}});
}
switch (TLV::TagNumFromTag(reader.GetTag()))
else
{{/zcl_command_arguments}}
{
{{#zcl_command_arguments}}
case to_underlying(Fields::k{{asUpperCamelCase label}}):
ReturnErrorOnFailure(DataModel::Decode(reader, {{asLowerCamelCase label}}));
break;
{{/zcl_command_arguments}}
default:
break;
}
}

chip::app::Clusters::detail::ExitStructAfterDecode(reader, outer);
return CHIP_NO_ERROR;
ReturnErrorOnFailure(err);
}
}
} // namespace {{asUpperCamelCase name}}.
{{/zcl_commands}}
Expand Down Expand Up @@ -143,29 +150,28 @@ CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const{
}

CHIP_ERROR DecodableType::Decode(TLV::TLVReader &reader) {
TLV::TLVType outer;
ReturnErrorOnFailure(chip::app::Clusters::detail::FlightCheckDecodeAndEnterStruct(reader, outer));
detail::StructDecodeIterator __iterator(reader);
while (true) {
detail::StructDecodeIterator::EntryElement __element = __iterator.Next();
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
if (std::holds_alternative<CHIP_ERROR>(__element)) {
return std::get<CHIP_ERROR>(__element);
}

CHIP_ERROR err = CHIP_NO_ERROR;
[[maybe_unused]] const uint8_t __context_tag = std::get<uint8_t>(__element);
andy31415 marked this conversation as resolved.
Show resolved Hide resolved

CHIP_ERROR err = CHIP_NO_ERROR;
while ((err = reader.Next()) == CHIP_NO_ERROR) {
if (!TLV::IsContextTag(reader.GetTag()))
{{#zcl_event_fields}}
if (__context_tag == to_underlying(Fields::k{{asUpperCamelCase name}}))
{
continue;
err = DataModel::Decode(reader, {{asLowerCamelCase name}});
}
switch (TLV::TagNumFromTag(reader.GetTag()))
else
{{/zcl_event_fields}}
{
{{#zcl_event_fields}}
case to_underlying(Fields::k{{asUpperCamelCase name}}):
ReturnErrorOnFailure(DataModel::Decode(reader, {{asLowerCamelCase name}}));
break;
{{/zcl_event_fields}}
default:
break;
}
}

chip::app::Clusters::detail::ExitStructAfterDecode(reader, outer);
return CHIP_NO_ERROR;
ReturnErrorOnFailure(err);
}
}
} // namespace {{asUpperCamelCase name}}.
{{/zcl_events}}
Expand Down
Loading