11#include "sparta/utils/Utils.hpp"
67 Node* parent_ =
nullptr;
74 uint32_t write_count_;
75 mutable uint32_t read_count_ = 0;
81 uint32_t required_ = 0;
90 Node(
Node* parent,
const std::string& name,
91 const std::string& value,
const std::string& origin) :
134 has_value_(n.has_value_),
135 write_count_(n.write_count_),
136 read_count_(n.read_count_)
138 for(
auto& x : n.children_){
139 children_.emplace_back(
new Node(
this, *x.get()));
154 has_value_ = n.has_value_;
155 write_count_ =
static_cast<decltype(write_count_)
>(has_value_);
157 for(
auto& x : n.children_){
158 children_.emplace_back(
new Node(
this, *x.get()));
168 void dump(std::ostream& o)
const {
169 o <<
"<VPT Node: \"" << name_ <<
"\" children:" << children_.size()
170 <<
" writes:" << write_count_ <<
" reads:" << read_count_ <<
" required:" << required_ <<
">";
176 const std::string&
getName()
const {
return name_; }
204 Node const * p =
this;
230 std::stack<const std::string*> names;
231 Node const * n =
this;
232 while(n && n->
getName().size() > 0){
237 std::stringstream ss;
238 if(names.size() > 0){
241 while(names.size() > 0){
242 ss <<
'.' << *names.top();
253 return name_.size() == 0;
313 template <typename T, typename=typename std::enable_if<!std::is_convertible<T, std::string>::value>::type>
321 template <typename T, typename=typename std::enable_if<std::is_convertible<T, std::string>::value>::type>
329 operator std::string ()
const {
337 template <
typename T>
338 operator T ()
const {
346 template <
typename T>
348 return getAs<T>() == rhp;
360 static bool matches(
const std::string& pattern,
const std::string& other) {
363 return std::regex_match(other, what, expr);
375 throw SpartaException(
"Cannot call ParameterTree::Node::getChild with a name that is a search pattern: \"")
376 << name <<
"\". addChild must be used instead";
380 auto itr = children_.rbegin();
381 for(; itr != children_.rend(); ++itr){
382 if(
matches((*itr)->getName(), name)){
401 if(path.size() == 0){
406 std::string immediate_child_name;
408 if(immediate_child_name.size() == 0){
422 child =
addChild(immediate_child_name, required);
425 if(name_pos == std::string::npos){
429 const std::string remainder = path.substr(name_pos);
430 return child->
create(remainder, required);
442 if(children_.size() == 0){
463 auto itr = children_.rbegin();
464 for(; itr != children_.rend(); ++itr){
465 if((*itr)->getName() == name){
471 if(name_has_wildcard){
477 }
else if(
matches(name, (*itr)->getName())){
488 }
else if(
matches((*itr)->getName(), name)){
504 "Cannot add a child to a virtual parameter tree node \"" << name_
505 <<
"\" since it already has a value: \"" << value_ <<
"\"");
506 children_.emplace_back(
new Node(
this, name));
508 children_.back()->incRequired();
510 return (children_.back().get());
523 "Node \"" << name_ <<
"\" has no child named \"" << name <<
"\"");
549 void setValue(
const std::string& val,
bool required=
true,
const std::string& origin=
"") {
576 for(
auto & n : children_){
587 return parent_->release_(
this);
603 bool set(
const std::string& path,
const std::string& val,
bool required,
const std::string& origin=
"") {
609 std::string full_path =
getPath();
610 if(full_path.size() > 0 && path.size() > 0){
614 return getOwner()->
set(full_path, val, required, origin);
655 std::vector<Node*> children;
656 for(
auto & n : children_){
657 children.push_back(n.get());
666 std::vector<const Node*> children;
667 for(
auto & n : children_){
668 children.push_back(n.get());
677 for(uint32_t i=0; i<indent; ++i){
682 o <<
" = \"" << value_ <<
"\" (read " << read_count_ <<
", written " << write_count_
683 <<
", required " << required_ <<
", origin '" <<
getOrigin() <<
"')";
686 for(
auto & n : children_){
687 n->recursePrint(o, indent+2);
704 sparta_assert(ot,
"Cannot append a null virtual parameter tree");
707 const bool required =
false;
709 child->recursAppendTree_(ot);
712 recursAppendTree_(ot);
721 ChildVector::const_reverse_iterator itr_;
732 return itr_ == rhp.itr_;
736 return itr_ != rhp.itr_;
739 void operator++(
int) {++itr_;}
741 void operator++() {++itr_;}
743 bool matches(
const std::string& other)
const {
747 const Node* get()
const {
755 const Node* operator->()
const {
779 void recursAppendTree_(
const Node* ot) {
787 Node* c =
create(child->getName(), child->getRequiredCount() > 0);
788 c->recursAppendTree_(child);
792 std::unique_ptr<Node> release_(
Node *node) {
793 std::unique_ptr<Node> rtn;
794 auto it = std::find_if(children_.begin(), children_.end(),
795 [node] (
const auto & child) ->
bool {
796 return (child.get() == node);
798 if (it != children_.end()) {
799 rtn = std::move(*it);
810 root_(new
Node(nullptr, this))
814 root_(new Node(nullptr, this))
816 root_->appendTree(rhp.getRoot());
837 root_.reset(
new Node(
nullptr,
this));
854 bool set(
const std::string& path,
const std::string& value,
bool required,
const std::string& origin=
"") {
859 n->
setValue(value, required, origin);
879 if(path.size() == 0){
883 return getRoot()->
create(path, required);
897 const Node&
get(
const std::string& path)
const {
900 throw SpartaException(
"Unable to find parameter in tree: \"") << path <<
"\"";
919 bool hasValue(
const std::string& path,
const bool must_be_leaf =
true)
const {
920 const Node* n = tryGet_(path, must_be_leaf);
921 return n !=
nullptr && n->
hasValue();
930 bool exists(
const std::string& path,
const bool must_be_leaf =
true)
const {
931 return tryGet_(path, must_be_leaf) !=
nullptr;
946 return recursCountUnreadValueNodes_<const Node>(root_.get(), nodes);
961 return recursCountUnreadValueNodes_<Node>(root_.get(), nodes);
969 const Node*
tryGet(
const std::string& path,
const bool must_be_leaf =
true)
const {
970 return tryGet_(path, must_be_leaf);
978 Node*
tryGet(
const std::string& path,
const bool must_be_leaf =
true) {
979 return tryGet_(path, must_be_leaf);
989 if(path.size() == 0){
990 return root_->getRequiredCount() > 0;
993 std::string immediate_child_name;
997 if(immediate_child_name.size() == 0){
1000 <<
" is invalid because it contains an empty name (between two '.' "
1001 "characters). Parents cannot currently be refrenced in the parameter tree";
1004 bool match_found =
false;
1005 const bool required = recursGetIsRequired_(root_.get(), path, immediate_child_name, name_pos, match_found);
1007 "Asked ParameterTree if path \"" << path <<
"\" is required but no "
1008 "matching node was found in the ParameterTree");
1018 Node * node = tryGet_(path,
false);
1019 if(
nullptr != node) {
1035 if(path.size() == 0){
1036 return root_->hasValue() && root_->getReadCount() > 0;
1039 std::string immediate_child_name;
1040 size_t name_pos = 0;
1043 if(immediate_child_name.size() == 0){
1046 <<
" is invalid because it contains an empty name (between two '.' "
1047 "characters). Parents cannot currently be refrenced in the parameter tree";
1050 return recursIsRead_(root_.get(), path, immediate_child_name, name_pos);
1053 Node
const * getRoot()
const {
return root_.get(); }
1055 Node * getRoot() {
return root_.get(); }
1063 root_->appendTree(rhp.getRoot());
1070 root_->recursePrint(o, 0);
1079 const Node* tryGet_(
const std::string& path,
const bool must_be_leaf =
true)
const {
1080 if(path.size() == 0){
1084 std::string immediate_child_name;
1085 size_t name_pos = 0;
1088 if(immediate_child_name.size() == 0){
1090 throw SpartaException(
"Parameter ") << path
1091 <<
" is invalid because it contains an empty name (between two '.' "
1092 "characters). Parents cannot currently be refrenced in the parameter tree";
1095 return recursTryGet_<const Node>(
static_cast<const Node*
>(root_.get()), path,
1096 immediate_child_name, name_pos, must_be_leaf);
1103 Node* tryGet_(
const std::string& path,
const bool must_be_leaf =
true) {
1104 if(path.size() == 0){
1108 std::string immediate_child_name;
1109 size_t name_pos = 0;
1112 if(immediate_child_name.size() == 0){
1114 throw SpartaException(
"Parameter ") << path
1115 <<
" is invalid because it contains an empty name (between two '.' "
1116 "characters). Parents cannot currently be refrenced in the parameter tree";
1119 return recursTryGet_(root_.get(), path,
1120 immediate_child_name, name_pos, must_be_leaf);
1123 template<
typename NodeT>
1124 static NodeT* recursTryGet_(NodeT* node,
const std::string& path,
1125 const std::string& match_name,
1126 size_t name_pos,
const bool must_be_leaf)
1129 "Cannot attempt to read a node with a path containing wildcard "
1130 "characters. A specific node path must be used. Error in \""
1131 << match_name <<
"\" from \"" << path <<
"\"");
1133 if(name_pos == std::string::npos){
1135 NodeT* result =
nullptr;
1136 NodeT* backup =
nullptr;
1137 auto itr = node->getMatcherBegin();
1138 for(; itr != node->getMatcherEnd(); ++itr){
1139 if(itr.matches(match_name)){
1140 if(itr.get()->hasValue() || !must_be_leaf){
1141 itr.get()->incrementReadCount();
1157 std::string immediate_child_name;
1160 if(immediate_child_name.size() == 0){
1162 throw SpartaException(
"Parameter ") << path
1163 <<
" is invalid because it contains an empty name (between two '.' "
1164 "characters). Parents cannot currently be refrenced in the parameter tree";
1167 NodeT* result =
nullptr;
1168 auto itr = node->getMatcherBegin();
1169 for(; itr != node->getMatcherEnd(); ++itr){
1170 if(itr.matches(match_name)){
1171 NodeT* match = recursTryGet_(itr.get(), path, immediate_child_name, name_pos, must_be_leaf);
1172 if(match && (match->hasValue() || !must_be_leaf)) {
1173 match->incrementReadCount();
1174 if(result ==
nullptr){
1187 bool recursGetIsRequired_(
const Node* node,
1188 const std::string& path,
1189 const std::string& match_name,
1191 bool& found_match)
const
1193 found_match =
false;
1195 if(name_pos == std::string::npos){
1197 auto itr = node->getMatcherBegin();
1198 for(; itr != node->getMatcherEnd(); ++itr){
1200 ? itr->getName() == match_name
1201 : itr.matches(match_name))
1204 return itr.get()->getRequiredCount() > 0;
1212 std::string immediate_child_name;
1215 if(immediate_child_name.size() == 0){
1217 throw SpartaException(
"Parameter ") << path
1218 <<
" is invalid because it contains an empty name (between two '.' "
1219 "characters). Parents cannot currently be refrenced in the parameter tree";
1222 auto itr = node->getMatcherBegin();
1223 for(; itr != node->getMatcherEnd(); ++itr){
1224 if(itr.matches(match_name)){
1225 const bool required = recursGetIsRequired_(itr.get(), path, immediate_child_name, name_pos, found_match);
1240 template<
class NodeT>
1241 static uint32_t recursCountUnreadValueNodes_(NodeT* n, std::vector<NodeT*> * nodes) {
1243 if(n->hasValue() && (n->getReadCount() == 0)){
1246 nodes->push_back(n);
1249 auto itr = n->getMatcherBegin();
1250 for(; itr != n->getMatcherEnd(); ++itr){
1251 count += recursCountUnreadValueNodes_<NodeT>(itr.get(), nodes);
1259 bool recursIsRead_(
const Node* node,
1260 const std::string& path,
1261 const std::string& match_name,
1262 size_t name_pos)
const
1265 "Cannot attempt to read a node with a path containing wildcard "
1266 "characters. A specific node path must be used. Error in \""
1267 << match_name <<
"\" from \"" << path <<
"\"");
1269 if(name_pos == std::string::npos){
1270 auto itr = node->getMatcherBegin();
1271 for(; itr != node->getMatcherEnd(); ++itr){
1272 if(itr.matches(match_name)){
1273 if(itr.get()->hasValue() && itr.get()->getReadCount() > 0){
1282 std::string immediate_child_name;
1284 if(immediate_child_name.size() == 0){
1286 throw SpartaException(
"Parameter ") << path
1287 <<
" is invalid because it contains an empty name (between two '.' "
1288 "characters). Parents cannot currently be refrenced in the parameter tree";
1291 auto itr = node->getMatcherBegin();
1292 for(; itr != node->getMatcherEnd(); ++itr){
1293 if(itr.matches(match_name)){
1294 bool read = recursIsRead_(itr.get(), path, immediate_child_name, name_pos);
1306 std::unique_ptr<Node> root_;
1310 inline std::ostream&
operator<<(std::ostream& o,
const ParameterTree::Node& n) {
1315 inline std::ostream&
operator<<(std::ostream& o,
const ParameterTree::Node* n) {
1317 o <<
"<null ParameterTree::Node>";
String-to-value helpers and string formatting helpers.
Individual Parameter interface base class, container class, and global helpers methods.
#define sparta_assert(...)
Simple variadic assertion that will throw a sparta_exception if the condition fails.
Basic Node framework in sparta device tree composite pattern.
Node containing a Parameter and value to apply. Can be used to describes a value extracted from the t...
const std::string & peekValue() const
Gets the value of this object as a string.
Node(Node *parent, const std::string &name)
Value-less constructor.
uint32_t getReadCount() const
Gets the number of times this node has been accessed to be read (i.e. with get/tryGet)
const std::string & getValue() const
Gets the value of this object as a string.
std::unique_ptr< Node > release()
Release this node and its children from the tree.
T getAs() const
Gets the value in this object.
Node * getPriorityChildMatch(const std::string &name) const
Attempts to get an immediate child with an exact match for a given name or pattern string....
std::string getPath() const
Gets the path to this node including the root node.
std::vector< std::unique_ptr< Node > > ChildVector
Vector of children owned by this node.
Node(Node *parent, ParameterTree *tree)
Root node constructor. Constructs node pointing to a new tree having no name. Normal nodes to not hav...
MatchIterator getMatcherBegin() const
Get most recent child added.
static bool matches(const std::string &pattern, const std::string &other)
Does a string, name, interpreted as a sparta TreeNode pattern, match another string interpreted as a ...
Node()=delete
Not default-constructable.
Node * getRoot()
Gets the parent of this node.
Node * addChild(const std::string &name, bool required)
void incrementReadCount() const
Increment the read count of this node.
bool operator==(const T &rhp) const
Equality test. Attempts to lexically cast underlying string to requested data-type.
bool isRoot() const
Is this a root node.
void recursePrint(std::ostream &o, uint32_t indent=0) const
Recursively print.
Node * create(const std::string &path, bool required)
Get a child for setting a parameter, creating it if needed.
Node & operator[](const std::string &name) const
Gets a child of this node by its name.
Node * getChild(const std::string &name) const
Gets the most recently created child of this node by a concrete child name.
const std::string & getAs() const
getAs template instance for string types (e.g. char[], const char*, std::string)
bool hasValue() const
Does this node have a value written to it which can be accessed through:
const std::string & getName() const
Gets the name of this node.
std::vector< const Node * > getChildren() const
Gets vector of pointers to children of this node.
void dump(std::ostream &o) const
Dumps the content of this node to an ostream on a single line. Does not recurs into children.
ParameterTree * getOwner()
Gets the ParameterTree object that owns this node.
Node const * getParent() const
Gets the parent of this node.
void incRequired()
Increment the required count.
bool isRequired() const
Return true if this parameter node is required to exist by the client by 1 or more "set"-ers using th...
std::vector< Node * > getChildren()
Gets vector of pointers to children of this node.
bool set(const std::string &path, const std::string &val, bool required, const std::string &origin="")
Set the string value of a child of this node. Note that this may not affect this node directly becaus...
void appendTree(const Node *ot)
Appends a tree as a child of this node.
const std::string & getOrigin() const
Gets the origin associated with the value at this node.
void setValue(const std::string &val, bool required=true, const std::string &origin="")
Set a value on this node directly.
Node * getParent()
Gets the parent of this node.
uint32_t getRequiredCount() const
Returns the number of times this node has been flagged as required.
Node const * getRoot() const
Gets the parent of this node.
MatchIterator getMatcherEnd() const
Get end of child match iterator (past oldest child added)
Node & operator=(const Node &n)
Parent-preserving deep-copy assignment operator.
void unrequire()
Clear the required count. This is necessary if a parameter is flagged as deprecated or removed in a c...
Node(Node *parent, const Node &n)
Deep-Copy constructor.
const ParameterTree * getOwner() const
Gets the ParameterTree object that owns this node.
Virtual Parameter Tree. This represents a tree of parameters read from some source but does not neces...
Node * create(const std::string &path, bool required=false)
Add a node to the tree, with proper priority.
bool set(const std::string &path, const std::string &value, bool required, const std::string &origin="")
Add a parameter to the tree, replacing any existing parameter.
const Node * tryGet(const std::string &path, const bool must_be_leaf=true) const
Try to get a node if it exists. Returns nullptr it it does not.
void recursePrint(std::ostream &o) const
Recursively print.
bool exists(const std::string &path, const bool must_be_leaf=true) const
Try to check if a node exists.
Node * tryGet(const std::string &path, const bool must_be_leaf=true)
tryGet non-const version
bool unrequire(const std::string &path)
Unrequire a node in the tree.
bool hasValue(const std::string &path, const bool must_be_leaf=true) const
Try to check if a node has value.
uint32_t getUnreadValueNodes(std::vector< Node * > *nodes)
Counts the number of values attached to the parameter tree which have values but have not been read....
virtual ~ParameterTree()
Destructor.
bool isRequired(const std::string &path) const
Recursively find first leaf node matching this pattern and decide if any node matching that node's pa...
ParameterTree()
Default Constructor.
void clear()
Clear all content from this tree.
uint32_t getUnreadValueNodes(std::vector< const Node * > *nodes) const
Counts the number of values attached to the parameter tree which have values but have not been read....
bool isRead(const std::string &path) const
Has a node with a given path been read.
const Node & operator[](const std::string &name) const
Gets a node form the parameter tree.
const Node & get(const std::string &path) const
Gets a node from the parameter tree while respecting parameter application order. In other words,...
void merge(const ParameterTree &rhp)
Merge this tree with another by applying all of its parameters to this tree. Parameters in the right ...
Used to construct and throw a standard C++ exception. Inherits from std::exception.
static std::string getNextName(const std::string &name, size_t &pos)
Gets the next name between two '.' chars in a string starting at pos.
static bool hasWildcardCharacters(const std::string &name)
Determines if a given node name has any wildcard characters which will be substituted in createSearch...
static std::string createSearchRegexPattern(const std::string &pat)
Compute a regex pattern for a node child path containing any number of wildcard characters (not a dot...
Macros for handling exponential backoff.
std::ostream & operator<<(std::ostream &o, const SimulationInfo &info)
ostream insertion operator for SimulationInfo