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

Improve DecodableList when not in list #13607

Merged
merged 2 commits into from
Jan 17, 2022
Merged
Changes from all commits
Commits
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
52 changes: 34 additions & 18 deletions src/app/data-model/DecodableList.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,36 +32,40 @@ namespace DataModel {
* This class provides an iteratable decoder of list items within TLV payloads
* such that no memory has to be provided ahead of time to store the entirety of the decoded
* list contents.
*
*/
template <typename T>
class DecodableList
{
public:
DecodableList()
{
// Init to an empty list.
mReader.Init(nullptr, 0);
}
DecodableList() { ClearReader(); }

/*
* @brief
*
* This call stores a TLV reader positioned on the list this class is to manage.
*
* Specifically, the passed-in TLV reader should be pointing into the list just after
* Specifically, the passed-in reader should be pointing into the list just after
* having called `OpenContainer` on the list element.
*/
void SetReader(const TLV::TLVReader & reader) { mReader = reader; }

/*
* @brief
*
* This call clears the TLV reader managed by this class, so it can be reused.
*/
void ClearReader() { mReader.Init(nullptr, 0); }

class Iterator
{
public:
/*
* Initialize the iterator with a reference to a reader.
*
* This reader should be pointing into the list just after
* having called `OpenContainer` on the list element.
* having called `OpenContainer` on the list element, or should
* have a `kTLVType_NotSpecified` container type if there is
* no list.
*/
Iterator(const TLV::TLVReader & reader)
{
Expand All @@ -77,16 +81,20 @@ class DecodableList
* If an element does exist and was successfully decoded, this
* shall return true.
*
* Otherwise, if the end of list is reached, this call shall return
* false.
* Otherwise, if the end of list is reached, or there was no list,
* this call shall return false.
*
* If an error was encountered at any point during the iteration or decode,
* this shall return false as well. The caller is expected to invoke GetStatus()
* to retrieve the status of the operation.
*
*/
bool Next()
{
if (mReader.GetContainerType() == TLV::kTLVType_NotSpecified)
{
return false;
}

if (mStatus == CHIP_NO_ERROR)
{
mStatus = mReader.Next();
Expand All @@ -111,7 +119,6 @@ class DecodableList
*
* Notably, if the end-of-list was encountered in a previous call to Next,
* the status returned shall be CHIP_NO_ERROR.
*
*/
CHIP_ERROR GetStatus() const
{
Expand All @@ -134,12 +141,24 @@ class DecodableList
Iterator begin() const { return Iterator(mReader); }

/*
* Compute the size of the list. This can fail if the TLV is malformed. If
* Compute the size of the list. This can fail if the TLV is malformed. If
* this succeeds, that does not guarantee that the individual items can be
* successfully decoded; consumers should check Iterator::GetStatus() when
* actually decoding them.
* actually decoding them. If there is no list then the size is considered
* to be zero.
*/
CHIP_ERROR ComputeSize(size_t * size) const { return mReader.CountRemainingInContainer(size); }
CHIP_ERROR ComputeSize(size_t * size) const
{
if (mReader.GetContainerType() == TLV::kTLVType_NotSpecified)
{
*size = 0;
return CHIP_NO_ERROR;
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
}
else
{
return mReader.CountRemainingInContainer(size);
}
}

private:
TLV::TLVReader mReader;
Expand All @@ -149,13 +168,10 @@ template <typename X>
CHIP_ERROR Decode(TLV::TLVReader & reader, DecodableList<X> & x)
{
VerifyOrReturnError(reader.GetType() == TLV::kTLVType_Array, CHIP_ERROR_SCHEMA_MISMATCH);
andy31415 marked this conversation as resolved.
Show resolved Hide resolved

TLV::TLVType type;

ReturnErrorOnFailure(reader.EnterContainer(type));
x.SetReader(reader);
ReturnErrorOnFailure(reader.ExitContainer(type));

return CHIP_NO_ERROR;
}

Expand Down