| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884 |
- //------------------------------------------------------------
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //------------------------------------------------------------
- namespace System.ServiceModel.Dispatcher
- {
- using System.Collections.Generic;
- using System.Runtime;
- using System.Text;
- internal class TrieSegmentComparer : IComparer<TrieSegment>
- {
- public int Compare(TrieSegment t1, TrieSegment t2)
- {
- return ((int)t1.FirstChar) - ((int)t2.FirstChar);
- }
- public bool Equals(TrieSegment t1, TrieSegment t2)
- {
- return t1.FirstChar == t2.FirstChar;
- }
- public int GetHashCode(TrieSegment t)
- {
- return t.GetHashCode();
- }
- }
- internal class TrieSegmentKeyComparer : IItemComparer<char, TrieSegment>
- {
- public int Compare(char c, TrieSegment t)
- {
- return ((int)c) - ((int)t.FirstChar);
- }
- }
- internal class TrieSegment
- {
- static readonly TrieSegmentKeyComparer SegKeyComparer = new TrieSegmentKeyComparer();
- static readonly TrieSegmentComparer SegComparer = new TrieSegmentComparer();
- SortedBuffer<TrieSegment, TrieSegmentComparer> children;
- QueryBranch data;
- TrieSegment parent; // segment's parent
- char segmentFirstChar; // this segment's first character
- string segmentTail; // this segment's tail
- int segmentLength;
- internal TrieSegment()
- : this(char.MinValue)
- {
- }
- internal TrieSegment(char firstChar)
- : this(firstChar, string.Empty)
- {
- }
- internal TrieSegment(char firstChar, string segmentTail)
- {
- Fx.Assert(null != segmentTail, "");
- this.SetSegment(firstChar, segmentTail);
- this.children = new SortedBuffer<TrieSegment, TrieSegmentComparer>(SegComparer);
- }
- internal TrieSegment(string sourceSegment, int offset, int length)
- {
- Fx.Assert(null != sourceSegment && length > 0, "");
- this.SetSegmentString(sourceSegment, offset, length);
- this.children = new SortedBuffer<TrieSegment, TrieSegmentComparer>(SegComparer);
- }
- internal bool CanMerge
- {
- get
- {
- return (null == this.data && 1 == this.children.Count);
- }
- }
- internal bool CanPrune
- {
- get
- {
- return (null == this.data && 0 == this.children.Count);
- }
- }
- #if NO
- internal int ChildCount
- {
- get
- {
- return this.children.Count;
- }
- }
- #endif
- internal void CollectXPathFilters(ICollection<MessageFilter> filters)
- {
- if (this.data != null)
- {
- (this.data).Branch.CollectXPathFilters(filters);
- }
- for (int i = 0; i < this.children.Count; ++i)
- {
- this.children[i].CollectXPathFilters(filters);
- }
- }
- internal QueryBranch Data
- {
- get
- {
- return this.data;
- }
- set
- {
- this.data = value;
- }
- }
- internal char FirstChar
- {
- get
- {
- return this.segmentFirstChar;
- }
- }
- internal bool HasChildren
- {
- get
- {
- return (this.children.Count > 0);
- }
- }
- internal int Length
- {
- get
- {
- //return (this.segmentFirstChar == char.MinValue) ? 0 : this.segmentTail.Length + 1;
- return this.segmentLength;
- }
- }
- #if NO
- internal string Tail
- {
- get
- {
- return this.segmentTail;
- }
- }
- #endif
- internal TrieSegment AddChild(TrieSegment segment)
- {
- Fx.Assert(null != segment, "");
- this.children.Insert(segment);
- segment.parent = this;
- return segment;
- }
- #if NO
- internal TrieSegment[] CopyChildren()
- {
- return this.children.ToArray();
- }
- #endif
- internal int FindDivergence(string compareString, int offset, int length)
- {
- Fx.Assert(null != compareString && length > 0, "");
- if (compareString[offset] != this.segmentFirstChar)
- {
- return 0;
- }
- --length;
- ++offset;
- int charCount = (length <= this.segmentTail.Length) ? length : this.segmentTail.Length;
- for (int iSegment = 0, iCompare = offset; iSegment < charCount; ++iSegment, ++iCompare)
- {
- if (compareString[iCompare] != this.segmentTail[iSegment])
- {
- return iSegment + 1;
- }
- }
- if (length < this.segmentTail.Length)
- {
- return length + 1;
- }
- return -1;
- }
- internal TrieSegment GetChild(int index)
- {
- Fx.Assert(this.HasChildren, "");
- return this.children[index];
- }
- /// <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>
- /// Return the index of the child such that child.segmentFirstChar == ch
- /// </summary>
- internal int GetChildPosition(char ch)
- {
- return this.children.IndexOfKey(ch, SegKeyComparer);
- }
- internal int IndexOf(TrieSegment segment)
- {
- return this.children.IndexOf(segment);
- }
- internal void MergeChild(TrieSegment segment)
- {
- int childIndex = this.IndexOf(segment);
- if (childIndex > -1)
- {
- this.MergeChild(childIndex);
- }
- }
- /// <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()
- {
- if (null != this.parent)
- {
- this.parent.RemoveChild(this);
- }
- }
- /// <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);
- }
- }
- /// <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);
- }
- }
- }
- void SetSegment(char firstChar, string segmentTail)
- {
- this.segmentFirstChar = firstChar;
- this.segmentTail = segmentTail;
- this.segmentLength = firstChar == char.MinValue ? 0 : 1 + segmentTail.Length;
- }
- void SetSegmentString(string segmentString, int offset, int length)
- {
- this.segmentFirstChar = segmentString[offset];
- if (length > 1)
- {
- this.segmentTail = segmentString.Substring(offset + 1, length - 1);
- }
- else
- {
- this.segmentTail = string.Empty;
- }
- this.segmentLength = length;
- }
- 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;
- }
- 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;
- }
- internal void Trim()
- {
- this.children.Trim();
- for (int i = 0; i < this.children.Count; ++i)
- {
- this.children[i].Trim();
- }
- }
- }
- internal struct TrieTraverser
- {
- int length;
- int offset;
- string prefix;
- TrieSegment rootSegment;
- TrieSegment segment;
- int segmentIndex;
- internal TrieTraverser(TrieSegment root, string prefix)
- {
- Fx.Assert(null != root && null != prefix, "");
- this.prefix = prefix;
- this.rootSegment = root;
- this.segment = null;
- this.segmentIndex = -1;
- this.offset = 0;
- this.length = prefix.Length;
- }
- /// <summary>
- /// What length of segment that matched
- /// </summary>
- internal int Length
- {
- get
- {
- return this.length;
- }
- }
- /// <summary>
- /// The offset within the original segment where the matching part of the source string began
- /// </summary>
- internal int Offset
- {
- get
- {
- return this.offset;
- }
- }
- /// <summary>
- /// The traverser is currently at this segment node
- /// </summary>
- internal TrieSegment Segment
- {
- get
- {
- return this.segment;
- }
- set
- {
- Fx.Assert(null != value, "");
- this.segment = value;
- }
- }
- internal int SegmentIndex
- {
- get
- {
- return this.segmentIndex;
- }
- }
- /// <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;
- }
- /// <summary>
- /// Traverse the prefix tree.. using only the first character of each segment to jump from
- /// segment to segment
- /// </summary>
- internal bool MoveNextByFirstChar()
- {
- 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]);
- 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;
- }
- }
- internal class Trie
- {
- TrieSegment root; // prefix tree root
- bool hasDescendants;
- internal Trie()
- {
- this.hasDescendants = false;
- }
- bool HasDescendants
- {
- get
- {
- //return (null != this.root && this.root.ChildCount > 0);
- return this.hasDescendants;
- }
- }
- #if NO
- internal bool IsEmpty
- {
- get
- {
- return (null == this.root || (null == this.root.Data && 0 == this.root.ChildCount));
- }
- }
- #endif
- internal TrieSegment this[string prefix]
- {
- get
- {
- return this.Find(prefix);
- }
- }
- /// <summary>
- /// Tree root segment
- /// </summary>
- internal TrieSegment Root
- {
- get
- {
- this.EnsureRoot();
- return this.root;
- }
- }
- internal TrieSegment Add(string newPrefix)
- {
- if (newPrefix.Length <= 0)
- {
- return this.Root;
- }
- this.EnsureRoot();
- TrieTraverser traverser = new TrieTraverser(this.root, newPrefix); // struct
- TrieSegment parent;
- int indexDivergence;
- while (true)
- {
- parent = traverser.Segment;
- if (traverser.MoveNextByFirstChar())
- {
- // There is a child segment that starts with the same character as the remainder of newPrefix
- // We have a shared segment
- // How much does newPrefix share with the current segment? Find the point at which they diverge
- if (null != parent && -1 != (indexDivergence = traverser.Segment.FindDivergence(newPrefix, traverser.Offset, traverser.Length)))
- {
- // Segments diverge at character # 'indexDivergence'. newPrefix will share the segment upto
- // that character. Beyond that character, we will now have 2 child segments:
- // - one for the portion of the current segment that diverged
- // - one for the portion of the new segment that diverged
- // Split the current segment into a shared part and a child containing the remainder of the segment..
- traverser.Segment = parent.SplitChild(traverser.SegmentIndex, indexDivergence);
- }
- }
- else
- {
- if (traverser.Length <= 0)
- {
- // The entire new prefix has been added to the tree
- break;
- }
- // No existing segment to share. Add a new one
- traverser.Segment = parent.AddChild(new TrieSegment(newPrefix, traverser.Offset, traverser.Length));
- }
- }
- this.hasDescendants = true;
- return parent;
- }
- void EnsureRoot()
- {
- if (null == this.root)
- {
- this.root = new TrieSegment();
- }
- }
- 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;
- }
- void PruneRoot()
- {
- if (null != this.root && this.root.CanPrune)
- {
- this.root = null;
- }
- }
- 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();
- }
- internal void Trim()
- {
- this.root.Trim();
- }
- }
- internal class StringPrefixOpcode : LiteralRelationOpcode
- {
- string literal;
- internal StringPrefixOpcode(string literal)
- : base(OpcodeID.StringPrefix)
- {
- Fx.Assert(null != literal, "");
- this.literal = literal;
- }
- #if NO
- internal override ValueDataType DataType
- {
- get
- {
- return ValueDataType.String;
- }
- }
- #endif
- internal override object Literal
- {
- get
- {
- return this.literal;
- }
- }
- internal override void Add(Opcode op)
- {
- StringPrefixOpcode prefixOp = op as StringPrefixOpcode;
- if (null == prefixOp)
- {
- base.Add(op);
- return;
- }
- Fx.Assert(null != this.prev, "");
- StringPrefixBranchOpcode branch = new StringPrefixBranchOpcode();
- this.prev.Replace(this, branch);
- branch.Add(this);
- branch.Add(prefixOp);
- }
- internal override bool Equals(Opcode op)
- {
- if (base.Equals(op))
- {
- StringPrefixOpcode prefixOp = (StringPrefixOpcode)op;
- return (prefixOp.literal == this.literal);
- }
- return false;
- }
- internal override Opcode Eval(ProcessingContext context)
- {
- StackFrame arg = context.TopArg;
- if (1 == arg.Count)
- {
- Fx.Assert(context.Values[arg.basePtr].IsType(ValueDataType.String), "");
- string target = context.Values[arg.basePtr].String;
- context.Values[arg.basePtr].Boolean = target.StartsWith(this.literal, StringComparison.Ordinal);
- }
- else
- {
- for (int i = arg.basePtr; i <= arg.endPtr; ++i)
- {
- Fx.Assert(context.Values[i].IsType(ValueDataType.String), "");
- string target = context.Values[i].String;
- context.Values[i].Boolean = target.StartsWith(this.literal, StringComparison.Ordinal);
- }
- }
- return this.next;
- }
- }
- internal class TrieBranchIndex : QueryBranchIndex
- {
- int count;
- Trie trie;
- internal TrieBranchIndex()
- {
- this.count = 0;
- this.trie = new Trie();
- }
- internal override int Count
- {
- get
- {
- return this.count;
- }
- }
- 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;
- }
- }
- internal override void CollectXPathFilters(ICollection<MessageFilter> filters)
- {
- this.trie.Root.CollectXPathFilters(filters);
- }
- #if NO
- internal override IEnumerator GetEnumerator()
- {
- //return new TrieBreadthFirstEnum(this.trie);
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplementedException("TODO"));
- }
- #endif
- void Match(int valIndex, string segment, QueryBranchResultSet results)
- {
- TrieTraverser traverser = new TrieTraverser(this.trie.Root, segment);
- while (traverser.MoveNext())
- {
- object segmentData = traverser.Segment.Data;
- if (null != segmentData)
- {
- results.Add((QueryBranch)segmentData, valIndex);
- }
- }
- }
- internal override void Match(int valIndex, ref Value val, QueryBranchResultSet results)
- {
- if (ValueDataType.Sequence == val.Type)
- {
- NodeSequence sequence = val.Sequence;
- for (int i = 0; i < sequence.Count; ++i)
- {
- this.Match(valIndex, sequence.Items[i].StringValue(), results);
- }
- }
- else
- {
- this.Match(valIndex, val.String, results);
- }
- }
- internal override void Remove(object key)
- {
- this.trie.Remove((string)key);
- this.count--;
- }
- internal override void Trim()
- {
- this.trie.Trim();
- }
- }
- internal class StringPrefixBranchOpcode : QueryConditionalBranchOpcode
- {
- internal StringPrefixBranchOpcode()
- : base(OpcodeID.StringPrefixBranch, new TrieBranchIndex())
- {
- }
- }
- }
|