// // Copyright 2011,2014-2016 Ettus Research // Copyright 2018 Ettus Research, a National Instruments Company // Copyright 2019 Ettus Research, a National Instruments Brand // // SPDX-License-Identifier: GPL-3.0-or-later // #include #include #include #include using namespace uhd; /*********************************************************************** * Helper function to iterate through paths **********************************************************************/ #include #define path_tokenizer(path) \ boost::tokenizer>(path, boost::char_separator("/")) /*********************************************************************** * Property path implementation wrapper **********************************************************************/ fs_path::fs_path(void) : std::string() {} fs_path::fs_path(const char* p) : std::string(p) {} fs_path::fs_path(const std::string& p) : std::string(p) {} std::string fs_path::leaf(void) const { const size_t pos = this->rfind("/"); if (pos == std::string::npos) { return *this; } return this->substr(pos + 1); } fs_path fs_path::branch_path(void) const { const size_t pos = this->rfind("/"); if (pos == std::string::npos) { return *this; } return fs_path(this->substr(0, pos)); } fs_path uhd::operator/(const fs_path& lhs, const fs_path& rhs) { // strip trailing slash on left-hand-side if (not lhs.empty() and *lhs.rbegin() == '/') { return fs_path(lhs.substr(0, lhs.size() - 1)) / rhs; } // strip leading slash on right-hand-side if (not rhs.empty() and *rhs.begin() == '/') { return lhs / fs_path(rhs.substr(1)); } return fs_path(lhs + "/" + rhs); } fs_path uhd::operator/(const fs_path& lhs, size_t rhs) { fs_path rhs_str = std::to_string(rhs); return lhs / rhs_str; } /*********************************************************************** * Property tree implementation **********************************************************************/ class property_tree_impl : public uhd::property_tree { public: property_tree_impl(const fs_path& root = fs_path()) : _root(root) { _guts = std::make_shared(); } sptr subtree(const fs_path& path_) const override { const fs_path path = _root / path_; std::lock_guard lock(_guts->mutex); property_tree_impl* subtree = new property_tree_impl(path); subtree->_guts = this->_guts; // copy the guts sptr return sptr(subtree); } void remove(const fs_path& path_) override { const fs_path path = _root / path_; std::lock_guard lock(_guts->mutex); node_type* parent = NULL; node_type* node = &_guts->root; for (const std::string& name : path_tokenizer(path)) { if (not node->has_key(name)) { throw_path_not_found(path); } parent = node; node = &(*node)[name]; } if (parent == NULL) { throw uhd::runtime_error("Cannot uproot"); } parent->pop(fs_path(path.leaf())); } bool exists(const fs_path& path_) const override { const fs_path path = _root / path_; std::lock_guard lock(_guts->mutex); node_type* node = &_guts->root; for (const std::string& name : path_tokenizer(path)) { if (not node->has_key(name)) { return false; } node = &(*node)[name]; } return true; } std::vector list(const fs_path& path_) const override { const fs_path path = _root / path_; std::lock_guard lock(_guts->mutex); node_type* node = &_guts->root; for (const std::string& name : path_tokenizer(path)) { if (not node->has_key(name)) { throw_path_not_found(path); } node = &(*node)[name]; } return node->keys(); } std::shared_ptr _pop(const fs_path& path_) override { const fs_path path = _root / path_; std::lock_guard lock(_guts->mutex); node_type* parent = NULL; node_type* node = &_guts->root; for (const std::string& name : path_tokenizer(path)) { if (not node->has_key(name)) { throw_path_not_found(path); } parent = node; node = &(*node)[name]; } if (node->prop.get() == NULL) { throw uhd::runtime_error("Cannot access! Property uninitialized at: " + path); } if (parent == NULL) { throw uhd::runtime_error("Cannot pop"); } auto prop = node->prop; parent->pop(fs_path(path.leaf())); return prop; } void _create(const fs_path& path_, const std::shared_ptr& prop) override { const fs_path path = _root / path_; std::lock_guard lock(_guts->mutex); node_type* node = &_guts->root; for (const std::string& name : path_tokenizer(path)) { if (not node->has_key(name)) { (*node)[name] = node_type(); } node = &(*node)[name]; } if (node->prop.get() != NULL) { throw uhd::runtime_error( "Cannot create! Property already exists at: " + path); } node->prop = prop; } std::shared_ptr& _access(const fs_path& path_) const override { const fs_path path = _root / path_; std::lock_guard lock(_guts->mutex); node_type* node = &_guts->root; for (const std::string& name : path_tokenizer(path)) { if (not node->has_key(name)) { throw_path_not_found(path); } node = &(*node)[name]; } if (node->prop.get() == NULL) { throw uhd::runtime_error("Cannot access! Property uninitialized at: " + path); } return node->prop; } private: void throw_path_not_found(const fs_path& path) const { throw uhd::lookup_error("Path not found in tree: " + path); } // basic structural node element struct node_type : uhd::dict { std::shared_ptr prop; }; // tree guts which may be referenced in a subtree struct tree_guts_type { node_type root; std::mutex mutex; }; // members, the tree and root prefix std::shared_ptr _guts; const fs_path _root; }; property_tree::~property_tree(void) { /* NOP */ } /*********************************************************************** * Property tree factory **********************************************************************/ uhd::property_tree::sptr uhd::property_tree::make(void) { return std::make_shared(); }