| Directory: | ./ |
|---|---|
| File: | src/msrproto/DirNode.cpp |
| Date: | 2025-02-12 12:41:42 |
| Exec | Total | Coverage | |
|---|---|---|---|
| Lines: | 63 | 79 | 79.7% |
| Branches: | 90 | 152 | 59.2% |
| 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 | 248 | DirectoryPathIterator(const char *path) { pathPtr = path; } | |
| 39 | |||
| 40 | 522 | std::string next() | |
| 41 | { | ||
| 42 | 522 | const char *p = pathPtr; | |
| 43 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 522 times.
|
522 | pathPtr = strchr(pathPtr, dirSeparator); |
| 44 |
12/22✓ Branch 1 taken 299 times.
✓ Branch 2 taken 223 times.
✓ Branch 8 taken 299 times.
✗ Branch 9 not taken.
✓ Branch 13 taken 223 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 223 times.
✓ Branch 16 taken 299 times.
✓ Branch 18 taken 223 times.
✓ Branch 19 taken 299 times.
✓ Branch 21 taken 299 times.
✓ Branch 22 taken 223 times.
✓ Branch 24 taken 299 times.
✓ Branch 25 taken 223 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.
|
522 | return pathPtr ? std::string(p, skip() - p) : p; |
| 45 | } | ||
| 46 | |||
| 47 |
3/4✓ Branch 1 taken 463 times.
✓ Branch 2 taken 111 times.
✓ Branch 5 taken 463 times.
✗ Branch 6 not taken.
|
574 | bool hasNext() const { return pathPtr and *pathPtr; } |
| 48 | |||
| 49 | private: | ||
| 50 | const char *pathPtr; | ||
| 51 | |||
| 52 | static const char dirSeparator; | ||
| 53 | |||
| 54 | 299 | const char *skip() | |
| 55 | { | ||
| 56 | 299 | const char *p = pathPtr; | |
| 57 | |||
| 58 |
3/4✓ Branch 2 taken 598 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 299 times.
✓ Branch 7 taken 299 times.
|
897 | while (*pathPtr and *pathPtr == dirSeparator) |
| 59 | 299 | ++pathPtr; | |
| 60 | |||
| 61 | 299 | return p; | |
| 62 | } | ||
| 63 | }; | ||
| 64 | |||
| 65 | } // namespace | ||
| 66 | const char DirectoryPathIterator::dirSeparator = '/'; | ||
| 67 | |||
| 68 | /////////////////////////////////////////////////////////////////////////// | ||
| 69 | /////////////////////////////////////////////////////////////////////////// | ||
| 70 | 137 | DirNode::DirNode(bool isDir) | |
| 71 | { | ||
| 72 | 137 | m_parent = this; | |
| 73 | 137 | directory = isDir; | |
| 74 | 137 | } | |
| 75 | |||
| 76 | /////////////////////////////////////////////////////////////////////////// | ||
| 77 | 258 | std::string DirNode::path() const | |
| 78 | { | ||
| 79 |
13/24✓ Branch 3 taken 112 times.
✓ Branch 4 taken 146 times.
✓ Branch 13 taken 146 times.
✗ Branch 14 not taken.
✓ Branch 17 taken 146 times.
✗ Branch 18 not taken.
✓ Branch 22 taken 146 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 146 times.
✓ Branch 25 taken 112 times.
✓ Branch 27 taken 146 times.
✓ Branch 28 taken 112 times.
✓ Branch 30 taken 146 times.
✓ Branch 31 taken 112 times.
✓ Branch 33 taken 146 times.
✓ Branch 34 taken 112 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.
|
258 | return m_parent == this ? std::string() : (m_parent->path() + '/' + m_name); |
| 80 | } | ||
| 81 | |||
| 82 | /////////////////////////////////////////////////////////////////////////// | ||
| 83 | 59 | void DirNode::insert(std::shared_ptr<DirNode> child, const char *cpath) | |
| 84 | { | ||
| 85 | 59 | DirectoryPathIterator path(cpath); | |
| 86 |
1/2✓ Branch 2 taken 59 times.
✗ Branch 3 not taken.
|
118 | std::shared_ptr<DirNode> parent = shared_from_this(); |
| 87 | |||
| 88 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 59 times.
|
59 | if (!path.hasNext()) { |
| 89 | ✗ | return; | |
| 90 | } | ||
| 91 | |||
| 92 | while (true) { | ||
| 93 |
4/5✓ Branch 2 taken 130 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 12 times.
✓ Branch 7 taken 59 times.
✓ Branch 8 taken 59 times.
|
142 | std::string name = path.next(); |
| 94 | |||
| 95 |
2/2✓ Branch 1 taken 59 times.
✓ Branch 2 taken 71 times.
|
189 | if (name.empty()) { |
| 96 | // Find root node | ||
| 97 |
1/2✓ Branch 2 taken 59 times.
✗ Branch 3 not taken.
|
59 | parent = getRootNode(); |
| 98 | 59 | continue; | |
| 99 | } | ||
| 100 | |||
| 101 | 71 | NodeVector::iterator it = std::lower_bound( | |
| 102 | 213 | parent->children.begin(), parent->children.end(), name, | |
| 103 |
4/5✓ Branch 4 taken 71 times.
✗ Branch 5 not taken.
✓ Branch 9 taken 12 times.
✓ Branch 10 taken 59 times.
✓ Branch 11 taken 59 times.
|
296 | LessThan()); |
| 104 | |||
| 105 | // Insert a new node if it exists | ||
| 106 |
8/10✓ Branch 5 taken 2 times.
✓ Branch 6 taken 69 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 1 times.
✓ Branch 14 taken 71 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 71 times.
✗ Branch 18 not taken.
✓ Branch 20 taken 70 times.
✓ Branch 21 taken 1 times.
|
71 | if (it == parent->children.end() or (*it)->m_name != name) |
| 107 |
1/2✓ Branch 8 taken 70 times.
✗ Branch 9 not taken.
|
70 | it = parent->children.insert(it, 0); |
| 108 | 71 | std::shared_ptr<DirNode> &node = *it; | |
| 109 | |||
| 110 |
2/2✓ Branch 1 taken 12 times.
✓ Branch 2 taken 59 times.
|
71 | if (path.hasNext()) { |
| 111 |
2/2✓ Branch 2 taken 11 times.
✓ Branch 3 taken 1 times.
|
12 | if (!node) { |
| 112 |
2/4✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 7 taken 11 times.
✗ Branch 8 not taken.
|
11 | node.reset(new DirNode); |
| 113 | 11 | node->m_parent = parent.get(); | |
| 114 |
1/2✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
|
11 | node->m_name = name; |
| 115 | } | ||
| 116 | 12 | parent = node; | |
| 117 | } | ||
| 118 | else { | ||
| 119 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 59 times.
|
59 | 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 | ✗ | std::swap(node->children, child->children); | |
| 124 | ✗ | child->directory = true; | |
| 125 | ✗ | for (auto &cchild : child->children) | |
| 126 | ✗ | cchild->m_parent = child.get(); | |
| 127 | |||
| 128 | ✗ | node.reset(); | |
| 129 | } | ||
| 130 | |||
| 131 | 59 | child->m_parent = parent.get(); | |
| 132 |
1/2✓ Branch 3 taken 59 times.
✗ Branch 4 not taken.
|
59 | child->m_name = name; |
| 133 | 59 | node = std::move(child); | |
| 134 | |||
| 135 |
2/2✓ Branch 1 taken 12 times.
✓ Branch 2 taken 59 times.
|
59 | return; |
| 136 | } | ||
| 137 | 71 | } | |
| 138 | } | ||
| 139 | |||
| 140 | /////////////////////////////////////////////////////////////////////////// | ||
| 141 | 1 | std::string DirNode::name() const | |
| 142 | { | ||
| 143 | 1 | return m_name; | |
| 144 | } | ||
| 145 | |||
| 146 | /////////////////////////////////////////////////////////////////////////// | ||
| 147 | 189 | std::shared_ptr<DirNode> DirNode::find(const std::string &pathStr) | |
| 148 | { | ||
| 149 |
1/2✓ Branch 2 taken 189 times.
✗ Branch 3 not taken.
|
378 | std::shared_ptr<DirNode> node = shared_from_this(); |
| 150 | 189 | DirectoryPathIterator path(pathStr.c_str()); | |
| 151 | |||
| 152 |
2/2✓ Branch 1 taken 392 times.
✓ Branch 2 taken 52 times.
|
699 | while (path.hasNext()) { |
| 153 |
4/5✓ Branch 2 taken 392 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 66 times.
✓ Branch 7 taken 189 times.
✓ Branch 8 taken 137 times.
|
458 | std::string name = path.next(); |
| 154 | |||
| 155 |
2/2✓ Branch 1 taken 189 times.
✓ Branch 2 taken 203 times.
|
581 | if (name.empty()) { |
| 156 | // Find root node | ||
| 157 |
1/2✓ Branch 2 taken 189 times.
✗ Branch 3 not taken.
|
189 | node = getRootNode(); |
| 158 | 189 | continue; | |
| 159 | } | ||
| 160 | |||
| 161 | 203 | NodeVector::iterator it = std::lower_bound( | |
| 162 |
4/5✓ Branch 8 taken 203 times.
✗ Branch 9 not taken.
✓ Branch 16 taken 66 times.
✓ Branch 17 taken 189 times.
✓ Branch 18 taken 137 times.
|
269 | node->children.begin(), node->children.end(), name, LessThan()); |
| 163 | |||
| 164 |
8/10✓ Branch 5 taken 69 times.
✓ Branch 6 taken 134 times.
✓ Branch 12 taken 3 times.
✓ Branch 13 taken 66 times.
✓ Branch 14 taken 203 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 203 times.
✗ Branch 18 not taken.
✓ Branch 20 taken 137 times.
✓ Branch 21 taken 66 times.
|
203 | if (it == node->children.end() or name != (*it)->m_name) |
| 165 | 137 | return nullptr; | |
| 166 | |||
| 167 |
2/2✓ Branch 4 taken 66 times.
✓ Branch 5 taken 137 times.
|
66 | node = *it; |
| 168 | } | ||
| 169 | |||
| 170 | 52 | return node; | |
| 171 | } | ||
| 172 | |||
| 173 | /////////////////////////////////////////////////////////////////////////// | ||
| 174 | ✗ | void DirNode::getChildren(List &list) const | |
| 175 | { | ||
| 176 | ✗ | for (const auto &child : children) | |
| 177 | ✗ | list.push_back(child); | |
| 178 | } | ||
| 179 | |||
| 180 | /////////////////////////////////////////////////////////////////////////// | ||
| 181 | ✗ | void DirNode::getAllChildren(List &list) const | |
| 182 | { | ||
| 183 | ✗ | for (const auto &child : children) { | |
| 184 | ✗ | list.push_back(child); | |
| 185 | ✗ | child->getAllChildren(list); | |
| 186 | } | ||
| 187 | } | ||
| 188 | |||
| 189 | /////////////////////////////////////////////////////////////////////////// | ||
| 190 | ✗ | bool DirNode::hasChildren() const | |
| 191 | { | ||
| 192 | ✗ | return directory or !children.empty(); | |
| 193 | } | ||
| 194 | |||
| 195 | ///////////////////////////////////////////////////////////////////////////// | ||
| 196 | 248 | std::shared_ptr<DirNode> DirNode::getRootNode() | |
| 197 | { | ||
| 198 | 248 | DirNode *n = this; | |
| 199 |
1/2✗ Branch 3 not taken.
✓ Branch 4 taken 248 times.
|
248 | while (n->m_parent != n) |
| 200 | ✗ | n = n->m_parent; | |
| 201 | 248 | return n->shared_from_this(); | |
| 202 | } | ||
| 203 |