diff --git a/src/app/ClusterStateCache.cpp b/src/app/ClusterStateCache.cpp index 7a6eed3de8576c..e3dd3dd8d84ca4 100644 --- a/src/app/ClusterStateCache.cpp +++ b/src/app/ClusterStateCache.cpp @@ -27,14 +27,14 @@ namespace app { namespace { // Determine how much space a StatusIB takes up on the wire. -size_t SizeOfStatusIB(const StatusIB & aStatus) +uint32_t SizeOfStatusIB(const StatusIB & aStatus) { // 1 byte: anonymous tag control byte for struct. // 1 byte: control byte for uint8 value. // 1 byte: context-specific tag for uint8 value. // 1 byte: the uint8 value. // 1 byte: end of container. - size_t size = 5; + uint32_t size = 5; if (aStatus.mClusterStatus.HasValue()) { @@ -49,7 +49,8 @@ size_t SizeOfStatusIB(const StatusIB & aStatus) } // anonymous namespace -CHIP_ERROR ClusterStateCache::GetElementTLVSize(TLV::TLVReader * apData, size_t & aSize) +template +CHIP_ERROR ClusterStateCacheT::GetElementTLVSize(TLV::TLVReader * apData, uint32_t & aSize) { Platform::ScopedMemoryBufferWithSize backingBuffer; TLV::TLVReader reader; @@ -64,8 +65,9 @@ CHIP_ERROR ClusterStateCache::GetElementTLVSize(TLV::TLVReader * apData, size_t return CHIP_NO_ERROR; } -CHIP_ERROR ClusterStateCache::UpdateCache(const ConcreteDataAttributePath & aPath, TLV::TLVReader * apData, - const StatusIB & aStatus) +template +CHIP_ERROR ClusterStateCacheT::UpdateCache(const ConcreteDataAttributePath & aPath, TLV::TLVReader * apData, + const StatusIB & aStatus) { AttributeState state; bool endpointIsNew = false; @@ -82,24 +84,32 @@ CHIP_ERROR ClusterStateCache::UpdateCache(const ConcreteDataAttributePath & aPat if (apData) { - size_t elementSize = 0; + uint32_t elementSize = 0; ReturnErrorOnFailure(GetElementTLVSize(apData, elementSize)); - if (mCacheData) + if constexpr (CanEnableDataCaching) { - Platform::ScopedMemoryBufferWithSize backingBuffer; - backingBuffer.Calloc(elementSize); - VerifyOrReturnError(backingBuffer.Get() != nullptr, CHIP_ERROR_NO_MEMORY); - TLV::ScopedBufferTLVWriter writer(std::move(backingBuffer), elementSize); - ReturnErrorOnFailure(writer.CopyElement(TLV::AnonymousTag(), *apData)); - ReturnErrorOnFailure(writer.Finalize(backingBuffer)); - - state.Set(std::move(backingBuffer)); + if (mCacheData) + { + Platform::ScopedMemoryBufferWithSize backingBuffer; + backingBuffer.Calloc(elementSize); + VerifyOrReturnError(backingBuffer.Get() != nullptr, CHIP_ERROR_NO_MEMORY); + TLV::ScopedBufferTLVWriter writer(std::move(backingBuffer), elementSize); + ReturnErrorOnFailure(writer.CopyElement(TLV::AnonymousTag(), *apData)); + ReturnErrorOnFailure(writer.Finalize(backingBuffer)); + + state.template Set(std::move(backingBuffer)); + } + else + { + state.template Set(elementSize); + } } else { - state.Set(elementSize); + state = elementSize; } + // // Clear out the committed data version and only set it again once we have received all data for this cluster. // Otherwise, we may have incomplete data that looks like it's complete since it has a valid data version. @@ -132,13 +142,20 @@ CHIP_ERROR ClusterStateCache::UpdateCache(const ConcreteDataAttributePath & aPat } else { - if (mCacheData) + if constexpr (CanEnableDataCaching) { - state.Set(aStatus); + if (mCacheData) + { + state.template Set(aStatus); + } + else + { + state.template Set(SizeOfStatusIB(aStatus)); + } } else { - state.Set(SizeOfStatusIB(aStatus)); + state = SizeOfStatusIB(aStatus); } } @@ -161,7 +178,9 @@ CHIP_ERROR ClusterStateCache::UpdateCache(const ConcreteDataAttributePath & aPat return CHIP_NO_ERROR; } -CHIP_ERROR ClusterStateCache::UpdateEventCache(const EventHeader & aEventHeader, TLV::TLVReader * apData, const StatusIB * apStatus) +template +CHIP_ERROR ClusterStateCacheT::UpdateEventCache(const EventHeader & aEventHeader, TLV::TLVReader * apData, + const StatusIB * apStatus) { if (apData) { @@ -208,7 +227,8 @@ CHIP_ERROR ClusterStateCache::UpdateEventCache(const EventHeader & aEventHeader, return CHIP_NO_ERROR; } -void ClusterStateCache::OnReportBegin() +template +void ClusterStateCacheT::OnReportBegin() { mLastReportDataPath = ConcreteClusterPath(kInvalidEndpointId, kInvalidClusterId); mChangedAttributeSet.clear(); @@ -216,7 +236,8 @@ void ClusterStateCache::OnReportBegin() mCallback.OnReportBegin(); } -void ClusterStateCache::CommitPendingDataVersion() +template +void ClusterStateCacheT::CommitPendingDataVersion() { if (!mLastReportDataPath.IsValidConcreteClusterPath()) { @@ -231,7 +252,8 @@ void ClusterStateCache::CommitPendingDataVersion() } } -void ClusterStateCache::OnReportEnd() +template +void ClusterStateCacheT::OnReportEnd() { CommitPendingDataVersion(); mLastReportDataPath = ConcreteClusterPath(kInvalidEndpointId, kInvalidClusterId); @@ -260,26 +282,35 @@ void ClusterStateCache::OnReportEnd() mCallback.OnReportEnd(); } -CHIP_ERROR ClusterStateCache::Get(const ConcreteAttributePath & path, TLV::TLVReader & reader) const +template <> +CHIP_ERROR ClusterStateCacheT::Get(const ConcreteAttributePath & path, TLV::TLVReader & reader) const { CHIP_ERROR err; auto attributeState = GetAttributeState(path.mEndpointId, path.mClusterId, path.mAttributeId, err); ReturnErrorOnFailure(err); - if (attributeState->Is()) + + if (attributeState->template Is()) { return CHIP_ERROR_IM_STATUS_CODE_RECEIVED; } - if (!attributeState->Is()) + if (!attributeState->template Is()) { return CHIP_ERROR_KEY_NOT_FOUND; } - reader.Init(attributeState->Get().Get(), attributeState->Get().AllocatedSize()); + reader.Init(attributeState->template Get().Get(), attributeState->template Get().AllocatedSize()); return reader.Next(); } -CHIP_ERROR ClusterStateCache::Get(EventNumber eventNumber, TLV::TLVReader & reader) const +template <> +CHIP_ERROR ClusterStateCacheT::Get(const ConcreteAttributePath & path, TLV::TLVReader & reader) const +{ + return CHIP_ERROR_KEY_NOT_FOUND; +} + +template +CHIP_ERROR ClusterStateCacheT::Get(EventNumber eventNumber, TLV::TLVReader & reader) const { CHIP_ERROR err; @@ -295,7 +326,9 @@ CHIP_ERROR ClusterStateCache::Get(EventNumber eventNumber, TLV::TLVReader & read return CHIP_NO_ERROR; } -const ClusterStateCache::EndpointState * ClusterStateCache::GetEndpointState(EndpointId endpointId, CHIP_ERROR & err) const +template +const typename ClusterStateCacheT::EndpointState * +ClusterStateCacheT::GetEndpointState(EndpointId endpointId, CHIP_ERROR & err) const { auto endpointIter = mCache.find(endpointId); if (endpointIter == mCache.end()) @@ -308,8 +341,9 @@ const ClusterStateCache::EndpointState * ClusterStateCache::GetEndpointState(End return &endpointIter->second; } -const ClusterStateCache::ClusterState * ClusterStateCache::GetClusterState(EndpointId endpointId, ClusterId clusterId, - CHIP_ERROR & err) const +template +const typename ClusterStateCacheT::ClusterState * +ClusterStateCacheT::GetClusterState(EndpointId endpointId, ClusterId clusterId, CHIP_ERROR & err) const { auto endpointState = GetEndpointState(endpointId, err); if (err != CHIP_NO_ERROR) @@ -328,8 +362,10 @@ const ClusterStateCache::ClusterState * ClusterStateCache::GetClusterState(Endpo return &clusterState->second; } -const ClusterStateCache::AttributeState * ClusterStateCache::GetAttributeState(EndpointId endpointId, ClusterId clusterId, - AttributeId attributeId, CHIP_ERROR & err) const +template +const typename ClusterStateCacheT::AttributeState * +ClusterStateCacheT::GetAttributeState(EndpointId endpointId, ClusterId clusterId, AttributeId attributeId, + CHIP_ERROR & err) const { auto clusterState = GetClusterState(endpointId, clusterId, err); if (err != CHIP_NO_ERROR) @@ -348,7 +384,9 @@ const ClusterStateCache::AttributeState * ClusterStateCache::GetAttributeState(E return &attributeState->second; } -const ClusterStateCache::EventData * ClusterStateCache::GetEventData(EventNumber eventNumber, CHIP_ERROR & err) const +template +const typename ClusterStateCacheT::EventData * +ClusterStateCacheT::GetEventData(EventNumber eventNumber, CHIP_ERROR & err) const { EventData compareKey; @@ -364,7 +402,9 @@ const ClusterStateCache::EventData * ClusterStateCache::GetEventData(EventNumber return &(*eventData); } -void ClusterStateCache::OnAttributeData(const ConcreteDataAttributePath & aPath, TLV::TLVReader * apData, const StatusIB & aStatus) +template +void ClusterStateCacheT::OnAttributeData(const ConcreteDataAttributePath & aPath, TLV::TLVReader * apData, + const StatusIB & aStatus) { // // Since the cache itself is a ReadClient::Callback, it may be incorrectly passed in directly when registering with the @@ -394,7 +434,9 @@ void ClusterStateCache::OnAttributeData(const ConcreteDataAttributePath & aPath, mCallback.OnAttributeData(aPath, apData ? &dataSnapshot : nullptr, aStatus); } -CHIP_ERROR ClusterStateCache::GetVersion(const ConcreteClusterPath & aPath, Optional & aVersion) const +template +CHIP_ERROR ClusterStateCacheT::GetVersion(const ConcreteClusterPath & aPath, + Optional & aVersion) const { VerifyOrReturnError(aPath.IsValidConcreteClusterPath(), CHIP_ERROR_INVALID_ARGUMENT); CHIP_ERROR err; @@ -404,7 +446,9 @@ CHIP_ERROR ClusterStateCache::GetVersion(const ConcreteClusterPath & aPath, Opti return CHIP_NO_ERROR; } -void ClusterStateCache::OnEventData(const EventHeader & aEventHeader, TLV::TLVReader * apData, const StatusIB * apStatus) +template +void ClusterStateCacheT::OnEventData(const EventHeader & aEventHeader, TLV::TLVReader * apData, + const StatusIB * apStatus) { VerifyOrDie(apData != nullptr || apStatus != nullptr); @@ -418,23 +462,31 @@ void ClusterStateCache::OnEventData(const EventHeader & aEventHeader, TLV::TLVRe mCallback.OnEventData(aEventHeader, apData ? &dataSnapshot : nullptr, apStatus); } -CHIP_ERROR ClusterStateCache::GetStatus(const ConcreteAttributePath & path, StatusIB & status) const +template <> +CHIP_ERROR ClusterStateCacheT::GetStatus(const ConcreteAttributePath & path, StatusIB & status) const { CHIP_ERROR err; auto attributeState = GetAttributeState(path.mEndpointId, path.mClusterId, path.mAttributeId, err); ReturnErrorOnFailure(err); - if (!attributeState->Is()) + if (!attributeState->template Is()) { return CHIP_ERROR_INVALID_ARGUMENT; } - status = attributeState->Get(); + status = attributeState->template Get(); return CHIP_NO_ERROR; } -CHIP_ERROR ClusterStateCache::GetStatus(const ConcreteEventPath & path, StatusIB & status) const +template <> +CHIP_ERROR ClusterStateCacheT::GetStatus(const ConcreteAttributePath & path, StatusIB & status) const +{ + return CHIP_ERROR_INVALID_ARGUMENT; +} + +template +CHIP_ERROR ClusterStateCacheT::GetStatus(const ConcreteEventPath & path, StatusIB & status) const { auto statusIter = mEventStatusCache.find(path); if (statusIter == mEventStatusCache.end()) @@ -446,7 +498,8 @@ CHIP_ERROR ClusterStateCache::GetStatus(const ConcreteEventPath & path, StatusIB return CHIP_NO_ERROR; } -void ClusterStateCache::GetSortedFilters(std::vector> & aVector) const +template +void ClusterStateCacheT::GetSortedFilters(std::vector> & aVector) const { for (auto const & endpointIter : mCache) { @@ -463,26 +516,33 @@ void ClusterStateCache::GetSortedFilters(std::vector()) - { - clusterSize += SizeOfStatusIB(attributeIter.second.Get()); - } - else if (attributeIter.second.Is()) + if constexpr (CanEnableDataCaching) { - clusterSize += attributeIter.second.Get(); + if (attributeIter.second.template Is()) + { + clusterSize += SizeOfStatusIB(attributeIter.second.template Get()); + } + else if (attributeIter.second.template Is()) + { + clusterSize += attributeIter.second.template Get(); + } + else + { + VerifyOrDie(attributeIter.second.template Is()); + TLV::TLVReader bufReader; + bufReader.Init(attributeIter.second.template Get().Get(), + attributeIter.second.template Get().AllocatedSize()); + ReturnOnFailure(bufReader.Next()); + // Skip to the end of the element. + ReturnOnFailure(bufReader.Skip()); + + // Compute the amount of value data + clusterSize += bufReader.GetLengthRead(); + } } else { - VerifyOrDie(attributeIter.second.Is()); - TLV::TLVReader bufReader; - bufReader.Init(attributeIter.second.Get().Get(), - attributeIter.second.Get().AllocatedSize()); - ReturnOnFailure(bufReader.Next()); - // Skip to the end of the element. - ReturnOnFailure(bufReader.Skip()); - - // Compute the amount of value data - clusterSize += bufReader.GetLengthRead(); + clusterSize += attributeIter.second; } } @@ -505,9 +565,10 @@ void ClusterStateCache::GetSortedFilters(std::vector & aAttributePaths, - bool & aEncodedDataVersionList) +template +CHIP_ERROR ClusterStateCacheT::OnUpdateDataVersionFilterList( + DataVersionFilterIBs::Builder & aDataVersionFilterIBsBuilder, const Span & aAttributePaths, + bool & aEncodedDataVersionList) { CHIP_ERROR err = CHIP_NO_ERROR; TLV::TLVWriter backup; @@ -587,7 +648,8 @@ CHIP_ERROR ClusterStateCache::OnUpdateDataVersionFilterList(DataVersionFilterIBs return err; } -CHIP_ERROR ClusterStateCache::GetLastReportDataPath(ConcreteClusterPath & aPath) +template +CHIP_ERROR ClusterStateCacheT::GetLastReportDataPath(ConcreteClusterPath & aPath) { if (mLastReportDataPath.IsValidConcreteClusterPath()) { @@ -596,5 +658,10 @@ CHIP_ERROR ClusterStateCache::GetLastReportDataPath(ConcreteClusterPath & aPath) } return CHIP_ERROR_INCORRECT_STATE; } + +// Ensure that our out-of-line template methods actually get compiled. +template class ClusterStateCacheT; +template class ClusterStateCacheT; + } // namespace app } // namespace chip diff --git a/src/app/ClusterStateCache.h b/src/app/ClusterStateCache.h index 4c663a2a5fc2f9..7f7e9e96e855a9 100644 --- a/src/app/ClusterStateCache.h +++ b/src/app/ClusterStateCache.h @@ -66,7 +66,8 @@ namespace app { * 2. The same cache cannot be used by multiple subscribe/read interactions at the same time. * */ -class ClusterStateCache : protected ReadClient::Callback +template +class ClusterStateCacheT : protected ReadClient::Callback { public: class Callback : public ReadClient::Callback @@ -83,17 +84,17 @@ class ClusterStateCache : protected ReadClient::Callback /* * Called anytime an attribute value has changed in the cache */ - virtual void OnAttributeChanged(ClusterStateCache * cache, const ConcreteAttributePath & path){}; + virtual void OnAttributeChanged(ClusterStateCacheT * cache, const ConcreteAttributePath & path){}; /* * Called anytime any attribute in a cluster has changed in the cache */ - virtual void OnClusterChanged(ClusterStateCache * cache, EndpointId endpointId, ClusterId clusterId){}; + virtual void OnClusterChanged(ClusterStateCacheT * cache, EndpointId endpointId, ClusterId clusterId){}; /* * Called anytime an endpoint was added to the cache */ - virtual void OnEndpointAdded(ClusterStateCache * cache, EndpointId endpointId){}; + virtual void OnEndpointAdded(ClusterStateCacheT * cache, EndpointId endpointId){}; }; /** @@ -104,18 +105,25 @@ class ClusterStateCache : protected ReadClient::Callback * @param [in] cacheData boolean to decide whether this cache would store attribute/event data/status, * the default is true. */ - ClusterStateCache(Callback & callback, Optional highestReceivedEventNumber = Optional::Missing(), - bool cacheData = true) : + ClusterStateCacheT(Callback & callback, Optional highestReceivedEventNumber = Optional::Missing()) : + mCallback(callback), mBufferedReader(*this) + { + mHighestReceivedEventNumber = highestReceivedEventNumber; + } + + template = true> + ClusterStateCacheT(Callback & callback, Optional highestReceivedEventNumber = Optional::Missing(), + bool cacheData = true) : mCallback(callback), mBufferedReader(*this), mCacheData(cacheData) { mHighestReceivedEventNumber = highestReceivedEventNumber; } - ClusterStateCache(const ClusterStateCache &) = delete; - ClusterStateCache(ClusterStateCache &&) = delete; - ClusterStateCache & operator=(const ClusterStateCache &) = delete; - ClusterStateCache & operator=(ClusterStateCache &&) = delete; + ClusterStateCacheT(const ClusterStateCacheT &) = delete; + ClusterStateCacheT(ClusterStateCacheT &&) = delete; + ClusterStateCacheT & operator=(const ClusterStateCacheT &) = delete; + ClusterStateCacheT & operator=(ClusterStateCacheT &&) = delete; void SetHighestReceivedEventNumber(EventNumber highestReceivedEventNumber) { @@ -534,8 +542,12 @@ class ClusterStateCache : protected ReadClient::Callback // * If we got data for the attribute and we are not storing data // oureselves, the size of the data, so we can still prioritize sending // DataVersions correctly. + // + // The data for a single attribute is not going to be gigabytes in size, so + // using uint32_t for the size is fine; on 64-bit systems this can save + // quite a bit of space. using AttributeData = Platform::ScopedMemoryBufferWithSize; - using AttributeState = Variant; + using AttributeState = std::conditional_t, uint32_t>; // mPendingDataVersion represents a tentative data version for a cluster that we have gotten some reports for. // // mCurrentDataVersion represents a known data version for a cluster. In order for this to have a @@ -659,7 +671,7 @@ class ClusterStateCache : protected ReadClient::Callback // on the wire if not all filters can be applied. void GetSortedFilters(std::vector> & aVector) const; - CHIP_ERROR GetElementTLVSize(TLV::TLVReader * apData, size_t & aSize); + CHIP_ERROR GetElementTLVSize(TLV::TLVReader * apData, uint32_t & aSize); Callback & mCallback; NodeState mCache; @@ -672,9 +684,12 @@ class ClusterStateCache : protected ReadClient::Callback std::map mEventStatusCache; BufferedReadCallback mBufferedReader; ConcreteClusterPath mLastReportDataPath = ConcreteClusterPath(kInvalidEndpointId, kInvalidClusterId); - const bool mCacheData = true; + const bool mCacheData = CanEnableDataCaching; }; +using ClusterStateCache = ClusterStateCacheT; +using ClusterStateCacheNoData = ClusterStateCacheT; + }; // namespace app }; // namespace chip #endif // CHIP_CONFIG_ENABLE_READ_CLIENT