/// <summary> /// Traverse the prefix tree /// </summary> internal bool MoveNext() { if (null != this.segment) { int segmentLength = this.segment.Length; this.offset += segmentLength; this.length -= segmentLength; if (this.length > 0) { this.segmentIndex = this.segment.GetChildPosition(this.prefix, this.offset, this.length); if (this.segmentIndex > -1) { this.segment = this.segment.GetChild(this.segmentIndex); return(true); } } else { this.segmentIndex = -1; } this.segment = null; } else if (null != this.rootSegment) { this.segment = this.rootSegment; this.rootSegment = null; return(true); } return(false); }
void EnsureRoot() { if (null == this.root) { this.root = new TrieSegment(); } }
internal void Remove(string segment) { Fx.Assert(null != segment, ""); TrieSegment trieSegment = this[segment]; if (null == trieSegment) { return; } if (trieSegment.HasChildren) { trieSegment.Data = null; return; } if (trieSegment == this.root) { // Remove the entire tree! this.root = null; this.hasDescendants = false; return; } trieSegment.Remove(); this.PruneRoot(); }
void PruneRoot() { if (null != this.root && this.root.CanPrune) { this.root = null; } }
private void EnsureRoot() { if (this.root == null) { this.root = new TrieSegment(); } }
private void PruneRoot() { if ((this.root != null) && this.root.CanPrune) { this.root = null; } }
internal bool MoveNext() { if (this.segment != null) { int length = this.segment.Length; this.offset += length; this.length -= length; if (this.length > 0) { this.segmentIndex = this.segment.GetChildPosition(this.prefix, this.offset, this.length); if (this.segmentIndex > -1) { this.segment = this.segment.GetChild(this.segmentIndex); return true; } } else { this.segmentIndex = -1; } this.segment = null; } else if (this.rootSegment != null) { this.segment = this.rootSegment; this.rootSegment = null; return true; } return false; }
TrieSegment Find(string prefix) { Fx.Assert(null != prefix, ""); if (0 == prefix.Length) { return(this.Root); } if (!this.HasDescendants) { return(null); } TrieTraverser traverser = new TrieTraverser(this.root, prefix); // struct TrieSegment foundSegment = null; while (traverser.MoveNext()) { foundSegment = traverser.Segment; } if (traverser.Length > 0) { // We haven't used up the entire prefix in this search. Clearly, we didn't find the matching node return(null); } return(foundSegment); }
internal bool MoveNextByFirstChar() { if (this.segment != null) { int length = this.segment.Length; this.offset += length; this.length -= length; if (this.length > 0) { this.segmentIndex = this.segment.GetChildPosition(this.prefix[this.offset]); if (this.segmentIndex > -1) { this.segment = this.segment.GetChild(this.segmentIndex); return(true); } } else { this.segmentIndex = -1; } this.segment = null; } else if (this.rootSegment != null) { this.segment = this.rootSegment; this.rootSegment = null; return(true); } return(false); }
internal TrieTraverser(TrieSegment root, string prefix) { this.prefix = prefix; this.rootSegment = root; this.segment = null; this.segmentIndex = -1; this.offset = 0; this.length = prefix.Length; }
private void RemoveChild(TrieSegment segment) { int index = this.IndexOf(segment); if (index >= 0) { this.RemoveChild(index, true); } }
internal void MergeChild(TrieSegment segment) { int index = this.IndexOf(segment); if (index > -1) { this.MergeChild(index); } }
internal TrieSegment AddChild(TrieSegment segment) { Fx.Assert(null != segment, ""); this.children.Insert(segment); segment.parent = this; return(segment); }
/// <summary> /// Remove the child == segment, and prune the tree /// </summary> void RemoveChild(TrieSegment segment) { Fx.Assert(null != segment, ""); int childIndex = this.IndexOf(segment); if (childIndex >= 0) { this.RemoveChild(childIndex, true); } }
internal TrieSegment SplitChild(int childIndex, int charIndex) { TrieSegment item = this.children[childIndex]; this.children.Remove(item); TrieSegment segment2 = item.SplitAt(charIndex); this.children.Insert(segment2); segment2.parent = this; return(segment2); }
internal TrieSegment SplitChild(int childIndex, int charIndex) { Fx.Assert(this.HasChildren, ""); TrieSegment child = this.children[childIndex]; this.children.Remove(child); TrieSegment newChild = child.SplitAt(charIndex); this.children.Insert(newChild); newChild.parent = this; return(newChild); }
private TrieSegment SplitAt(int charIndex) { TrieSegment segment; if (1 == charIndex) { segment = new TrieSegment(this.segmentFirstChar); } else { segment = new TrieSegment(this.segmentFirstChar, this.segmentTail.Substring(0, charIndex - 1)); } charIndex--; this.SetSegmentString(this.segmentTail, charIndex, this.segmentTail.Length - charIndex); segment.AddChild(this); return(segment); }
internal void MergeChild(int childIndex) { TrieSegment old = this.children[childIndex]; if (old.CanMerge) { TrieSegment replace = old.children[0]; StringBuilder builder = new StringBuilder(); builder.Append(old.segmentTail); builder.Append(replace.segmentFirstChar); builder.Append(replace.segmentTail); replace.SetSegment(old.segmentFirstChar, builder.ToString()); replace.parent = this; this.children.Exchange(old, replace); old.parent = null; } }
internal override QueryBranch this[object key] { get { TrieSegment segment = this.trie[(string)key]; if (segment != null) { return(segment.Data); } return(null); } set { TrieSegment segment = this.trie.Add((string)key); this.count++; segment.Data = value; } }
internal void RemoveChild(int childIndex, bool fixupTree) { TrieSegment segment = this.children[childIndex]; segment.parent = null; this.children.RemoveAt(childIndex); if (this.children.Count == 0) { if (fixupTree && this.CanPrune) { this.Remove(); } } else if ((fixupTree && this.CanMerge) && (this.parent != null)) { this.parent.MergeChild(this); } }
internal int GetChildPosition(string matchString, int offset, int length) { if (this.HasChildren) { char key = matchString[offset]; int num = length - 1; int indexA = offset + 1; int num3 = this.children.IndexOfKey <char>(key, SegKeyComparer); if (num3 >= 0) { TrieSegment segment = this.children[num3]; if ((num >= segment.segmentTail.Length) && ((segment.segmentTail.Length == 0) || (string.CompareOrdinal(matchString, indexA, segment.segmentTail, 0, segment.segmentTail.Length) == 0))) { return(num3); } } } return(-1); }
internal override QueryBranch this[object key] { get { TrieSegment segment = this.trie[(string)key]; if (null != segment) { return(segment.Data); } return(null); } set { Fx.Assert(null != key, ""); TrieSegment segment = this.trie.Add((string)key); Fx.Assert(null != segment, ""); this.count++; segment.Data = value; } }
TrieSegment SplitAt(int charIndex) { Fx.Assert(charIndex > 0, ""); TrieSegment newSegment; if (1 == charIndex) { newSegment = new TrieSegment(this.segmentFirstChar); } else { Fx.Assert(this.segmentTail.Length > 0, ""); newSegment = new TrieSegment(this.segmentFirstChar, this.segmentTail.Substring(0, charIndex - 1)); } --charIndex; this.SetSegmentString(this.segmentTail, charIndex, this.segmentTail.Length - charIndex); newSegment.AddChild(this); return(newSegment); }
/// <summary> /// Return the index of the child such that matchString == the string segment stored at that child /// i.e. matchString[0] == child.segmentFirstChar and matchString[1 -> length] == child.segmentTail[0 -> length] /// </summary> internal int GetChildPosition(string matchString, int offset, int length) { Fx.Assert(null != matchString, ""); if (this.HasChildren) { char matchChar = matchString[offset]; int tailLength = length - 1; int tailOffset = offset + 1; int index = this.children.IndexOfKey(matchChar, SegKeyComparer); if (index >= 0) { TrieSegment child = this.children[index]; if (tailLength >= child.segmentTail.Length && (0 == child.segmentTail.Length || 0 == string.CompareOrdinal(matchString, tailOffset, child.segmentTail, 0, child.segmentTail.Length))) { return(index); } } } return(-1); }
/// <summary> /// If the child node has no data associated with it and but one child of its own, it can be /// merged with the child, reducing the path by 1 /// </summary> internal void MergeChild(int childIndex) { Fx.Assert(this.HasChildren, ""); TrieSegment child = this.children[childIndex]; if (child.CanMerge) { TrieSegment grandchild = child.children[0]; StringBuilder newTail = new StringBuilder(); newTail.Append(child.segmentTail); newTail.Append(grandchild.segmentFirstChar); newTail.Append(grandchild.segmentTail); grandchild.SetSegment(child.segmentFirstChar, newTail.ToString()); grandchild.parent = this; this.children.Exchange(child, grandchild); child.parent = null; } }
internal void Remove(string segment) { TrieSegment segment2 = this[segment]; if (segment2 != null) { if (segment2.HasChildren) { segment2.Data = null; } else if (segment2 == this.root) { this.root = null; this.hasDescendants = false; } else { segment2.Remove(); this.PruneRoot(); } } }
private TrieSegment Find(string prefix) { if (prefix.Length == 0) { return(this.Root); } if (!this.HasDescendants) { return(null); } TrieTraverser traverser = new TrieTraverser(this.root, prefix); TrieSegment segment = null; while (traverser.MoveNext()) { segment = traverser.Segment; } if (traverser.Length > 0) { return(null); } return(segment); }
/// <summary> /// Remove the child at index childIndex. /// If fixupTree is true, traverse back up the tree, removing prunable nodes or merging mergable nodes /// as appropriate /// </summary> internal void RemoveChild(int childIndex, bool fixupTree) { Fx.Assert(this.HasChildren && childIndex >= 0, ""); TrieSegment child = this.children[childIndex]; child.parent = null; this.children.RemoveAt(childIndex); if (0 == this.children.Count) { if (fixupTree && this.CanPrune) { this.Remove(); } } else { if (fixupTree && this.CanMerge && null != this.parent) { this.parent.MergeChild(this); } } }
private TrieSegment SplitAt(int charIndex) { TrieSegment segment; if (1 == charIndex) { segment = new TrieSegment(this.segmentFirstChar); } else { segment = new TrieSegment(this.segmentFirstChar, this.segmentTail.Substring(0, charIndex - 1)); } charIndex--; this.SetSegmentString(this.segmentTail, charIndex, this.segmentTail.Length - charIndex); segment.AddChild(this); return segment; }
internal TrieSegment AddChild(TrieSegment segment) { this.children.Insert(segment); segment.parent = this; return(segment); }
internal int IndexOf(TrieSegment segment) { return(this.children.IndexOf(segment)); }
internal TrieSegment AddChild(TrieSegment segment) { this.children.Insert(segment); segment.parent = this; return segment; }
internal int IndexOf(TrieSegment segment) { return this.children.IndexOf(segment); }