1 /** 2 * Base tree nodes 3 * 4 * Copyright: © 2017 Andrey Kabylin 5 * License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file. 6 */ 7 8 module rpdl.node; 9 10 import std.stdio; 11 import std.container; 12 import std.traits; 13 import std.conv; 14 import std.algorithm.iteration : filter; 15 16 import rpdl.value; 17 import rpdl.accessors; 18 import rpdl.exception; 19 20 import gl3n.linalg; 21 22 /// Base tree node class 23 class Node { 24 const bool isRoot; /// If true then node is the root 25 26 this(in string name, in bool isRoot = false) { 27 this.p_name = name; 28 this.p_path = name; 29 this.isRoot = isRoot; 30 } 31 32 this(in string name, Node parent) { 33 this.p_name = name; 34 this.isRoot = false; 35 parent.insert(this); 36 } 37 38 @property string name() { return p_name; } 39 40 /// Path of node relative to the root 41 @property string path() { return p_path; } 42 @property Node parent() { return p_parent; } 43 @property Array!Node children() { return p_children; } 44 @property size_t length() { return p_children.length; } 45 46 @property void name(in string value) { 47 p_name = value; 48 updatePath(); 49 } 50 51 /// Retrieve child node by the `index` 52 Node getAtIndex(in size_t index) { 53 return p_children[index]; 54 } 55 56 /// Insert node to the children 57 void insert(Node object) { 58 p_children ~= object; 59 object.p_parent = this; 60 object.updatePath(); 61 } 62 63 /// Find node relative to this node by the path 64 Node getNode(in string relativePath) { 65 return findNodeByPath(relativePath, this); 66 } 67 68 Node optNode(in string path, Node defaultVal = null) { 69 Node node = findNodeByPath(path, getRootNode()); 70 71 if (node is null) 72 return defaultVal; 73 74 return node; 75 } 76 77 mixin Accessors; 78 79 protected: 80 string p_name; 81 string p_path; // Key for find node 82 83 Node p_parent; 84 package Node inherit; 85 Array!Node p_children; 86 87 /// Update path relative to `root` 88 void updatePath() { 89 assert(parent !is null); 90 p_path = parent.path == "" ? name : parent.path ~ "." ~ name; 91 92 foreach (Node child; p_children) 93 child.updatePath(); 94 } 95 96 private: 97 Node getRootNode() { 98 return this; 99 } 100 101 /// Recursively find node relative to the `node` 102 Node findNodeByPath(in string relativePath, Node node) { 103 assert(node !is null); 104 const absolutePath = isRoot ? relativePath : path ~ "." ~ relativePath; 105 106 foreach_reverse (Node child; node.children) { 107 if (child.path == absolutePath) 108 return child; 109 110 Node findNode = findNodeByPath(relativePath, child); 111 112 if (findNode !is null) 113 return findNode; 114 } 115 116 if (node.inherit !is null) { 117 import std.stdio : writeln; 118 119 const relative = relativePath[node.name.length + 1 .. $]; 120 const inheritPath = node.inherit.name ~ "." ~ relative; 121 122 return findNodeByPath(inheritPath, node.inherit); 123 } 124 125 return null; 126 } 127 } 128 129 /// Represents parameter with the values in the object 130 class Parameter: Node { 131 this(in string name) { super(name); } 132 this(in string name, Node parent) { super(name, parent); } 133 } 134 135 /// Represents object with parameters and other objects 136 class ObjectNode: Node { 137 this(in string name) { super(name); } 138 this(in string name, Node parent) { super(name, parent); } 139 }