/// <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);
        }
Beispiel #9
0
 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);
            }
        }
Beispiel #12
0
 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;
 }
        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;
 }
 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 int IndexOf(TrieSegment segment)
 {
     return this.children.IndexOf(segment);
 }