Coverage Report

Created: 2024-12-17 06:44

/src/connectedhomeip/src/lib/format/FlatTreePosition.h
Line
Count
Source (jump to first uncovered line)
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
114k
    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
    void ResetToTop()
65
123k
    {
66
123k
        mDescendDepth        = 0;
67
123k
        mUnknownDescendDepth = 0;
68
123k
    }
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
5.08k
    bool HasValidTree() const { return mTree != nullptr; }
92
93
12.7k
    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
const CONTENT * Position<CONTENT, DESCEND_DEPTH>::Get() const
111
35.2M
{
112
35.2M
    if (mUnknownDescendDepth > 0)
113
35.0M
    {
114
35.0M
        return nullptr;
115
35.0M
    }
116
117
178k
    if (mDescendDepth == 0)
118
0
    {
119
0
        return nullptr;
120
0
    }
121
122
178k
    return &mPositions[mDescendDepth - 1]->data;
123
178k
}
124
125
template <typename CONTENT, size_t DESCEND_DEPTH>
126
template <typename MATCHER>
127
void Position<CONTENT, DESCEND_DEPTH>::Enter(MATCHER matcher)
128
34.8M
{
129
34.8M
    if (mUnknownDescendDepth > 0)
130
34.5M
    {
131
        // keep descending into the unknown
132
34.5M
        mUnknownDescendDepth++;
133
34.5M
        return;
134
34.5M
    }
135
136
    // To be able to descend, we have to be able to remember
137
    // the current position
138
246k
    if (mDescendDepth == DESCEND_DEPTH)
139
0
    {
140
0
        mUnknownDescendDepth = 1;
141
0
        return;
142
0
    }
143
144
246k
    size_t nodeIdx = 0; // assume root node
145
246k
    if (mDescendDepth > 0)
146
180k
    {
147
180k
        nodeIdx = mPositions[mDescendDepth - 1]->node_index;
148
180k
    }
149
150
246k
    const Entry<CONTENT> * child = FindEntry(mTree, mTreeSize, nodeIdx, matcher);
151
152
246k
    if (child == nullptr)
153
85.6k
    {
154
85.6k
        mUnknownDescendDepth = 1;
155
85.6k
        return;
156
85.6k
    }
157
158
161k
    mPositions[mDescendDepth++] = child;
159
161k
}
160
161
template <typename CONTENT, size_t DESCEND_DEPTH>
162
void Position<CONTENT, DESCEND_DEPTH>::Exit()
163
424k
{
164
424k
    if (mUnknownDescendDepth > 0)
165
385k
    {
166
385k
        mUnknownDescendDepth--;
167
385k
        return;
168
385k
    }
169
170
38.5k
    if (mDescendDepth > 0)
171
38.5k
    {
172
38.5k
        mDescendDepth--;
173
38.5k
    }
174
38.5k
}
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