Matter SDK Coverage Report
Current view: top level - app - AttributePathExpandIterator.h (source / functions) Coverage Total Hit
Test: SHA:0a260ffe149e0486eee9e451428453f0b12a3d3c Lines: 100.0 % 14 14
Test Date: 2025-06-06 07:10:05 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/MetadataTypes.h>
      23              : #include <app/data-model-provider/Provider.h>
      24              : #include <lib/core/DataModelTypes.h>
      25              : #include <lib/support/LinkedList.h>
      26              : #include <lib/support/ReadOnlyBuffer.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         2146 :         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         1132 :         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         2146 :         Position(SingleLinkedListNode<AttributePathParams> * path) :
      97         2146 :             mAttributePath(path), mOutputPath(kInvalidEndpointId, kInvalidClusterId, kInvalidAttributeId)
      98         2146 :         {}
      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              :     /// Can also optionally ask for the corresponding AttributeEntry (e.g. to validate
     114              :     /// read/write options).
     115              :     ///
     116              :     /// @param entry - an optional out argument for the corresponding attribute entry metadata
     117              :     ///                for the given path. Since the expand iterator looks over cluster metadata
     118              :     ///                to generate valid paths, the metadata information is `free` to receive
     119              :     ///                by the caller.
     120              :     ///
     121              :     /// NOTES:
     122              :     ///   - returning the `entry` information is done here as a convenience/optimization
     123              :     ///     to avoid extra lookups for metadata. Callers are free to use `expanded path` instead
     124              :     ///     and not ask for the entry data.
     125              :     ///   - `entry` may be `std::nullopt`: AttributePathExpandIterator will return non-wildcard
     126              :     ///     paths as-is and those may be invalid. If a path is not valid for the DataModel::Provider
     127              :     ///     then entry will be `std::nullopt`.
     128              :     ///
     129              :     /// On success, true is returned and `path` is filled with the next path in the
     130              :     /// expansion.
     131              :     /// On iteration completion, false is returned and the content of path IS NOT DEFINED.
     132              :     bool Next(ConcreteAttributePath & path, std::optional<DataModel::AttributeEntry> * entry = nullptr);
     133              : 
     134              : private:
     135              :     static constexpr size_t kInvalidIndex = std::numeric_limits<size_t>::max();
     136              : 
     137              :     DataModel::Provider * mDataModelProvider;
     138              :     Position & mPosition;
     139              : 
     140              :     ReadOnlyBuffer<DataModel::EndpointEntry> mEndpoints; // all endpoints
     141              :     size_t mEndpointIndex = kInvalidIndex;
     142              : 
     143              :     ReadOnlyBuffer<DataModel::ServerClusterEntry> mClusters; // all clusters ON THE CURRENT endpoint
     144              :     size_t mClusterIndex = kInvalidIndex;
     145              : 
     146              :     ReadOnlyBuffer<DataModel::AttributeEntry> mAttributes; // all attributes ON THE CURRENT cluster
     147              :     size_t mAttributeIndex = kInvalidIndex;
     148              : 
     149              :     /// Move to the next endpoint/cluster/attribute triplet that is valid given
     150              :     /// the current mOutputPath and mpAttributePath.
     151              :     ///
     152              :     /// returns true if such a next value was found.
     153              :     bool AdvanceOutputPath(std::optional<DataModel::AttributeEntry> * entry);
     154              : 
     155              :     /// Get the next attribute ID in mOutputPath(endpoint/cluster) if one is available.
     156              :     /// Will start from the beginning if current mOutputPath.mAttributeId is kInvalidAttributeId
     157              :     ///
     158              :     /// Respects path expansion/values in mpAttributePath
     159              :     std::optional<AttributeId> NextAttribute(std::optional<DataModel::AttributeEntry> * entry);
     160              : 
     161              :     /// Get the next cluster ID in mOutputPath(endpoint) if one is available.
     162              :     /// Will start from the beginning if current mOutputPath.mClusterId is kInvalidClusterId
     163              :     ///
     164              :     /// Respects path expansion/values in mpAttributePath
     165              :     std::optional<ClusterId> NextClusterId();
     166              : 
     167              :     /// Get the next endpoint ID in mOutputPath if one is available.
     168              :     /// Will start from the beginning if current mOutputPath.mEndpointId is kInvalidEndpointId
     169              :     ///
     170              :     /// Respects path expansion/values in mpAttributePath
     171              :     std::optional<EndpointId> NextEndpointId();
     172              : };
     173              : 
     174              : /// RollbackAttributePathExpandIterator is an AttributePathExpandIterator wrapper that rolls back the Next()
     175              : /// call whenever a new `MarkCompleted()` method is not called.
     176              : ///
     177              : /// Example use cases:
     178              : ///
     179              : /// - Iterate over all attributes and process one-by-one, however when the iteration fails, resume at
     180              : ///   the last failure point:
     181              : ///
     182              : ///      RollbackAttributePathExpandIterator iterator(....);
     183              : ///      ConcreteAttributePath path;
     184              : ///
     185              : ///      for ( ; iterator.Next(path); iterator.MarkCompleted()) {
     186              : ///         if (!CanProcess(path)) {
     187              : ///             // iterator state IS PRESERVED so that Next() will return the SAME path on the next call.
     188              : ///             return CHIP_ERROR_TRY_AGAIN_LATER;
     189              : ///         }
     190              : ///      }
     191              : ///
     192              : /// -  Grab what the next output path would be WITHOUT advancing a state;
     193              : ///
     194              : ///      {
     195              : ///        RollbackAttributePathExpandIterator iterator(...., state);
     196              : ///        if (iterator.Next(...)) { ... }
     197              : ///      }
     198              : ///      // state here is ROLLED BACK (i.e. initializing a new iterator with it will start at the same place as the previous
     199              : ///      iteration attempt).
     200              : ///
     201              : ///
     202              : class RollbackAttributePathExpandIterator
     203              : {
     204              : public:
     205         1980 :     RollbackAttributePathExpandIterator(DataModel::Provider * dataModel, AttributePathExpandIterator::Position & position) :
     206         1980 :         mAttributePathExpandIterator(dataModel, position), mPositionTarget(position), mCompletedPosition(position)
     207         1980 :     {}
     208         1980 :     ~RollbackAttributePathExpandIterator() { mPositionTarget = mCompletedPosition; }
     209              : 
     210         6463 :     bool Next(ConcreteAttributePath & path) { return mAttributePathExpandIterator.Next(path); }
     211              : 
     212              :     /// Marks the current iteration completed (so peek does not actually roll back)
     213         4483 :     void MarkCompleted() { mCompletedPosition = mPositionTarget; }
     214              : 
     215              : private:
     216              :     AttributePathExpandIterator mAttributePathExpandIterator;
     217              :     AttributePathExpandIterator::Position & mPositionTarget;
     218              :     AttributePathExpandIterator::Position mCompletedPosition;
     219              : };
     220              : 
     221              : } // namespace app
     222              : } // namespace chip
        

Generated by: LCOV version 2.0-1