| 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 |