The Sparta Modeling Framework
Loading...
Searching...
No Matches
ParameterTree.hpp
1// <ParameterTree.hpp> -*- C++ -*-
2
3#pragma once
4
5#include <vector>
6#include <sstream>
7#include <regex>
8#include <memory>
9#include <string>
10
11#include "sparta/utils/Utils.hpp"
15
16namespace sparta
17{
38 {
39 public:
40
56 class Node
57 {
58 public:
59
63 typedef std::vector<std::unique_ptr<Node>> ChildVector;
64
65 private:
66
67 Node* parent_ = nullptr;
68 ParameterTree * tree_ = nullptr;
69 std::string name_;
70 std::string value_;
71 std::string origin_;
72 bool has_value_;
73 ChildVector children_;
74 uint32_t write_count_;
75 mutable uint32_t read_count_ = 0;
76
81 uint32_t required_ = 0;
82
83 public:
84
88 Node() = delete;
89
90 Node(Node* parent, const std::string& name,
91 const std::string& value, const std::string& origin) :
92 parent_(parent),
93 name_(name),
94 value_(value),
95 origin_(origin),
96 has_value_(true),
97 write_count_(1)
98 {;}
99
103 Node(Node* parent, const std::string& name) :
104 parent_(parent),
105 name_(name),
106 value_(),
107 has_value_(false),
108 write_count_(0)
109 {;}
110
116 Node(Node* parent, ParameterTree* tree) :
117 parent_(parent),
118 tree_(tree),
119 name_(""),
120 value_(),
121 has_value_(false),
122 write_count_(0)
123 {;}
124
129 Node(Node* parent, const Node& n) :
130 parent_(parent),
131 name_(n.name_),
132 value_(n.value_),
133 origin_(n.origin_),
134 has_value_(n.has_value_),
135 write_count_(n.write_count_),
136 read_count_(n.read_count_)
137 {
138 for(auto& x : n.children_){
139 children_.emplace_back(new Node(this, *x.get()));
140 }
141 }
142
149 Node& operator= (const Node& n) {
150 // preserve parent_
151 name_ = n.name_;
152 value_ = n.value_;
153 origin_ = n.origin_;
154 has_value_ = n.has_value_;
155 write_count_ = static_cast<decltype(write_count_)>(has_value_);
156 read_count_ = 0;
157 for(auto& x : n.children_){
158 children_.emplace_back(new Node(this, *x.get()));
159 }
160 return *this;
161 }
162
168 void dump(std::ostream& o) const {
169 o << "<VPT Node: \"" << name_ << "\" children:" << children_.size()
170 << " writes:" << write_count_ << " reads:" << read_count_ << " required:" << required_ << ">";
171 }
172
176 const std::string& getName() const { return name_; }
177
181 Node* getParent() { return parent_; }
182
186 Node const * getParent() const { return parent_; }
187
192 Node* p = this;
193 while(p->getParent() != nullptr){
194 p = p->getParent();
195 }
196 sparta_assert(p->getName().size() == 0);
197 return p;
198 }
199
203 Node const * getRoot() const {
204 Node const * p = this;
205 while(p->getParent() != nullptr){
206 p = p->getParent();
207 }
208 sparta_assert(p->getName().size() == 0);
209 return p;
210 }
211
216 return getRoot()->tree_;
217 }
218
222 const ParameterTree* getOwner() const {
223 return getRoot()->tree_;
224 }
225
229 std::string getPath() const {
230 std::stack<const std::string*> names;
231 Node const * n = this;
232 while(n && n->getName().size() > 0){ // Stop at null parent, or root (which has no name)
233 names.push(&n->getName());
234 n = n->getParent();
235 }
236
237 std::stringstream ss;
238 if(names.size() > 0){
239 ss << *names.top();
240 names.pop();
241 while(names.size() > 0){
242 ss << '.' << *names.top();
243 names.pop();
244 }
245 }
246 return ss.str();
247 }
248
252 bool isRoot() const {
253 return name_.size() == 0;
254 }
255
259 void incrementReadCount() const {
260 ++read_count_;
261 }
262
267 uint32_t getReadCount() const {
268 return read_count_;
269 }
270
276 const std::string& getValue() const {
277 sparta_assert(hasValue(), "Node \"" << name_ << "\" does not have a value associated with it");
279 return value_;
280 }
281
287 const std::string& peekValue() const {
288 sparta_assert(hasValue(), "Node \"" << name_ << "\" does not have a value associated with it");
289 return value_;
290 }
291
296 const std::string& getOrigin() const {
297 sparta_assert(hasValue(), "Node \"" << name_ << "\" does not have a value associated with it");
298 return origin_;
299 }
300
313 template <typename T, typename=typename std::enable_if<!std::is_convertible<T, std::string>::value>::type>
314 T getAs() const {
315 return lexicalCast<T>(getValue());
316 }
317
321 template <typename T, typename=typename std::enable_if<std::is_convertible<T, std::string>::value>::type>
322 const std::string& getAs() const {
323 return getValue();
324 }
325
329 operator std::string () const {
330 return value_;
331 }
332
337 template <typename T>
338 operator T () const {
339 return getAs<T>();
340 }
341
346 template <typename T>
347 bool operator==(const T& rhp) const {
348 return getAs<T>() == rhp;
349 }
350
360 static bool matches(const std::string& pattern, const std::string& other) {
361 std::regex expr(TreeNode::createSearchRegexPattern(pattern));
362 std::smatch what;
363 return std::regex_match(other, what, expr);
364 }
365
373 Node* getChild(const std::string& name) const {
375 throw SpartaException("Cannot call ParameterTree::Node::getChild with a name that is a search pattern: \"")
376 << name << "\". addChild must be used instead";
377 }
378
379 // Always search in reverse-applied order to match on most recent changes first
380 auto itr = children_.rbegin();
381 for(; itr != children_.rend(); ++itr){
382 if(matches((*itr)->getName(), name)){
383 return itr->get();
384 }
385 }
386
387 return nullptr;
388 }
389
400 Node* create(const std::string& path, bool required) {
401 if(path.size() == 0){
402 return this;
403 }
404
405 size_t name_pos = 0;
406 std::string immediate_child_name;
407 immediate_child_name = TreeNode::getNextName(path, name_pos);
408 if(immediate_child_name.size() == 0){
409 // Cannot get parent like this
410 return nullptr; // TEMPORARY behavior. See docstring
411 //throw SpartaException("Virtual parameter path \"") << path
412 // << "\" is invalid because it contains an empty name (between two '.' "
413 // "characters). Parents cannot currently be referenced in the virtual parameter tree";
414 }
415
416 // Get a child of node if one exists with an exact match before any nodes
417 // with wilcards are encountered. If this node name includes a wildcard, a
418 // child will be returned IFF it the pattern string itself matches with the
419 // highest priority child in this node.
420 Node* child = getPriorityChildMatch(immediate_child_name);
421 if(!child){
422 child = addChild(immediate_child_name, required);
423 }
424
425 if(name_pos == std::string::npos){
426 return child;
427 }
428
429 const std::string remainder = path.substr(name_pos);
430 return child->create(remainder, required);
431 }
432
441 Node* getPriorityChildMatch(const std::string& name) const {
442 if(children_.size() == 0){
443 return nullptr;
444 }
445
446 // Becase the name is a pattern, it is impossible to math against other existing
447 // children which are patterns. Therefore, if a pattern child is encountered
448 // which does not exactly match the given name string, nullptr must be returned so
449 // that the caller appends a new node, whih will have the highest priority
450 const bool name_has_wildcard = TreeNode::hasWildcardCharacters(name);
451
452 // Always search in reverse-applied order to match on most recent changes first.
453 //
454 // This is an optimization to prevent nodes from being created needlessly. It tries
455 // to find a matching node while considering wildcards to avoid creating new nodes
456 // in most cases where it is possible.
457 //
458 // Read the rules below to understand what happens. In general, if we don't get an
459 // exact string match with an existing node before hitting another node which is
460 // an exclusive superset or incomplete subset of the 'name' argument's pattern (it
461 // may have no wildcards) then a new node will need to be added at the end of the
462 // children list to specify a value. An existing node cannot be overridden.
463 auto itr = children_.rbegin();
464 for(; itr != children_.rend(); ++itr){
465 if((*itr)->getName() == name){
466 // Found a node with an exact name match (no pattern matching) before
467 // hitting a pattern node. This node can be used to apply a new parameter
468 return itr->get();
469 }
470
471 if(name_has_wildcard){
472 if(TreeNode::hasWildcardCharacters((*itr)->getName())){
473 // Encountered a wildcard node whch was not an exact string match.
474 // No way to tell if the name pattern exactly matches this node's, so
475 // assume it doesn't
476 return nullptr;
477 }else if(matches(name, (*itr)->getName())){
478 // Node has not wildcards but matches the pattern in 'name'. Therfore,
479 // A new parameter with this name would affect this node and more. A new
480 // node will have to be added to override it.
481 return nullptr;
482 }else{
483 // Node has no wildcards and the name agument is a pattern which
484 // does not match it. Therefore, it can be ignored because this 'name'
485 // will not apply
486 continue;
487 }
488 }else if(matches((*itr)->getName(), name)){
489 // Encountered a wildcard node which matches on this name before hitting an
490 // exact match. Therefore, a new node must be created by the caller so that
491 // the parameter being set will affect a subset of this node's pattern
492 return nullptr;
493 }
494 }
495 // No matches or important mismatches
496 return nullptr;
497 }
498
502 Node* addChild(const std::string& name, bool required) {
503 sparta_assert(hasValue() == false,
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));
507 if(required){
508 children_.back()->incRequired();
509 }
510 return (children_.back().get());
511 }
512
520 Node& operator[] (const std::string& name) const {
521 Node* child = getChild(name);
522 sparta_assert(child != nullptr,
523 "Node \"" << name_ << "\" has no child named \"" << name << "\"");
524 return *child;
525 }
526
527 Node& operator[] (const char* name) const {
528 return this->operator[](std::string(name));
529 }
530
538 bool hasValue() const {
539 return has_value_;
540 }
541
549 void setValue(const std::string& val, bool required=true, const std::string& origin="") {
550 //sparta_assert(parent_,
551 // "Cannot assign a value to the root node of a virtual parameter tree");
552 //sparta_assert(read_count_ == 0,
553 // "Cannot set(\"" << val << "\") on node \"" << name_ << "\" because it has been read already");
554 value_ = val;
555 origin_ = origin;
556 has_value_ = true;
557 write_count_++;
558 if(required){
559 required_ += 1;
560 }
561 }
562
566 void incRequired() {
567 required_ += 1;
568 }
569
574 void unrequire() {
575 required_ = 0;
576 for(auto & n : children_){
577 n->unrequire();
578 }
579 }
580
586 std::unique_ptr<Node> release() {
587 return parent_->release_(this);
588 }
589
603 bool set(const std::string& path, const std::string& val, bool required, const std::string& origin="") {
604 //sparta_assert(read_count_ == 0,
605 // "Cannot set(\"" << val << "\") on node \"" << name_
606 // << "\" because it has been read already");
607
608 // Set through root of the tree.
609 std::string full_path = getPath();
610 if(full_path.size() > 0 && path.size() > 0){
611 full_path += ".";
612 }
613 full_path += path;
614 return getOwner()->set(full_path, val, required, origin);
615 }
616
623 const std::string& operator= (const std::string& val) {
624 set("", val, true);
625 return val;
626 }
627
633 bool isRequired() const {
634 // Start at beginning. Another, later-written node may override
635 // this node if it has the same patch or a matching pattern.
636 if (getOwner()->isRequired(getPath()))
637 {
638 return true;
639 }
640 return false;
641 }
642
647 uint32_t getRequiredCount() const {
648 return required_;
649 }
650
654 std::vector<Node*> getChildren() {
655 std::vector<Node*> children;
656 for(auto & n : children_){
657 children.push_back(n.get());
658 }
659 return children;
660 }
661
665 std::vector<const Node*> getChildren() const {
666 std::vector<const Node*> children;
667 for(auto & n : children_){
668 children.push_back(n.get());
669 }
670 return children;
671 }
672
676 void recursePrint(std::ostream& o, uint32_t indent=0) const {
677 for(uint32_t i=0; i<indent; ++i){
678 o << " ";
679 }
680 o << name_;
681 if(has_value_){
682 o << " = \"" << value_ << "\" (read " << read_count_ << ", written " << write_count_
683 << ", required " << required_ << ", origin '" << getOrigin() << "')";
684 }
685 o << "\n";
686 for(auto & n : children_){
687 n->recursePrint(o, indent+2);
688 }
689 }
690
703 void appendTree(const Node* ot) {
704 sparta_assert(ot, "Cannot append a null virtual parameter tree");
705 if(ot->getName().size() > 0){
706 // Attach 'ot' node argument as child of this
707 const bool required = false; // The starting node is not required to exist.. only its node children
708 Node* child = create(ot->getName(), required);
709 child->recursAppendTree_(ot);
710 }else{
711 // 'ot' is a root node (no name). Merge it with this.
712 recursAppendTree_(ot);
713 }
714 }
715
721 ChildVector::const_reverse_iterator itr_;
722 public:
723 MatchIterator(ChildVector::const_reverse_iterator itr) :
724 itr_(itr)
725 {;}
726
727 MatchIterator(const MatchIterator&) = default;
728
729 MatchIterator& operator=(const MatchIterator&) = default;
730
731 bool operator==(const MatchIterator& rhp) const {
732 return itr_ == rhp.itr_;
733 }
734
735 bool operator!=(const MatchIterator& rhp) const {
736 return itr_ != rhp.itr_;
737 }
738
739 void operator++(int) {++itr_;}
740
741 void operator++() {++itr_;}
742
743 bool matches(const std::string& other) const {
744 return ParameterTree::Node::matches((*itr_)->getName(), other);
745 }
746
747 const Node* get() const {
748 return itr_->get();
749 }
750
751 Node* get() {
752 return itr_->get();
753 }
754
755 const Node* operator->() const {
756 return itr_->get();
757 }
758 };
759
760 friend class MatchIterator;
761
765 MatchIterator getMatcherBegin() const { return MatchIterator(children_.rbegin()); }
766
770 MatchIterator getMatcherEnd() const { return MatchIterator(children_.rend()); }
771
772 private:
773
779 void recursAppendTree_(const Node* ot) {
780 // Inherit value. Never invalidate
781 if(ot->hasValue()){
782 setValue(ot->peekValue(), ot->getRequiredCount() > 0, ot->getOrigin());
783 }
784
785 for(auto & child : ot->getChildren()){
786 // TODO: copy required count instead of just boolean
787 Node* c = create(child->getName(), child->getRequiredCount() > 0); // Create if needed
788 c->recursAppendTree_(child);
789 }
790 }
791
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);
797 });
798 if (it != children_.end()) {
799 rtn = std::move(*it);
800 children_.erase(it);
801 }
802 return rtn;
803 }
804 };
805
810 root_(new Node(nullptr, this))
811 {;}
812
813 ParameterTree(const ParameterTree& rhp) :
814 root_(new Node(nullptr, this))
815 {
816 root_->appendTree(rhp.getRoot());
817 }
818
819 ParameterTree& operator=(const ParameterTree& rhp) {
820 clear();
821 merge(rhp);
822 return *this;
823 }
824
825 //bool operator==(const ParameterTree& rhp) const {
826 //}
827
831 virtual ~ParameterTree() {}
832
836 void clear() {
837 root_.reset(new Node(nullptr, this)); // Clear all children
838 }
839
854 bool set(const std::string& path, const std::string& value, bool required, const std::string& origin="") {
855 Node* n = create(path, false); // inc required after setting value
856 if(!n){
857 return false;
858 }
859 n->setValue(value, required, origin);
860
861 return true;
862 }
863
878 Node* create(const std::string& path, bool required=false) {
879 if(path.size() == 0){
880 return getRoot();
881 }
882
883 return getRoot()->create(path, required);
884 }
885
897 const Node& get(const std::string& path) const {
898 const Node* node = tryGet(path);
899 if(!node){
900 throw SpartaException("Unable to find parameter in tree: \"") << path << "\"";
901 }
902 return *node;
903 }
904
909 const Node& operator[] (const std::string& name) const {
910 return get(name);
911 }
912
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();
922 }
923
930 bool exists(const std::string& path, const bool must_be_leaf = true) const {
931 return tryGet_(path, must_be_leaf) != nullptr;
932 }
933
945 uint32_t getUnreadValueNodes(std::vector<const Node*>* nodes) const {
946 return recursCountUnreadValueNodes_<const Node>(root_.get(), nodes);
947 }
948
960 uint32_t getUnreadValueNodes(std::vector<Node*>* nodes) {
961 return recursCountUnreadValueNodes_<Node>(root_.get(), nodes);
962 }
963
969 const Node* tryGet(const std::string& path, const bool must_be_leaf = true) const {
970 return tryGet_(path, must_be_leaf);
971 }
972
978 Node* tryGet(const std::string& path, const bool must_be_leaf = true) {
979 return tryGet_(path, must_be_leaf);
980 }
981
987 bool isRequired(const std::string& path) const {
988
989 if(path.size() == 0){
990 return root_->getRequiredCount() > 0;
991 }
992
993 std::string immediate_child_name;
994 size_t name_pos = 0;
995 immediate_child_name = TreeNode::getNextName(path, name_pos);
996
997 if(immediate_child_name.size() == 0){
998 // Cannot get parent.
999 throw SpartaException("Parameter ") << path
1000 << " is invalid because it contains an empty name (between two '.' "
1001 "characters). Parents cannot currently be refrenced in the parameter tree";
1002 }
1003
1004 bool match_found = false;
1005 const bool required = recursGetIsRequired_(root_.get(), path, immediate_child_name, name_pos, match_found);
1006 sparta_assert(match_found,
1007 "Asked ParameterTree if path \"" << path << "\" is required but no "
1008 "matching node was found in the ParameterTree");
1009 return required;
1010 }
1011
1017 bool unrequire(const std::string &path) {
1018 Node * node = tryGet_(path, false);
1019 if(nullptr != node) {
1020 node->unrequire();
1021 return true;
1022 }
1023 return false;
1024 }
1025
1034 bool isRead(const std::string& path) const {
1035 if(path.size() == 0){
1036 return root_->hasValue() && root_->getReadCount() > 0;
1037 }
1038
1039 std::string immediate_child_name;
1040 size_t name_pos = 0;
1041 immediate_child_name = TreeNode::getNextName(path, name_pos);
1042
1043 if(immediate_child_name.size() == 0){
1044 // Cannot get parent.
1045 throw SpartaException("Parameter ") << path
1046 << " is invalid because it contains an empty name (between two '.' "
1047 "characters). Parents cannot currently be refrenced in the parameter tree";
1048 }
1049
1050 return recursIsRead_(root_.get(), path, immediate_child_name, name_pos);
1051 }
1052
1053 Node const * getRoot() const { return root_.get(); }
1054
1055 Node * getRoot() { return root_.get(); }
1056
1062 void merge(const ParameterTree& rhp) {
1063 root_->appendTree(rhp.getRoot());
1064 }
1065
1069 void recursePrint(std::ostream& o) const {
1070 root_->recursePrint(o, 0); // Begin with 0 indent
1071 }
1072
1073 private:
1074
1079 const Node* tryGet_(const std::string& path, const bool must_be_leaf = true) const {
1080 if(path.size() == 0){
1081 return root_.get();
1082 }
1083
1084 std::string immediate_child_name;
1085 size_t name_pos = 0;
1086 immediate_child_name = TreeNode::getNextName(path, name_pos);
1087
1088 if(immediate_child_name.size() == 0){
1089 // Cannot get parent.
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";
1093 }
1094
1095 return recursTryGet_<const Node>(static_cast<const Node*>(root_.get()), path,
1096 immediate_child_name, name_pos, must_be_leaf);
1097 }
1098
1103 Node* tryGet_(const std::string& path, const bool must_be_leaf = true) {
1104 if(path.size() == 0){
1105 return root_.get();
1106 }
1107
1108 std::string immediate_child_name;
1109 size_t name_pos = 0;
1110 immediate_child_name = TreeNode::getNextName(path, name_pos);
1111
1112 if(immediate_child_name.size() == 0){
1113 // Cannot get parent.
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";
1117 }
1118
1119 return recursTryGet_(root_.get(), path,
1120 immediate_child_name, name_pos, must_be_leaf);
1121 }
1122
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)
1127 {
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 << "\"");
1132
1133 if(name_pos == std::string::npos){
1134 // End of the search.. No deeper
1135 NodeT* result = nullptr;
1136 NodeT* backup = nullptr; // First match (if is has no value)
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();
1142 if(!result){
1143 result = itr.get(); // Found it
1144 }
1145 }else if(!backup){
1146 backup = itr.get();
1147 }
1148 }
1149 }
1150 if(result){
1151 return result;
1152 }
1153 return backup; // No match here
1154 }
1155
1156 // Search deeper
1157 std::string immediate_child_name;
1158 immediate_child_name = TreeNode::getNextName(path, name_pos);
1159
1160 if(immediate_child_name.size() == 0){
1161 // Cannot get parent.
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";
1165 }
1166
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){
1175 result = match;
1176 }
1177 }
1178 // Keep this match as result and continue iterating to mark all matching nodes as read
1179 }
1180 }
1181 return result;
1182 }
1183
1187 bool recursGetIsRequired_(const Node* node,
1188 const std::string& path,
1189 const std::string& match_name,
1190 size_t name_pos,
1191 bool& found_match) const
1192 {
1193 found_match = false;
1194
1195 if(name_pos == std::string::npos){
1196 // End of the search.. No deeper
1197 auto itr = node->getMatcherBegin();
1198 for(; itr != node->getMatcherEnd(); ++itr){
1199 if(TreeNode::hasWildcardCharacters(match_name)
1200 ? itr->getName() == match_name // Exact name match if match_name has wildcards
1201 : itr.matches(match_name)) // Pattern match if match_name has no wildcards
1202 {
1203 found_match = true;
1204 return itr.get()->getRequiredCount() > 0;
1205 }
1206 }
1207
1208 return false; // dummy
1209 }
1210
1211 // Search deeper
1212 std::string immediate_child_name;
1213 immediate_child_name = TreeNode::getNextName(path, name_pos);
1214
1215 if(immediate_child_name.size() == 0){
1216 // Cannot get parent.
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";
1220 }
1221
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);
1226 if(found_match){
1227 return required;
1228 }
1229 // No match found. Keep going
1230 }
1231 }
1232
1233 sparta_assert(found_match == false); // Should not have been set
1234 return false; // dummy
1235 }
1236
1240 template<class NodeT>
1241 static uint32_t recursCountUnreadValueNodes_(NodeT* n, std::vector<NodeT*> * nodes) {
1242 uint32_t count = 0;
1243 if(n->hasValue() && (n->getReadCount() == 0)){
1244 count = 1;
1245 if(nodes){
1246 nodes->push_back(n);
1247 }
1248 }
1249 auto itr = n->getMatcherBegin();
1250 for(; itr != n->getMatcherEnd(); ++itr){
1251 count += recursCountUnreadValueNodes_<NodeT>(itr.get(), nodes);
1252 }
1253 return count;
1254 }
1255
1259 bool recursIsRead_(const Node* node,
1260 const std::string& path,
1261 const std::string& match_name,
1262 size_t name_pos) const
1263 {
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 << "\"");
1268
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){
1274 return true;
1275 }
1276 }
1277 }
1278 return false;
1279 }
1280
1281 // Search deeper
1282 std::string immediate_child_name;
1283 immediate_child_name = TreeNode::getNextName(path, name_pos);
1284 if(immediate_child_name.size() == 0){
1285 // Cannot get parent.
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";
1289 }
1290
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);
1295 if(read){
1296 return true;
1297 }
1298 }
1299 }
1300 return false;
1301 }
1302
1306 std::unique_ptr<Node> root_;
1307
1308 }; // class ParameterSet
1309
1310 inline std::ostream& operator<<(std::ostream& o, const ParameterTree::Node& n) {
1311 n.dump(o);
1312 return o;
1313 }
1314
1315 inline std::ostream& operator<<(std::ostream& o, const ParameterTree::Node* n) {
1316 if(!n){
1317 o << "<null ParameterTree::Node>";
1318 }else{
1319 o << *n;
1320 }
1321 return o;
1322 }
1323
1324} // namespace sparta
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