private static void Add(UriTemplateTrieNode root, KeyValuePair <UriTemplate, object> kvp) { UriTemplateTrieNode node = root; UriTemplate key = kvp.Key; bool flag = ((key.segments.Count == 0) || key.HasWildcard) || key.segments[key.segments.Count - 1].EndsWithSlash; for (int i = 0; i < key.segments.Count; i++) { if (i >= key.firstOptionalSegment) { node.endOfPath.Items.Add(kvp); } UriTemplatePathSegment segment = key.segments[i]; if (!segment.EndsWithSlash) { switch (segment.Nature) { case UriTemplatePartType.Literal: node.AddFinalLiteralSegment(segment as UriTemplateLiteralPathSegment, kvp); break; case UriTemplatePartType.Compound: node.AddFinalCompoundSegment(segment as UriTemplateCompoundPathSegment, kvp); break; case UriTemplatePartType.Variable: node.finalVariableSegment.Items.Add(kvp); break; } } else { switch (segment.Nature) { case UriTemplatePartType.Literal: node = node.AddNextLiteralSegment(segment as UriTemplateLiteralPathSegment); break; case UriTemplatePartType.Compound: node = node.AddNextCompoundSegment(segment as UriTemplateCompoundPathSegment); break; case UriTemplatePartType.Variable: node = node.AddNextVariableSegment(); break; } } } if (flag) { if (key.HasWildcard) { node.star.Items.Add(kvp); } else { node.endOfPath.Items.Add(kvp); } } }
public static UriTemplateTrieNode Make(IEnumerable <KeyValuePair <UriTemplate, object> > keyValuePairs, bool allowDuplicateEquivalentUriTemplates) { UriTemplateTrieNode root = new UriTemplateTrieNode(0); foreach (KeyValuePair <UriTemplate, object> pair in keyValuePairs) { Add(root, pair); } Validate(root, allowDuplicateEquivalentUriTemplates); return(root); }
static UriTemplate FindAnyUriTemplate(UriTemplateTrieNode node) { while (node != null) { if (node.endOfPath.Items.Count > 0) { return(node.endOfPath.Items[0].Key); } if (node.finalVariableSegment.Items.Count > 0) { return(node.finalVariableSegment.Items[0].Key); } if (node.star.Items.Count > 0) { return(node.star.Items[0].Key); } if (node.finalLiteralSegment != null) { UriTemplatePathPartiallyEquivalentSet pes = GetAnyDictionaryValue <UriTemplatePathPartiallyEquivalentSet>(node.finalLiteralSegment); Fx.Assert(pes.Items.Count > 0, "Otherwise, why creating the dictionary?"); return(pes.Items[0].Key); } if (node.finalCompoundSegment != null) { UriTemplatePathPartiallyEquivalentSet pes = node.finalCompoundSegment.GetAnyValue(); Fx.Assert(pes.Items.Count > 0, "Otherwise, why creating the collection?"); return(pes.Items[0].Key); } if (node.nextLiteralSegment != null) { UriTemplateTrieLocation location = GetAnyDictionaryValue <UriTemplateTrieLocation>(node.nextLiteralSegment); node = location.node; } else if (node.nextCompoundSegment != null) { UriTemplateTrieLocation location = node.nextCompoundSegment.GetAnyValue(); node = location.node; } else if (node.nextVariableSegment != null) { node = node.nextVariableSegment.node; } else { node = null; } } Fx.Assert("How did we got here without finding a UriTemplate earlier?"); return(null); }
private void Validate(bool allowDuplicateEquivalentUriTemplates) { if (this.baseAddress == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(System.ServiceModel.SR.GetString("UTTBaseAddressNotSet"))); } this.numSegmentsInBaseAddress = this.baseAddress.Segments.Length; if (this.templates.Count == 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(System.ServiceModel.SR.GetString("UTTEmptyKeyValuePairs"))); } this.rootNode = UriTemplateTrieNode.Make(this.templates, allowDuplicateEquivalentUriTemplates); }
UriTemplateTrieNode AddNextVariableSegment() { if (this.nextVariableSegment != null) { return(this.nextVariableSegment.node); } else { UriTemplateTrieNode newNode = new UriTemplateTrieNode(this.depth + 1); newNode.onFailure = new UriTemplateTrieLocation(this, UriTemplateTrieIntraNodeLocation.AfterVariable); this.nextVariableSegment = new UriTemplateTrieLocation(newNode, UriTemplateTrieIntraNodeLocation.BeforeLiteral); return(newNode); } }
public static UriTemplateTrieNode Make(IEnumerable <KeyValuePair <UriTemplate, object> > keyValuePairs, bool allowDuplicateEquivalentUriTemplates) { // given a UTT at MakeReadOnly time, build the trie // note that root.onFailure == null; UriTemplateTrieNode root = new UriTemplateTrieNode(0); foreach (KeyValuePair <UriTemplate, object> kvp in keyValuePairs) { Add(root, kvp); } Validate(root, allowDuplicateEquivalentUriTemplates); return(root); }
private static UriTemplate FindAnyUriTemplate(UriTemplateTrieNode node) { while (node != null) { if (node.endOfPath.Items.Count > 0) { KeyValuePair <UriTemplate, object> pair = node.endOfPath.Items[0]; return(pair.Key); } if (node.finalVariableSegment.Items.Count > 0) { KeyValuePair <UriTemplate, object> pair2 = node.finalVariableSegment.Items[0]; return(pair2.Key); } if (node.star.Items.Count > 0) { KeyValuePair <UriTemplate, object> pair3 = node.star.Items[0]; return(pair3.Key); } if (node.finalLiteralSegment != null) { KeyValuePair <UriTemplate, object> pair4 = GetAnyDictionaryValue <UriTemplatePathPartiallyEquivalentSet>(node.finalLiteralSegment).Items[0]; return(pair4.Key); } if (node.finalCompoundSegment != null) { KeyValuePair <UriTemplate, object> pair5 = node.finalCompoundSegment.GetAnyValue().Items[0]; return(pair5.Key); } if (node.nextLiteralSegment != null) { node = GetAnyDictionaryValue <UriTemplateTrieLocation>(node.nextLiteralSegment).node; } else { if (node.nextCompoundSegment != null) { node = node.nextCompoundSegment.GetAnyValue().node; continue; } if (node.nextVariableSegment != null) { node = node.nextVariableSegment.node; continue; } node = null; } } return(null); }
private UriTemplateTrieNode AddNextVariableSegment() { if (this.nextVariableSegment != null) { return(this.nextVariableSegment.node); } UriTemplateTrieNode n = new UriTemplateTrieNode(this.depth + 1) { onFailure = new UriTemplateTrieLocation(this, UriTemplateTrieIntraNodeLocation.AfterVariable) }; this.nextVariableSegment = new UriTemplateTrieLocation(n, UriTemplateTrieIntraNodeLocation.BeforeLiteral); return(n); }
void Validate(bool allowDuplicateEquivalentUriTemplates) { if (this.baseAddress == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString( SR.UTTBaseAddressNotSet))); } this.numSegmentsInBaseAddress = this.baseAddress.Segments.Length; if (this.templates.Count == 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString( SR.UTTEmptyKeyValuePairs))); } // build the trie and // validate that forall Uri u, at most one UriTemplate is a best match for u rootNode = UriTemplateTrieNode.Make(this.templates, allowDuplicateEquivalentUriTemplates); }
UriTemplateTrieNode AddNextCompoundSegment(UriTemplateCompoundPathSegment cps) { Fx.Assert(cps != null, "must be - based on the segment nature"); if (this.nextCompoundSegment == null) { this.nextCompoundSegment = new AscendingSortedCompoundSegmentsCollection <UriTemplateTrieLocation>(); } UriTemplateTrieLocation nextLocation = this.nextCompoundSegment.Find(cps); if (nextLocation == null) { UriTemplateTrieNode nextNode = new UriTemplateTrieNode(this.depth + 1); nextNode.onFailure = new UriTemplateTrieLocation(this, UriTemplateTrieIntraNodeLocation.AfterCompound); nextLocation = new UriTemplateTrieLocation(nextNode, UriTemplateTrieIntraNodeLocation.BeforeLiteral); this.nextCompoundSegment.Add(cps, nextLocation); } return(nextLocation.node); }
private UriTemplateTrieNode AddNextLiteralSegment(UriTemplateLiteralPathSegment lps) { if ((this.nextLiteralSegment != null) && this.nextLiteralSegment.ContainsKey(lps)) { return(this.nextLiteralSegment[lps].node); } if (this.nextLiteralSegment == null) { this.nextLiteralSegment = new Dictionary <UriTemplateLiteralPathSegment, UriTemplateTrieLocation>(); } UriTemplateTrieNode n = new UriTemplateTrieNode(this.depth + 1) { onFailure = new UriTemplateTrieLocation(this, UriTemplateTrieIntraNodeLocation.AfterLiteral) }; this.nextLiteralSegment.Add(lps, new UriTemplateTrieLocation(n, UriTemplateTrieIntraNodeLocation.BeforeLiteral)); return(n); }
UriTemplateTrieNode AddNextLiteralSegment(UriTemplateLiteralPathSegment lps) { Fx.Assert(lps != null, "must be - based on the segment nature"); if (this.nextLiteralSegment != null && this.nextLiteralSegment.ContainsKey(lps)) { return(this.nextLiteralSegment[lps].node); } else { if (this.nextLiteralSegment == null) { this.nextLiteralSegment = new Dictionary <UriTemplateLiteralPathSegment, UriTemplateTrieLocation>(); } UriTemplateTrieNode newNode = new UriTemplateTrieNode(this.depth + 1); newNode.onFailure = new UriTemplateTrieLocation(this, UriTemplateTrieIntraNodeLocation.AfterLiteral); this.nextLiteralSegment.Add(lps, new UriTemplateTrieLocation(newNode, UriTemplateTrieIntraNodeLocation.BeforeLiteral)); return(newNode); } }
private UriTemplateTrieNode AddNextCompoundSegment(UriTemplateCompoundPathSegment cps) { if (this.nextCompoundSegment == null) { this.nextCompoundSegment = new AscendingSortedCompoundSegmentsCollection <UriTemplateTrieLocation>(); } UriTemplateTrieLocation location = this.nextCompoundSegment.Find(cps); if (location == null) { UriTemplateTrieNode n = new UriTemplateTrieNode(this.depth + 1) { onFailure = new UriTemplateTrieLocation(this, UriTemplateTrieIntraNodeLocation.AfterCompound) }; location = new UriTemplateTrieLocation(n, UriTemplateTrieIntraNodeLocation.BeforeLiteral); this.nextCompoundSegment.Add(cps, location); } return(location.node); }
static void Add(UriTemplateTrieNode root, KeyValuePair <UriTemplate, object> kvp) { // Currently UTT doesn't support teplates with ignoreTrailingSlash == true; thus we // don't care about supporting it in the trie as well. UriTemplateTrieNode current = root; UriTemplate ut = kvp.Key; bool needProcessingOnFinalNode = ((ut.segments.Count == 0) || ut.HasWildcard || ut.segments[ut.segments.Count - 1].EndsWithSlash); for (int i = 0; i < ut.segments.Count; ++i) { if (i >= ut.firstOptionalSegment) { current.endOfPath.Items.Add(kvp); } UriTemplatePathSegment ps = ut.segments[i]; if (!ps.EndsWithSlash) { Fx.Assert(i == ut.segments.Count - 1, "only the last segment can !EndsWithSlash"); Fx.Assert(!ut.HasWildcard, "path star cannot have !EndsWithSlash"); switch (ps.Nature) { case UriTemplatePartType.Literal: current.AddFinalLiteralSegment(ps as UriTemplateLiteralPathSegment, kvp); break; case UriTemplatePartType.Compound: current.AddFinalCompoundSegment(ps as UriTemplateCompoundPathSegment, kvp); break; case UriTemplatePartType.Variable: current.finalVariableSegment.Items.Add(kvp); break; default: Fx.Assert("Invalid value as PathSegment.Nature"); break; } } else { Fx.Assert(ps.EndsWithSlash, "ps.EndsWithSlash"); switch (ps.Nature) { case UriTemplatePartType.Literal: current = current.AddNextLiteralSegment(ps as UriTemplateLiteralPathSegment); break; case UriTemplatePartType.Compound: current = current.AddNextCompoundSegment(ps as UriTemplateCompoundPathSegment); break; case UriTemplatePartType.Variable: current = current.AddNextVariableSegment(); break; default: Fx.Assert("Invalid value as PathSegment.Nature"); break; } } } if (needProcessingOnFinalNode) { // if the last segment ended in a slash, there is still more to do if (ut.HasWildcard) { // e.g. "path1/path2/*" current.star.Items.Add(kvp); } else { // e.g. "path1/path2/" current.endOfPath.Items.Add(kvp); } } }
static void Validate(UriTemplateTrieNode root, bool allowDuplicateEquivalentUriTemplates) { // walk the entire tree, and ensure that each PathEquivalentSet is ok (no ambiguous queries), // verify thst compound segments didn't add potentialy multiple matchs; // also Assert various data-structure invariants Queue <UriTemplateTrieNode> nodesQueue = new Queue <UriTemplateTrieNode>(); UriTemplateTrieNode current = root; while (true) { // validate all the PathEquivalentSets that live in this node Validate(current.endOfPath, allowDuplicateEquivalentUriTemplates); Validate(current.finalVariableSegment, allowDuplicateEquivalentUriTemplates); Validate(current.star, allowDuplicateEquivalentUriTemplates); if (current.finalLiteralSegment != null) { foreach (KeyValuePair <UriTemplateLiteralPathSegment, UriTemplatePathPartiallyEquivalentSet> kvp in current.finalLiteralSegment) { Validate(kvp.Value, allowDuplicateEquivalentUriTemplates); } } if (current.finalCompoundSegment != null) { IList <IList <UriTemplatePathPartiallyEquivalentSet> > pesLists = current.finalCompoundSegment.Values; for (int i = 0; i < pesLists.Count; i++) { if (!allowDuplicateEquivalentUriTemplates && (pesLists[i].Count > 1)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString( SR.UTTDuplicate, pesLists[i][0].Items[0].Key.ToString(), pesLists[i][1].Items[0].Key.ToString()))); } for (int j = 0; j < pesLists[i].Count; j++) { Validate(pesLists[i][j], allowDuplicateEquivalentUriTemplates); } } } // deal with children of this node if (current.nextLiteralSegment != null) { foreach (KeyValuePair <UriTemplateLiteralPathSegment, UriTemplateTrieLocation> kvp in current.nextLiteralSegment) { Fx.Assert(kvp.Value.locationWithin == UriTemplateTrieIntraNodeLocation.BeforeLiteral, "forward-pointers should always point to a BeforeLiteral location"); Fx.Assert(kvp.Value.node.depth == current.depth + 1, "kvp.Value.node.depth == current.depth + 1"); Fx.Assert(kvp.Value.node.onFailure.node == current, "back pointer should point back to here"); Fx.Assert(kvp.Value.node.onFailure.locationWithin == UriTemplateTrieIntraNodeLocation.AfterLiteral, "back-pointer should be AfterLiteral"); nodesQueue.Enqueue(kvp.Value.node); } } if (current.nextCompoundSegment != null) { IList <IList <UriTemplateTrieLocation> > locations = current.nextCompoundSegment.Values; for (int i = 0; i < locations.Count; i++) { if (!allowDuplicateEquivalentUriTemplates && (locations[i].Count > 1)) { // In the future we might ease up the restrictions and verify if there is realy // a potential multiple match here; for now we are throwing. UriTemplate firstTemplate = FindAnyUriTemplate(locations[i][0].node); UriTemplate secondTemplate = FindAnyUriTemplate(locations[i][1].node); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString( SR.UTTDuplicate, firstTemplate.ToString(), secondTemplate.ToString()))); } for (int j = 0; j < locations[i].Count; j++) { UriTemplateTrieLocation location = locations[i][j]; Fx.Assert(location.locationWithin == UriTemplateTrieIntraNodeLocation.BeforeLiteral, "forward-pointers should always point to a BeforeLiteral location"); Fx.Assert(location.node.depth == current.depth + 1, "kvp.Value.node.depth == current.depth + 1"); Fx.Assert(location.node.onFailure.node == current, "back pointer should point back to here"); Fx.Assert(location.node.onFailure.locationWithin == UriTemplateTrieIntraNodeLocation.AfterCompound, "back-pointer should be AfterCompound"); nodesQueue.Enqueue(location.node); } } } if (current.nextVariableSegment != null) { Fx.Assert(current.nextVariableSegment.locationWithin == UriTemplateTrieIntraNodeLocation.BeforeLiteral, "forward-pointers should always point to a BeforeLiteral location"); Fx.Assert(current.nextVariableSegment.node.depth == current.depth + 1, "current.nextVariableSegment.node.depth == current.depth + 1"); Fx.Assert(current.nextVariableSegment.node.onFailure.node == current, "back pointer should point back to here"); Fx.Assert(current.nextVariableSegment.node.onFailure.locationWithin == UriTemplateTrieIntraNodeLocation.AfterVariable, "back-pointer should be AfterVariable"); nodesQueue.Enqueue(current.nextVariableSegment.node); } // move on to next bit of work if (nodesQueue.Count == 0) { break; } current = nodesQueue.Dequeue(); } }
private static void Validate(UriTemplateTrieNode root, bool allowDuplicateEquivalentUriTemplates) { Queue <UriTemplateTrieNode> queue = new Queue <UriTemplateTrieNode>(); UriTemplateTrieNode node = root; while (true) { Validate(node.endOfPath, allowDuplicateEquivalentUriTemplates); Validate(node.finalVariableSegment, allowDuplicateEquivalentUriTemplates); Validate(node.star, allowDuplicateEquivalentUriTemplates); if (node.finalLiteralSegment != null) { foreach (KeyValuePair <UriTemplateLiteralPathSegment, UriTemplatePathPartiallyEquivalentSet> pair in node.finalLiteralSegment) { Validate(pair.Value, allowDuplicateEquivalentUriTemplates); } } if (node.finalCompoundSegment != null) { IList <IList <UriTemplatePathPartiallyEquivalentSet> > values = node.finalCompoundSegment.Values; for (int i = 0; i < values.Count; i++) { if (!allowDuplicateEquivalentUriTemplates && (values[i].Count > 1)) { object[] args = new object[2]; KeyValuePair <UriTemplate, object> pair3 = values[i][0].Items[0]; args[0] = pair3.Key.ToString(); KeyValuePair <UriTemplate, object> pair4 = values[i][1].Items[0]; args[1] = pair4.Key.ToString(); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(System.ServiceModel.SR.GetString("UTTDuplicate", args))); } for (int j = 0; j < values[i].Count; j++) { Validate(values[i][j], allowDuplicateEquivalentUriTemplates); } } } if (node.nextLiteralSegment != null) { foreach (KeyValuePair <UriTemplateLiteralPathSegment, UriTemplateTrieLocation> pair2 in node.nextLiteralSegment) { queue.Enqueue(pair2.Value.node); } } if (node.nextCompoundSegment != null) { IList <IList <UriTemplateTrieLocation> > list2 = node.nextCompoundSegment.Values; for (int k = 0; k < list2.Count; k++) { if (!allowDuplicateEquivalentUriTemplates && (list2[k].Count > 1)) { UriTemplate template = FindAnyUriTemplate(list2[k][0].node); UriTemplate template2 = FindAnyUriTemplate(list2[k][1].node); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(System.ServiceModel.SR.GetString("UTTDuplicate", new object[] { template.ToString(), template2.ToString() }))); } for (int m = 0; m < list2[k].Count; m++) { UriTemplateTrieLocation location = list2[k][m]; queue.Enqueue(location.node); } } } if (node.nextVariableSegment != null) { queue.Enqueue(node.nextVariableSegment.node); } if (queue.Count == 0) { return; } node = queue.Dequeue(); } }