Matter SDK Coverage Report
Current view: top level - app - AttributePathExpandIterator.h (source / functions) Coverage Total Hit
Test: SHA:f84fe08d06f240e801b5d923f8a938a9938ca110 Lines: 100.0 % 14 14
Test Date: 2025-02-22 08:08:07 Functions: 100.0 % 8 8

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2021 Project CHIP Authors
       4              :  *    All rights reserved.
       5              :  *
       6              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       7              :  *    you may not use this file except in compliance with the License.
       8              :  *    You may obtain a copy of the License at
       9              :  *
      10              :  *        http://www.apache.org/licenses/LICENSE-2.0
      11              :  *
      12              :  *    Unless required by applicable law or agreed to in writing, software
      13              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      14              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15              :  *    See the License for the specific language governing permissions and
      16              :  *    limitations under the License.
      17              :  */
      18              : #pragma once
      19              : 
      20              : #include <app/AttributePathParams.h>
      21              : #include <app/ConcreteAttributePath.h>
      22              : #include <app/data-model-provider/MetadataList.h>
      23              : #include <app/data-model-provider/MetadataTypes.h>
      24              : #include <app/data-model-provider/Provider.h>
      25              : #include <lib/core/DataModelTypes.h>
      26              : #include <lib/support/LinkedList.h>
      27              : #include <lib/support/Span.h>
      28              : 
      29              : #include <limits>
      30              : 
      31              : namespace chip {
      32              : namespace app {
      33              : 
      34              : /// Handles attribute path expansions
      35              : /// Usage:
      36              : ///
      37              : /// - Start iterating by creating an iteration state
      38              : ///
      39              : ///      AttributePathExpandIterator::Position position = AttributePathExpandIterator::Position::StartIterating(path);
      40              : ///
      41              : /// - Use the iteration state in a for loop:
      42              : ///
      43              : ///      ConcreteAttributePath path;
      44              : ///      for (AttributePathExpandIterator iterator(position); iterator->Next(path);) {
      45              : ///         // use `path` here`
      46              : ///      }
      47              : ///
      48              : ///   OR:
      49              : ///
      50              : ///      ConcreteAttributePath path;
      51              : ///      AttributePathExpandIterator iterator(position);
      52              : ///
      53              : ///      while (iterator.Next(path)) {
      54              : ///         // use `path` here`
      55              : ///      }
      56              : ///
      57              : /// Usage requirements and assumptions:
      58              : ///
      59              : ///    - An ` AttributePathExpandIterator::Position` can only be used by a single AttributePathExpandIterator at a time.
      60              : ///
      61              : ///    - `position` is automatically updated by the AttributePathExpandIterator, so
      62              : ///      calling `Next` on the iterator will update the position cursor variable.
      63              : ///
      64              : class AttributePathExpandIterator
      65              : {
      66              : public:
      67              :     class Position
      68              :     {
      69              :     public:
      70              :         // Position is treated as a direct member access by the AttributePathExpandIterator, however it is opaque (except copying)
      71              :         // for external code. We allow friendship here to not have specific get/set for methods (clearer interface and less
      72              :         // likelihood of extra code usage).
      73              :         friend class AttributePathExpandIterator;
      74              : 
      75              :         /// External callers can only ever start iterating on a new path from the beginning
      76         2132 :         static Position StartIterating(SingleLinkedListNode<AttributePathParams> * path) { return Position(path); }
      77              : 
      78              :         /// Copies are allowed
      79              :         Position(const Position &)             = default;
      80              :         Position & operator=(const Position &) = default;
      81              : 
      82         1125 :         Position() : mAttributePath(nullptr) {}
      83              : 
      84              :         /// Reset the iterator to the beginning of current cluster if we are in the middle of expanding a wildcard attribute id for
      85              :         /// some cluster.
      86              :         ///
      87              :         /// When attributes are changed in the middle of expanding a wildcard attribute, we need to reset the iterator, to provide
      88              :         /// the client with a consistent state of the cluster.
      89          264 :         void IterateFromTheStartOfTheCurrentClusterIfAttributeWildcard()
      90              :         {
      91          264 :             VerifyOrReturn(mAttributePath != nullptr && mAttributePath->mValue.HasWildcardAttributeId());
      92            4 :             mOutputPath.mAttributeId = kInvalidAttributeId;
      93              :         }
      94              : 
      95              :     protected:
      96         2132 :         Position(SingleLinkedListNode<AttributePathParams> * path) :
      97         2132 :             mAttributePath(path), mOutputPath(kInvalidEndpointId, kInvalidClusterId, kInvalidAttributeId)
      98         2132 :         {}
      99              : 
     100              :         SingleLinkedListNode<AttributePathParams> * mAttributePath;
     101              :         ConcreteAttributePath mOutputPath;
     102              :     };
     103              : 
     104              :     AttributePathExpandIterator(DataModel::Provider * dataModel, Position & position);
     105              : 
     106              :     // This class may not be copied. A new one should be created when needed and they
     107              :     // should not overlap.
     108              :     AttributePathExpandIterator(const AttributePathExpandIterator &)             = delete;
     109              :     AttributePathExpandIterator & operator=(const AttributePathExpandIterator &) = delete;
     110              : 
     111              :     /// Get the next path of the expansion (if one exists).
     112              :     ///
     113              :     /// On success, true is returned and `path` is filled with the next path in the
     114              :     /// expansion.
     115              :     /// On iteration completion, false is returned and the content of path IS NOT DEFINED.
     116              :     bool Next(ConcreteAttributePath & path);
     117              : 
     118              : private:
     119              :     static constexpr size_t kInvalidIndex = std::numeric_limits<size_t>::max();
     120              : 
     121              :     DataModel::Provider * mDataModelProvider;
     122              :     Position & mPosition;
     123              : 
     124              :     DataModel::ReadOnlyBuffer<DataModel::EndpointEntry> mEndpoints; // all endpoints
     125              :     size_t mEndpointIndex = kInvalidIndex;
     126              : 
     127              :     DataModel::ReadOnlyBuffer<DataModel::ServerClusterEntry> mClusters; // all clusters ON THE CURRENT endpoint
     128              :     size_t mClusterIndex = kInvalidIndex;
     129              : 
     130              :     DataModel::ReadOnlyBuffer<DataModel::AttributeEntry> mAttributes; // all attributes ON THE CURRENT cluster
     131              :     size_t mAttributeIndex = kInvalidIndex;
     132              : 
     133              :     /// Move to the next endpoint/cluster/attribute triplet that is valid given
     134              :     /// the current mOutputPath and mpAttributePath.
     135              :     ///
     136              :     /// returns true if such a next value was found.
     137              :     bool AdvanceOutputPath();
     138              : 
     139              :     /// Get the next attribute ID in mOutputPath(endpoint/cluster) if one is available.
     140              :     /// Will start from the beginning if current mOutputPath.mAttributeId is kInvalidAttributeId
     141              :     ///
     142              :     /// Respects path expansion/values in mpAttributePath
     143              :     ///
     144              :     /// Handles Global attributes (which are returned at the end)
     145              :     std::optional<AttributeId> NextAttributeId();
     146              : 
     147              :     /// Get the next cluster ID in mOutputPath(endpoint) if one is available.
     148              :     /// Will start from the beginning if current mOutputPath.mClusterId is kInvalidClusterId
     149              :     ///
     150              :     /// Respects path expansion/values in mpAttributePath
     151              :     std::optional<ClusterId> NextClusterId();
     152              : 
     153              :     /// Get the next endpoint ID in mOutputPath if one is available.
     154              :     /// Will start from the beginning if current mOutputPath.mEndpointId is kInvalidEndpointId
     155              :     ///
     156              :     /// Respects path expansion/values in mpAttributePath
     157              :     std::optional<EndpointId> NextEndpointId();
     158              : 
     159              :     /// Checks if the given attributeId is valid for the current mOutputPath(endpoint/cluster)
     160              :     ///
     161              :     /// Meaning that it is known to the data model OR it is a always-there global attribute.
     162              :     bool IsValidAttributeId(AttributeId attributeId);
     163              : };
     164              : 
     165              : /// RollbackAttributePathExpandIterator is an AttributePathExpandIterator wrapper that rolls back the Next()
     166              : /// call whenever a new `MarkCompleted()` method is not called.
     167              : ///
     168              : /// Example use cases:
     169              : ///
     170              : /// - Iterate over all attributes and process one-by-one, however when the iteration fails, resume at
     171              : ///   the last failure point:
     172              : ///
     173              : ///      RollbackAttributePathExpandIterator iterator(....);
     174              : ///      ConcreteAttributePath path;
     175              : ///
     176              : ///      for ( ; iterator.Next(path); iterator.MarkCompleted()) {
     177              : ///         if (!CanProcess(path)) {
     178              : ///             // iterator state IS PRESERVED so that Next() will return the SAME path on the next call.
     179              : ///             return CHIP_ERROR_TRY_AGAIN_LATER;
     180              : ///         }
     181              : ///      }
     182              : ///
     183              : /// -  Grab what the next output path would be WITHOUT advancing a state;
     184              : ///
     185              : ///      {
     186              : ///        RollbackAttributePathExpandIterator iterator(...., state);
     187              : ///        if (iterator.Next(...)) { ... }
     188              : ///      }
     189              : ///      // state here is ROLLED BACK (i.e. initializing a new iterator with it will start at the same place as the previous
     190              : ///      iteration attempt).
     191              : ///
     192              : ///
     193              : class RollbackAttributePathExpandIterator
     194              : {
     195              : public:
     196         1973 :     RollbackAttributePathExpandIterator(DataModel::Provider * dataModel, AttributePathExpandIterator::Position & position) :
     197         1973 :         mAttributePathExpandIterator(dataModel, position), mPositionTarget(position), mCompletedPosition(position)
     198         1973 :     {}
     199         1973 :     ~RollbackAttributePathExpandIterator() { mPositionTarget = mCompletedPosition; }
     200              : 
     201         6449 :     bool Next(ConcreteAttributePath & path) { return mAttributePathExpandIterator.Next(path); }
     202              : 
     203              :     /// Marks the current iteration completed (so peek does not actually roll back)
     204         4476 :     void MarkCompleted() { mCompletedPosition = mPositionTarget; }
     205              : 
     206              : private:
     207              :     AttributePathExpandIterator mAttributePathExpandIterator;
     208              :     AttributePathExpandIterator::Position & mPositionTarget;
     209              :     AttributePathExpandIterator::Position mCompletedPosition;
     210              : };
     211              : 
     212              : } // namespace app
     213              : } // namespace chip
        

Generated by: LCOV version 2.0-1