static void Validate(UriTemplatePathPartiallyEquivalentSet pes, bool allowDuplicateEquivalentUriTemplates) { // A set with 0 or 1 items is valid by definition if (pes.Items.Count < 2) { return; } // Assert all paths are partially-equivalent for (int i = 0; i < pes.Items.Count - 1; ++i) { Fx.Assert(pes.Items[i].Key.IsPathPartiallyEquivalentAt(pes.Items[i + 1].Key, pes.SegmentsCount), "all elements of a PES must be path partially-equivalent"); } // We will check that the queries disambiguate only for templates, which are // matched completely at the segments count; templates, which are match at // that point due to terminal defaults, will be ruled out. UriTemplate[] a = new UriTemplate[pes.Items.Count]; int arrayIndex = 0; foreach (KeyValuePair <UriTemplate, object> kvp in pes.Items) { if (pes.SegmentsCount < kvp.Key.segments.Count) { continue; } Fx.Assert(arrayIndex < a.Length, "We made enough room for all the items"); a[arrayIndex++] = kvp.Key; } // Ensure that queries disambiguate (if needed) : if (arrayIndex > 0) { UriTemplateHelpers.DisambiguateSamePath(a, 0, arrayIndex, allowDuplicateEquivalentUriTemplates); } }
UriTemplatePathPartiallyEquivalentSet star; // matches any "extra/path/segments" at the end UriTemplateTrieNode(int depth) { this.depth = depth; this.nextLiteralSegment = null; this.nextCompoundSegment = null; this.finalLiteralSegment = null; this.finalCompoundSegment = null; this.finalVariableSegment = new UriTemplatePathPartiallyEquivalentSet(depth + 1); this.star = new UriTemplatePathPartiallyEquivalentSet(depth); this.endOfPath = new UriTemplatePathPartiallyEquivalentSet(depth); }
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 AddFinalCompoundSegment(UriTemplateCompoundPathSegment cps, KeyValuePair <UriTemplate, object> kvp) { if (this.finalCompoundSegment == null) { this.finalCompoundSegment = new AscendingSortedCompoundSegmentsCollection <UriTemplatePathPartiallyEquivalentSet>(); } UriTemplatePathPartiallyEquivalentSet set = this.finalCompoundSegment.Find(cps); if (set == null) { set = new UriTemplatePathPartiallyEquivalentSet(this.depth + 1); this.finalCompoundSegment.Add(cps, set); } set.Items.Add(kvp); }
void AddFinalCompoundSegment(UriTemplateCompoundPathSegment cps, KeyValuePair <UriTemplate, object> kvp) { Fx.Assert(cps != null, "must be - based on the segment nature"); if (this.finalCompoundSegment == null) { this.finalCompoundSegment = new AscendingSortedCompoundSegmentsCollection <UriTemplatePathPartiallyEquivalentSet>(); } UriTemplatePathPartiallyEquivalentSet pes = this.finalCompoundSegment.Find(cps); if (pes == null) { pes = new UriTemplatePathPartiallyEquivalentSet(this.depth + 1); this.finalCompoundSegment.Add(cps, pes); } pes.Items.Add(kvp); }
private void AddFinalLiteralSegment(UriTemplateLiteralPathSegment lps, KeyValuePair <UriTemplate, object> kvp) { if ((this.finalLiteralSegment != null) && this.finalLiteralSegment.ContainsKey(lps)) { this.finalLiteralSegment[lps].Items.Add(kvp); } else { if (this.finalLiteralSegment == null) { this.finalLiteralSegment = new Dictionary <UriTemplateLiteralPathSegment, UriTemplatePathPartiallyEquivalentSet>(); } UriTemplatePathPartiallyEquivalentSet set = new UriTemplatePathPartiallyEquivalentSet(this.depth + 1); set.Items.Add(kvp); this.finalLiteralSegment.Add(lps, set); } }
void AddFinalLiteralSegment(UriTemplateLiteralPathSegment lps, KeyValuePair <UriTemplate, object> kvp) { Fx.Assert(lps != null, "must be - based on the segment nature"); if (this.finalLiteralSegment != null && this.finalLiteralSegment.ContainsKey(lps)) { this.finalLiteralSegment[lps].Items.Add(kvp); } else { if (this.finalLiteralSegment == null) { this.finalLiteralSegment = new Dictionary <UriTemplateLiteralPathSegment, UriTemplatePathPartiallyEquivalentSet>(); } UriTemplatePathPartiallyEquivalentSet pes = new UriTemplatePathPartiallyEquivalentSet(this.depth + 1); pes.Items.Add(kvp); this.finalLiteralSegment.Add(lps, pes); } }
private static void Validate(UriTemplatePathPartiallyEquivalentSet pes, bool allowDuplicateEquivalentUriTemplates) { if (pes.Items.Count >= 2) { for (int i = 0; i < (pes.Items.Count - 1); i++) { } UriTemplate[] array = new UriTemplate[pes.Items.Count]; int b = 0; foreach (KeyValuePair <UriTemplate, object> pair in pes.Items) { if (pes.SegmentsCount >= pair.Key.segments.Count) { array[b++] = pair.Key; } } if (b > 0) { UriTemplateHelpers.DisambiguateSamePath(array, 0, b, allowDuplicateEquivalentUriTemplates); } } }
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 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); }