| Directory: | ./ |
|---|---|
| File: | pdcom5/src/msrproto/DirNode.cpp |
| Date: | 2025-11-02 04:09:49 |
| 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 |