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); }
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); } }
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); }
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 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 bool GetMatch(UriTemplateTrieLocation location, UriTemplateLiteralPathSegment[] wireData, ICollection <UriTemplateTableMatchCandidate> candidates) { int initialDepth = location.node.depth; SingleLocationOrLocationsSet nextStep; UriTemplatePathPartiallyEquivalentSet answer; do { if (TryMatch(wireData, location, out answer, out nextStep)) { if (answer != null) { for (int i = 0; i < answer.Items.Count; i++) { candidates.Add(new UriTemplateTableMatchCandidate(answer.Items[i].Key, answer.SegmentsCount, answer.Items[i].Value)); } } return(true); } if (nextStep.IsSingle) { location = nextStep.SingleLocation; } else { Fx.Assert(nextStep.LocationsSet != null, "This should be set to a valid value by TryMatch"); if (CheckMultipleMatches(nextStep.LocationsSet, wireData, candidates)) { return(true); } location = GetFailureLocationFromLocationsSet(nextStep.LocationsSet); } } while ((location != null) && (location.node.depth >= initialDepth)); // we walked the whole trie down and found nothing return(false); }
private static bool GetMatch(UriTemplateTrieLocation location, UriTemplateLiteralPathSegment[] wireData, ICollection <UriTemplateTableMatchCandidate> candidates) { int depth = location.node.depth; do { SingleLocationOrLocationsSet set; UriTemplatePathPartiallyEquivalentSet set2; if (TryMatch(wireData, location, out set2, out set)) { if (set2 != null) { for (int i = 0; i < set2.Items.Count; i++) { KeyValuePair <UriTemplate, object> pair = set2.Items[i]; KeyValuePair <UriTemplate, object> pair2 = set2.Items[i]; candidates.Add(new UriTemplateTableMatchCandidate(pair.Key, set2.SegmentsCount, pair2.Value)); } } return(true); } if (set.IsSingle) { location = set.SingleLocation; } else { if (CheckMultipleMatches(set.LocationsSet, wireData, candidates)) { return(true); } location = GetFailureLocationFromLocationsSet(set.LocationsSet); } }while ((location != null) && (location.node.depth >= depth)); return(false); }
public SingleLocationOrLocationsSet(IList <IList <UriTemplateTrieLocation> > locationsSet) { this.isSingle = false; this.singleLocation = null; this.locationsSet = locationsSet; }
public SingleLocationOrLocationsSet(UriTemplateTrieLocation singleLocation) { this.isSingle = true; this.singleLocation = singleLocation; this.locationsSet = null; }
public bool Match(UriTemplateLiteralPathSegment[] wireData, ICollection <UriTemplateTableMatchCandidate> candidates) { UriTemplateTrieLocation currentLocation = new UriTemplateTrieLocation(this, UriTemplateTrieIntraNodeLocation.BeforeLiteral); return(GetMatch(currentLocation, wireData, candidates)); }
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(); } }
static bool TryMatch(UriTemplateLiteralPathSegment[] wireUriSegments, UriTemplateTrieLocation currentLocation, out UriTemplatePathPartiallyEquivalentSet success, out SingleLocationOrLocationsSet nextStep) { // if returns true, success is set to answer // if returns false, nextStep is set to next place to look success = null; nextStep = new SingleLocationOrLocationsSet(); if (wireUriSegments.Length <= currentLocation.node.depth) { Fx.Assert(wireUriSegments.Length == 0 || wireUriSegments[wireUriSegments.Length - 1].EndsWithSlash, "we should not have traversed this deep into the trie unless the wire path ended in a slash"); if (currentLocation.node.endOfPath.Items.Count != 0) { // exact match of e.g. "path1/path2/" success = currentLocation.node.endOfPath; return(true); } else if (currentLocation.node.star.Items.Count != 0) { // inexact match of e.g. WIRE("path1/path2/") against TEMPLATE("path1/path2/*") success = currentLocation.node.star; return(true); } else { nextStep = new SingleLocationOrLocationsSet(currentLocation.node.onFailure); return(false); } } else { UriTemplateLiteralPathSegment curWireSeg = wireUriSegments[currentLocation.node.depth]; bool considerLiteral = false; bool considerCompound = false; bool considerVariable = false; bool considerStar = false; switch (currentLocation.locationWithin) { case UriTemplateTrieIntraNodeLocation.BeforeLiteral: considerLiteral = true; considerCompound = true; considerVariable = true; considerStar = true; break; case UriTemplateTrieIntraNodeLocation.AfterLiteral: considerLiteral = false; considerCompound = true; considerVariable = true; considerStar = true; break; case UriTemplateTrieIntraNodeLocation.AfterCompound: considerLiteral = false; considerCompound = false; considerVariable = true; considerStar = true; break; case UriTemplateTrieIntraNodeLocation.AfterVariable: considerLiteral = false; considerCompound = false; considerVariable = false; considerStar = true; break; default: Fx.Assert("bad kind"); break; } if (curWireSeg.EndsWithSlash) { IList <IList <UriTemplateTrieLocation> > compoundLocationsSet; if (considerLiteral && currentLocation.node.nextLiteralSegment != null && currentLocation.node.nextLiteralSegment.ContainsKey(curWireSeg)) { nextStep = new SingleLocationOrLocationsSet(currentLocation.node.nextLiteralSegment[curWireSeg]); return(false); } else if (considerCompound && currentLocation.node.nextCompoundSegment != null && AscendingSortedCompoundSegmentsCollection <UriTemplateTrieLocation> .Lookup(currentLocation.node.nextCompoundSegment, curWireSeg, out compoundLocationsSet)) { nextStep = new SingleLocationOrLocationsSet(compoundLocationsSet); return(false); } else if (considerVariable && currentLocation.node.nextVariableSegment != null && !curWireSeg.IsNullOrEmpty()) { nextStep = new SingleLocationOrLocationsSet(currentLocation.node.nextVariableSegment); return(false); } else if (considerStar && currentLocation.node.star.Items.Count != 0) { // matches e.g. WIRE("path1/path2/path3") and TEMPLATE("path1/*") success = currentLocation.node.star; return(true); } else { nextStep = new SingleLocationOrLocationsSet(currentLocation.node.onFailure); return(false); } } else { IList <IList <UriTemplatePathPartiallyEquivalentSet> > compoundPathEquivalentSets; Fx.Assert(!curWireSeg.EndsWithSlash, "!curWireSeg.EndsWithSlash"); Fx.Assert(!curWireSeg.IsNullOrEmpty(), "!curWireSeg.IsNullOrEmpty()"); if (considerLiteral && currentLocation.node.finalLiteralSegment != null && currentLocation.node.finalLiteralSegment.ContainsKey(curWireSeg)) { // matches e.g. WIRE("path1/path2") and TEMPLATE("path1/path2") success = currentLocation.node.finalLiteralSegment[curWireSeg]; return(true); } else if (considerCompound && currentLocation.node.finalCompoundSegment != null && AscendingSortedCompoundSegmentsCollection <UriTemplatePathPartiallyEquivalentSet> .Lookup(currentLocation.node.finalCompoundSegment, curWireSeg, out compoundPathEquivalentSets)) { // matches e.g. WIRE("path1/path2") and TEMPLATE("path1/p{var}th2") // we should take only the highest order match! Fx.Assert(compoundPathEquivalentSets.Count >= 1, "Lookup is expected to return false otherwise"); Fx.Assert(compoundPathEquivalentSets[0].Count > 0, "Find shouldn't return empty sublists"); if (compoundPathEquivalentSets[0].Count == 1) { success = compoundPathEquivalentSets[0][0]; } else { success = new UriTemplatePathPartiallyEquivalentSet(currentLocation.node.depth + 1); for (int i = 0; i < compoundPathEquivalentSets[0].Count; i++) { success.Items.AddRange(compoundPathEquivalentSets[0][i].Items); } } return(true); } else if (considerVariable && currentLocation.node.finalVariableSegment.Items.Count != 0) { // matches e.g. WIRE("path1/path2") and TEMPLATE("path1/{var}") success = currentLocation.node.finalVariableSegment; return(true); } else if (considerStar && currentLocation.node.star.Items.Count != 0) { // matches e.g. WIRE("path1/path2") and TEMPLATE("path1/*") success = currentLocation.node.star; return(true); } else { nextStep = new SingleLocationOrLocationsSet(currentLocation.node.onFailure); return(false); } } } }
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(); } }
private static bool TryMatch(UriTemplateLiteralPathSegment[] wireUriSegments, UriTemplateTrieLocation currentLocation, out UriTemplatePathPartiallyEquivalentSet success, out SingleLocationOrLocationsSet nextStep) { IList <IList <UriTemplatePathPartiallyEquivalentSet> > list2; success = null; nextStep = new SingleLocationOrLocationsSet(); if (wireUriSegments.Length <= currentLocation.node.depth) { if (currentLocation.node.endOfPath.Items.Count != 0) { success = currentLocation.node.endOfPath; return(true); } if (currentLocation.node.star.Items.Count != 0) { success = currentLocation.node.star; return(true); } nextStep = new SingleLocationOrLocationsSet(currentLocation.node.onFailure); return(false); } UriTemplateLiteralPathSegment key = wireUriSegments[currentLocation.node.depth]; bool flag = false; bool flag2 = false; bool flag3 = false; bool flag4 = false; switch (currentLocation.locationWithin) { case UriTemplateTrieIntraNodeLocation.BeforeLiteral: flag = true; flag2 = true; flag3 = true; flag4 = true; break; case UriTemplateTrieIntraNodeLocation.AfterLiteral: flag = false; flag2 = true; flag3 = true; flag4 = true; break; case UriTemplateTrieIntraNodeLocation.AfterCompound: flag = false; flag2 = false; flag3 = true; flag4 = true; break; case UriTemplateTrieIntraNodeLocation.AfterVariable: flag = false; flag2 = false; flag3 = false; flag4 = true; break; } if (key.EndsWithSlash) { IList <IList <UriTemplateTrieLocation> > list; if ((flag && (currentLocation.node.nextLiteralSegment != null)) && currentLocation.node.nextLiteralSegment.ContainsKey(key)) { nextStep = new SingleLocationOrLocationsSet(currentLocation.node.nextLiteralSegment[key]); return(false); } if ((flag2 && (currentLocation.node.nextCompoundSegment != null)) && AscendingSortedCompoundSegmentsCollection <UriTemplateTrieLocation> .Lookup(currentLocation.node.nextCompoundSegment, key, out list)) { nextStep = new SingleLocationOrLocationsSet(list); return(false); } if ((flag3 && (currentLocation.node.nextVariableSegment != null)) && !key.IsNullOrEmpty()) { nextStep = new SingleLocationOrLocationsSet(currentLocation.node.nextVariableSegment); return(false); } if (flag4 && (currentLocation.node.star.Items.Count != 0)) { success = currentLocation.node.star; return(true); } nextStep = new SingleLocationOrLocationsSet(currentLocation.node.onFailure); return(false); } if ((flag && (currentLocation.node.finalLiteralSegment != null)) && currentLocation.node.finalLiteralSegment.ContainsKey(key)) { success = currentLocation.node.finalLiteralSegment[key]; return(true); } if ((flag2 && (currentLocation.node.finalCompoundSegment != null)) && AscendingSortedCompoundSegmentsCollection <UriTemplatePathPartiallyEquivalentSet> .Lookup(currentLocation.node.finalCompoundSegment, key, out list2)) { if (list2[0].Count == 1) { success = list2[0][0]; } else { success = new UriTemplatePathPartiallyEquivalentSet(currentLocation.node.depth + 1); for (int i = 0; i < list2[0].Count; i++) { success.Items.AddRange(list2[0][i].Items); } } return(true); } if (flag3 && (currentLocation.node.finalVariableSegment.Items.Count != 0)) { success = currentLocation.node.finalVariableSegment; return(true); } if (flag4 && (currentLocation.node.star.Items.Count != 0)) { success = currentLocation.node.star; return(true); } nextStep = new SingleLocationOrLocationsSet(currentLocation.node.onFailure); return(false); }