4 using System.Collections.Generic;
9 public class Trees : IDisposable {
10 #region Private Functionality 12 internal class Node : IDisposable {
15 internal struct LeafNode : IDisposable {
20 internal struct BranchNode : IDisposable {
27 private LeafNode leafNode;
28 private BranchNode branchNode;
30 internal object Leaf {
get => leafNode.Value;
set => leafNode.Value = value; }
31 internal Map Branch => branchNode.Value ?? (branchNode.Value =
new Map());
33 public static Node New(
object name, Node parent) {
35 node.Name = name.ToString();
40 public int Count => branchNode.Value == null ? 0 : Branch.
Count;
45 leafNode =
new LeafNode();
46 branchNode =
new BranchNode();
54 private readonly Node root;
57 private double floatingPoint;
60 private struct Anchors : IDisposable {
64 public void Dispose() => Tree.here = Stack.
Pop();
69 private readonly Anchors anchors;
72 root = here = Node.New(
"~ROOT~", null);
73 anchors =
new Anchors {Stack =
new LinkedList<Node>(
"Trees Anchor Stack"), Tree =
this};
76 private Trees Walk(
bool create,
string path) {
79 var split = path.Split(
'.');
81 for (var i = 0; i < split.Length; i++) {
82 string key = split[i];
83 if (here == null)
return Failure();
85 if (here.Branch[key].Found) {
86 here = here.Branch.Value as Node;
88 if (
string.IsNullOrWhiteSpace(key)) {
89 here = i == 0 ? here : here.Parent;
91 here = (Node) here.Branch.Add(key, Node.New(key, here)).
Value;
101 private Trees Failure() {
107 #region Public Interface 127 public Trees To(
string path) =>
Root().Walk(create:
false, path: path);
131 public Trees Next(
string path) => Walk(create:
false, path: path);
135 public Trees Add(
string path) => Walk(create:
true, path: path);
138 public string Name => here?.Name;
149 public string Value {
get => here?.Leaf?.ToString();
set => here.Leaf = value; }
154 if (isNumber != -1)
return isNumber != 0;
158 if (
long.TryParse(word, out integer)) { floatingPoint = integer; }
else if (
double.TryParse(
159 word, out floatingPoint)) { integer = (long) floatingPoint; }
else {
161 return (isNumber = 0) == 1;
165 return (isNumber = 1) == 1;
182 public object this[
object key] {
183 get => (here.Branch[key].Value as Node)?.
Leaf;
184 set => ((Node) here.Branch[key].Value).Leaf = value;
198 var parent = here.Parent;
199 string key = here.Name;
201 here = parent ?? root;
202 here.Branch.Remove(key);
206 public IDisposable
Anchor(
string path =
"") {
207 anchors.Stack.Push(here);
218 if (here == null)
return "No Path";
221 for (var there = here; there.Parent != null; there = there.Parent) tsPath.Add(there.Name);
223 return string.Join(separator:
".", values: tsPath);
227 private readonly List<string> tsPath =
new List<string>();
Trees Root()
Set here to root
bool IsNull
The leaf here is a null reference
int Count
Number of entries in the map
T Pop()
Retrieve the first list item - Node.Recycle
long Long
Long value of the leaf here
static Action< Node > DeactivateItemStatic
Called before an item is returned to recycling
double Double
Double value of the leaf here
Trees To(string path)
Walk the path, failing if a branch or leaf is unavailable
string Value
Leaf value here (null if last walk failed)
bool Boolean
Boolean value of the leaf here
object FirstChild
First branch under here
object [] Children
List of strings being the names of keys for branches under here
string Name
Name of node here
bool IsRoot
Set if here is root
void Dispose()
Dispose of the branch node here
static Trees Instance
Fetch a cached Trees instance
string Key
The path to here as a string
override string ToString()
object NextChild
Second branch under here
IDisposable Anchor(string path="")
Mark here so wec an return to it
Trees Next(string path)
See To
bool Failed
Set if last search did not succeed
Trees Add(string path)
Walk the path creating new segments as needed