Directory: | ./ |
---|---|
File: | pdcom5/src/msrproto/DirNode.cpp |
Date: | 2024-12-15 04:08:34 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 79 | 81 | 97.5% |
Branches: | 104 | 152 | 68.4% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /***************************************************************************** | ||
2 | * | ||
3 | * Copyright (C) 2015-2016 Richard Hacker (lerichi at gmx dot net) | ||
4 | * | ||
5 | * This file is part of the PdCom library. | ||
6 | * | ||
7 | * The PdCom library is free software: you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU Lesser General Public License as published by | ||
9 | * the Free Software Foundation, either version 3 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | * The PdCom library is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
14 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
15 | * License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU Lesser General Public License | ||
18 | * along with the PdCom library. If not, see <http://www.gnu.org/licenses/>. | ||
19 | * | ||
20 | *****************************************************************************/ | ||
21 | |||
22 | #include "DirNode.h" | ||
23 | |||
24 | #include "../Debug.h" | ||
25 | |||
26 | #include <algorithm> // std::copy | ||
27 | #include <cstring> // strchr() | ||
28 | #include <iterator> // back_inserter | ||
29 | |||
30 | using namespace PdCom::impl::MsrProto; | ||
31 | |||
32 | namespace { | ||
33 | /////////////////////////////////////////////////////////////////////////// | ||
34 | /////////////////////////////////////////////////////////////////////////// | ||
35 | class DirectoryPathIterator | ||
36 | { | ||
37 | public: | ||
38 | 960 | DirectoryPathIterator(const char *path) { pathPtr = path; } | |
39 | |||
40 | 3202 | std::string next() | |
41 | { | ||
42 | 3202 | const char *p = pathPtr; | |
43 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3202 times.
|
3202 | pathPtr = strchr(pathPtr, dirSeparator); |
44 |
12/22✓ Branch 1 taken 2451 times.
✓ Branch 2 taken 751 times.
✓ Branch 8 taken 2451 times.
✗ Branch 9 not taken.
✓ Branch 13 taken 751 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 751 times.
✓ Branch 16 taken 2451 times.
✓ Branch 18 taken 751 times.
✓ Branch 19 taken 2451 times.
✓ Branch 21 taken 2451 times.
✓ Branch 22 taken 751 times.
✓ Branch 24 taken 2451 times.
✓ Branch 25 taken 751 times.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
|
3202 | return pathPtr ? std::string(p, skip() - p) : p; |
45 | } | ||
46 | |||
47 |
3/4✓ Branch 1 taken 2820 times.
✓ Branch 2 taken 474 times.
✓ Branch 5 taken 2820 times.
✗ Branch 6 not taken.
|
3294 | bool hasNext() const { return pathPtr and *pathPtr; } |
48 | |||
49 | private: | ||
50 | const char *pathPtr; | ||
51 | |||
52 | static const char dirSeparator; | ||
53 | |||
54 | 2451 | const char *skip() | |
55 | { | ||
56 | 2451 | const char *p = pathPtr; | |
57 | |||
58 |
3/4✓ Branch 2 taken 4902 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2451 times.
✓ Branch 7 taken 2451 times.
|
7353 | while (*pathPtr and *pathPtr == dirSeparator) |
59 | 2451 | ++pathPtr; | |
60 | |||
61 | 2451 | return p; | |
62 | } | ||
63 | }; | ||
64 | |||
65 | } // namespace | ||
66 | const char DirectoryPathIterator::dirSeparator = '/'; | ||
67 | |||
68 | /////////////////////////////////////////////////////////////////////////// | ||
69 | /////////////////////////////////////////////////////////////////////////// | ||
70 | 709 | DirNode::DirNode(bool isDir) | |
71 | { | ||
72 | 709 | m_parent = this; | |
73 | 709 | directory = isDir; | |
74 | 709 | } | |
75 | |||
76 | /////////////////////////////////////////////////////////////////////////// | ||
77 | 1779 | std::string DirNode::path() const | |
78 | { | ||
79 |
13/24✓ Branch 3 taken 481 times.
✓ Branch 4 taken 1298 times.
✓ Branch 13 taken 1298 times.
✗ Branch 14 not taken.
✓ Branch 17 taken 1298 times.
✗ Branch 18 not taken.
✓ Branch 22 taken 1298 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 1298 times.
✓ Branch 25 taken 481 times.
✓ Branch 27 taken 1298 times.
✓ Branch 28 taken 481 times.
✓ Branch 30 taken 1298 times.
✓ Branch 31 taken 481 times.
✓ Branch 33 taken 1298 times.
✓ Branch 34 taken 481 times.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
|
1779 | return m_parent == this ? std::string() : (m_parent->path() + '/' + m_name); |
80 | } | ||
81 | |||
82 | /////////////////////////////////////////////////////////////////////////// | ||
83 | 382 | void DirNode::insert(std::shared_ptr<DirNode> child, const char *cpath) | |
84 | { | ||
85 | 382 | DirectoryPathIterator path(cpath); | |
86 |
1/2✓ Branch 2 taken 382 times.
✗ Branch 3 not taken.
|
764 | std::shared_ptr<DirNode> parent = shared_from_this(); |
87 | |||
88 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 382 times.
|
382 | if (!path.hasNext()) { |
89 | ✗ | return; | |
90 | } | ||
91 | |||
92 | while (true) { | ||
93 |
4/5✓ Branch 2 taken 1436 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 672 times.
✓ Branch 7 taken 382 times.
✓ Branch 8 taken 382 times.
|
2108 | std::string name = path.next(); |
94 | |||
95 |
2/2✓ Branch 1 taken 382 times.
✓ Branch 2 taken 1054 times.
|
1818 | if (name.empty()) { |
96 | // Find root node | ||
97 |
1/2✓ Branch 2 taken 382 times.
✗ Branch 3 not taken.
|
382 | parent = getRootNode(); |
98 | 382 | continue; | |
99 | } | ||
100 | |||
101 | 1054 | NodeVector::iterator it = std::lower_bound( | |
102 | 3162 | parent->children.begin(), parent->children.end(), name, | |
103 |
4/5✓ Branch 4 taken 1054 times.
✗ Branch 5 not taken.
✓ Branch 9 taken 672 times.
✓ Branch 10 taken 382 times.
✓ Branch 11 taken 382 times.
|
4888 | LessThan()); |
104 | |||
105 | // Insert a new node if it exists | ||
106 |
8/10✓ Branch 5 taken 617 times.
✓ Branch 6 taken 437 times.
✓ Branch 12 taken 113 times.
✓ Branch 13 taken 504 times.
✓ Branch 14 taken 1054 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 1054 times.
✗ Branch 18 not taken.
✓ Branch 20 taken 550 times.
✓ Branch 21 taken 504 times.
|
1054 | if (it == parent->children.end() or (*it)->m_name != name) |
107 |
1/2✓ Branch 8 taken 550 times.
✗ Branch 9 not taken.
|
550 | it = parent->children.insert(it, 0); |
108 | 1054 | std::shared_ptr<DirNode> &node = *it; | |
109 | |||
110 |
2/2✓ Branch 1 taken 672 times.
✓ Branch 2 taken 382 times.
|
1054 | if (path.hasNext()) { |
111 |
2/2✓ Branch 2 taken 170 times.
✓ Branch 3 taken 502 times.
|
672 | if (!node) { |
112 |
2/4✓ Branch 2 taken 170 times.
✗ Branch 3 not taken.
✓ Branch 7 taken 170 times.
✗ Branch 8 not taken.
|
170 | node.reset(new DirNode); |
113 | 170 | node->m_parent = parent.get(); | |
114 |
1/2✓ Branch 4 taken 170 times.
✗ Branch 5 not taken.
|
170 | node->m_name = name; |
115 | } | ||
116 | 672 | parent = node; | |
117 | } | ||
118 | else { | ||
119 |
2/2✓ Branch 2 taken 2 times.
✓ Branch 3 taken 380 times.
|
382 | if (node) { |
120 | // Node exists. This can happen, when a deep node has | ||
121 | // been discovered before the current node. An example is a | ||
122 | // signal that has parameters as children | ||
123 | 2 | std::swap(node->children, child->children); | |
124 | 2 | child->directory = true; | |
125 |
2/2✓ Branch 7 taken 2 times.
✓ Branch 8 taken 2 times.
|
4 | for (auto &cchild : child->children) |
126 | 2 | cchild->m_parent = child.get(); | |
127 | |||
128 | 2 | node.reset(); | |
129 | } | ||
130 | |||
131 | 382 | child->m_parent = parent.get(); | |
132 |
1/2✓ Branch 3 taken 382 times.
✗ Branch 4 not taken.
|
382 | child->m_name = name; |
133 | 382 | node = std::move(child); | |
134 | |||
135 |
2/2✓ Branch 1 taken 672 times.
✓ Branch 2 taken 382 times.
|
382 | return; |
136 | } | ||
137 | 1054 | } | |
138 | } | ||
139 | |||
140 | /////////////////////////////////////////////////////////////////////////// | ||
141 | 5 | std::string DirNode::name() const | |
142 | { | ||
143 | 5 | return m_name; | |
144 | } | ||
145 | |||
146 | /////////////////////////////////////////////////////////////////////////// | ||
147 | 578 | std::shared_ptr<DirNode> DirNode::find(const std::string &pathStr) | |
148 | { | ||
149 |
1/2✓ Branch 2 taken 578 times.
✗ Branch 3 not taken.
|
1156 | std::shared_ptr<DirNode> node = shared_from_this(); |
150 | 578 | DirectoryPathIterator path(pathStr.c_str()); | |
151 | |||
152 |
2/2✓ Branch 1 taken 1766 times.
✓ Branch 2 taken 92 times.
|
3138 | while (path.hasNext()) { |
153 |
4/5✓ Branch 2 taken 1766 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 702 times.
✓ Branch 7 taken 578 times.
✓ Branch 8 taken 486 times.
|
2468 | std::string name = path.next(); |
154 | |||
155 |
2/2✓ Branch 1 taken 578 times.
✓ Branch 2 taken 1188 times.
|
2344 | if (name.empty()) { |
156 | // Find root node | ||
157 |
1/2✓ Branch 2 taken 578 times.
✗ Branch 3 not taken.
|
578 | node = getRootNode(); |
158 | 578 | continue; | |
159 | } | ||
160 | |||
161 | 1188 | NodeVector::iterator it = std::lower_bound( | |
162 |
4/5✓ Branch 8 taken 1188 times.
✗ Branch 9 not taken.
✓ Branch 16 taken 702 times.
✓ Branch 17 taken 578 times.
✓ Branch 18 taken 486 times.
|
1890 | node->children.begin(), node->children.end(), name, LessThan()); |
163 | |||
164 |
8/10✓ Branch 5 taken 816 times.
✓ Branch 6 taken 372 times.
✓ Branch 12 taken 114 times.
✓ Branch 13 taken 702 times.
✓ Branch 14 taken 1188 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 1188 times.
✗ Branch 18 not taken.
✓ Branch 20 taken 486 times.
✓ Branch 21 taken 702 times.
|
1188 | if (it == node->children.end() or name != (*it)->m_name) |
165 | 486 | return nullptr; | |
166 | |||
167 |
2/2✓ Branch 4 taken 702 times.
✓ Branch 5 taken 486 times.
|
702 | node = *it; |
168 | } | ||
169 | |||
170 | 92 | return node; | |
171 | } | ||
172 | |||
173 | /////////////////////////////////////////////////////////////////////////// | ||
174 | 12 | void DirNode::getChildren(List &list) const | |
175 | { | ||
176 |
2/2✓ Branch 6 taken 18 times.
✓ Branch 7 taken 12 times.
|
30 | for (const auto &child : children) |
177 |
1/2✓ Branch 3 taken 18 times.
✗ Branch 4 not taken.
|
18 | list.push_back(child); |
178 | 12 | } | |
179 | |||
180 | /////////////////////////////////////////////////////////////////////////// | ||
181 | 264 | void DirNode::getAllChildren(List &list) const | |
182 | { | ||
183 |
2/2✓ Branch 6 taken 258 times.
✓ Branch 7 taken 264 times.
|
522 | for (const auto &child : children) { |
184 |
1/2✓ Branch 3 taken 258 times.
✗ Branch 4 not taken.
|
258 | list.push_back(child); |
185 |
1/2✓ Branch 6 taken 258 times.
✗ Branch 7 not taken.
|
258 | child->getAllChildren(list); |
186 | } | ||
187 | 264 | } | |
188 | |||
189 | /////////////////////////////////////////////////////////////////////////// | ||
190 | 18 | bool DirNode::hasChildren() const | |
191 | { | ||
192 |
4/6✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✓ Branch 5 taken 12 times.
✓ Branch 6 taken 6 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 12 times.
|
18 | return directory or !children.empty(); |
193 | } | ||
194 | |||
195 | ///////////////////////////////////////////////////////////////////////////// | ||
196 | 960 | std::shared_ptr<DirNode> DirNode::getRootNode() | |
197 | { | ||
198 | 960 | DirNode *n = this; | |
199 |
1/2✗ Branch 3 not taken.
✓ Branch 4 taken 960 times.
|
960 | while (n->m_parent != n) |
200 | ✗ | n = n->m_parent; | |
201 | 960 | return n->shared_from_this(); | |
202 | } | ||
203 |