LCOV - code coverage report
Current view: top level - lib/format - FlatTreePosition.h (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 31 34 91.2 %
Date: 2024-02-15 08:20:41 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *    Copyright (c) 2023 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 <lib/format/FlatTree.h>
      21             : #include <lib/support/Span.h>
      22             : 
      23             : namespace chip {
      24             : namespace FlatTree {
      25             : 
      26             : /// Represents a position inside a given tree, allowing for descending
      27             : /// and ascending.
      28             : ///
      29             : /// A possition in the tree may be undefined if descending to a non-existing leaf,
      30             : /// however the position still allows moving back again.
      31             : ///
      32             : /// DESCEND_DEPTH is the maximum remembered depth for going back up.
      33             : ///
      34             : /// General usage:
      35             : ///
      36             : ///     Position<DataType, 10> position(tree, tree_size);
      37             : ///
      38             : ///     position.Enter(ByName("foo"));
      39             : ///     position.Enter(ByName("bar"));
      40             : ///     position.Enter(ByName("baz"));
      41             : ///
      42             : ///     position.Get()  /// content of foo::bar::baz if it exists
      43             : ///
      44             : ///     position.Exit();
      45             : ///     position.Exit();
      46             : ///
      47             : ///     position.Get()  /// content of foo if it exists
      48             : ///
      49             : ///     position.Enter(ById(1234));
      50             : ///
      51             : ///     position.Get()  /// content of foo::1234
      52             : ///
      53             : template <typename CONTENT, size_t DESCEND_DEPTH>
      54             : class Position
      55             : {
      56             : public:
      57          56 :     Position(const Node<CONTENT> * tree, size_t treeSize) : mTree(tree), mTreeSize(treeSize) {}
      58             : 
      59             :     template <size_t N>
      60             :     Position(const std::array<const Node<CONTENT>, N> & tree) : mTree(tree.data()), mTreeSize(N)
      61             :     {}
      62             : 
      63             :     // Move back to the top
      64         153 :     void ResetToTop()
      65             :     {
      66         153 :         mDescendDepth        = 0;
      67         153 :         mUnknownDescendDepth = 0;
      68         153 :     }
      69             : 
      70             :     /// Attempt to find a child of the current position that matches
      71             :     /// the given matcher
      72             :     template <typename MATCHER>
      73             :     void Enter(MATCHER matcher);
      74             : 
      75             :     /// Move up the tree, undoes an 'Enter' operation.
      76             :     void Exit();
      77             : 
      78             :     /// Fetch the value where the node is positioned on or nullptr if that
      79             :     /// value is not available;
      80             :     const CONTENT * Get() const;
      81             : 
      82             :     /// Returns the entries visited so far
      83             :     ///
      84             :     /// WILL RETURN EMPTY if the descend depth has been
      85             :     /// exceeded. Callers MUST handle empty return.
      86             :     ///
      87             :     /// Span valid until one of Enter/Exit functions are called
      88             :     /// and as long as the Position is valid (points inside the object).
      89             :     chip::Span<const Entry<CONTENT> *> CurrentPath();
      90             : 
      91          24 :     bool HasValidTree() const { return mTree != nullptr; }
      92             : 
      93          11 :     size_t DescendDepth() const { return mDescendDepth + mUnknownDescendDepth; }
      94             : 
      95             : private:
      96             :     // actual tree that we visit
      97             :     const Node<CONTENT> * mTree = nullptr;
      98             :     const size_t mTreeSize      = 0;
      99             : 
     100             :     // Keeping track of descending into the tree, to be able to move back
     101             :     // last element in the array is the "current" item
     102             :     const Entry<CONTENT> * mPositions[DESCEND_DEPTH] = { nullptr };
     103             :     size_t mDescendDepth                             = 0; // filled amount of mDescendPositions
     104             : 
     105             :     // Descend past remembering memory or in not-found entries.
     106             :     size_t mUnknownDescendDepth = 0; // depth in invalid positions
     107             : };
     108             : 
     109             : template <typename CONTENT, size_t DESCEND_DEPTH>
     110         920 : const CONTENT * Position<CONTENT, DESCEND_DEPTH>::Get() const
     111             : {
     112         920 :     if (mUnknownDescendDepth > 0)
     113             :     {
     114         137 :         return nullptr;
     115             :     }
     116             : 
     117         783 :     if (mDescendDepth == 0)
     118             :     {
     119           0 :         return nullptr;
     120             :     }
     121             : 
     122         783 :     return &mPositions[mDescendDepth - 1]->data;
     123             : }
     124             : 
     125             : template <typename CONTENT, size_t DESCEND_DEPTH>
     126             : template <typename MATCHER>
     127         602 : void Position<CONTENT, DESCEND_DEPTH>::Enter(MATCHER matcher)
     128             : {
     129         602 :     if (mUnknownDescendDepth > 0)
     130             :     {
     131             :         // keep descending into the unknown
     132          66 :         mUnknownDescendDepth++;
     133          66 :         return;
     134             :     }
     135             : 
     136             :     // To be able to descend, we have to be able to remember
     137             :     // the current position
     138         536 :     if (mDescendDepth == DESCEND_DEPTH)
     139             :     {
     140           0 :         mUnknownDescendDepth = 1;
     141           0 :         return;
     142             :     }
     143             : 
     144         536 :     size_t nodeIdx = 0; // assume root node
     145         536 :     if (mDescendDepth > 0)
     146             :     {
     147         411 :         nodeIdx = mPositions[mDescendDepth - 1]->node_index;
     148             :     }
     149             : 
     150         536 :     const Entry<CONTENT> * child = FindEntry(mTree, mTreeSize, nodeIdx, matcher);
     151             : 
     152         536 :     if (child == nullptr)
     153             :     {
     154          43 :         mUnknownDescendDepth = 1;
     155          43 :         return;
     156             :     }
     157             : 
     158         493 :     mPositions[mDescendDepth++] = child;
     159             : }
     160             : 
     161             : template <typename CONTENT, size_t DESCEND_DEPTH>
     162         420 : void Position<CONTENT, DESCEND_DEPTH>::Exit()
     163             : {
     164         420 :     if (mUnknownDescendDepth > 0)
     165             :     {
     166          50 :         mUnknownDescendDepth--;
     167          50 :         return;
     168             :     }
     169             : 
     170         370 :     if (mDescendDepth > 0)
     171             :     {
     172         370 :         mDescendDepth--;
     173             :     }
     174             : }
     175             : 
     176             : template <typename CONTENT, size_t DESCEND_DEPTH>
     177             : chip::Span<const Entry<CONTENT> *> Position<CONTENT, DESCEND_DEPTH>::CurrentPath()
     178             : {
     179             :     if (mUnknownDescendDepth > 0)
     180             :     {
     181             :         return chip::Span<const Entry<CONTENT> *>();
     182             :     }
     183             : 
     184             :     // const chip::FlatTree::Entry<{anonymous}::NamedTag>* const* to
     185             :     // const chip::FlatTree::Entry<{anonymous}::NamedTag>**
     186             :     typename chip::Span<const Entry<CONTENT> *>::pointer p = mPositions;
     187             : 
     188             :     // return chip::Span<const Entry<CONTENT> *>(mPositions, mDescendDepth);
     189             :     return chip::Span<const Entry<CONTENT> *>(p, mDescendDepth);
     190             : }
     191             : 
     192             : } // namespace FlatTree
     193             : } // namespace chip

Generated by: LCOV version 1.14