From e2bcefc3d0bca1fbe59594cacb10f463dd0e46d4 Mon Sep 17 00:00:00 2001 From: Jass Bagga Date: Wed, 15 Nov 2017 11:17:59 -0800 Subject: [PATCH] Move TreeEnumerator to shared source (#494) --- .../TreeEnumerator.cs | 119 ++++++++++++++++++ .../Tree/TreeMatcher.cs | 105 +--------------- .../Tree/TreeRouter.cs | 109 +--------------- 3 files changed, 121 insertions(+), 212 deletions(-) create mode 100644 shared/Microsoft.AspNetCore.Routing.UrlMatchingTree.Sources/TreeEnumerator.cs diff --git a/shared/Microsoft.AspNetCore.Routing.UrlMatchingTree.Sources/TreeEnumerator.cs b/shared/Microsoft.AspNetCore.Routing.UrlMatchingTree.Sources/TreeEnumerator.cs new file mode 100644 index 0000000000..916b154ab0 --- /dev/null +++ b/shared/Microsoft.AspNetCore.Routing.UrlMatchingTree.Sources/TreeEnumerator.cs @@ -0,0 +1,119 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using Microsoft.AspNetCore.Dispatcher.Internal; + +#if ROUTING +namespace Microsoft.AspNetCore.Routing.Tree +#elif DISPATCHER +namespace Microsoft.AspNetCore.Dispatcher +#else +#error +#endif +{ + internal struct TreeEnumerator : IEnumerator + { + private readonly Stack _stack; + private readonly PathTokenizer _tokenizer; + + public TreeEnumerator(UrlMatchingNode root, PathTokenizer tokenizer) + { + _stack = new Stack(); + _tokenizer = tokenizer; + Current = null; + + _stack.Push(root); + } + + public UrlMatchingNode Current { get; private set; } + + object IEnumerator.Current => Current; + + public void Dispose() + { + } + + public bool MoveNext() + { + if (_stack == null) + { + return false; + } + + while (_stack.Count > 0) + { + var next = _stack.Pop(); + + // In case of wild card segment, the request path segment length can be greater + // Example: + // Template: a/{*path} + // Request Url: a/b/c/d + if (next.IsCatchAll && next.Matches.Count > 0) + { + Current = next; + return true; + } + + // Next template has the same length as the url we are trying to match + // The only possible matching segments are either our current matches or + // any catch-all segment after this segment in which the catch all is empty. + else if (next.Depth >= _tokenizer.Count) + { + if (next.Matches.Count > 0) + { + Current = next; + return true; + } + else + { + // We can stop looking as any other child node from this node will be + // either a literal, a constrained parameter or a parameter. + // (Catch alls and constrained catch alls will show up as candidate matches). + continue; + } + } + + if (next.CatchAlls != null) + { + _stack.Push(next.CatchAlls); + } + + if (next.ConstrainedCatchAlls != null) + { + _stack.Push(next.ConstrainedCatchAlls); + } + + if (next.Parameters != null) + { + _stack.Push(next.Parameters); + } + + if (next.ConstrainedParameters != null) + { + _stack.Push(next.ConstrainedParameters); + } + + if (next.Literals.Count > 0) + { + Debug.Assert(next.Depth < _tokenizer.Count); + if (next.Literals.TryGetValue(_tokenizer[next.Depth].Value, out var node)) + { + _stack.Push(node); + } + } + } + + return false; + } + + public void Reset() + { + _stack.Clear(); + Current = null; + } + } + +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Dispatcher/Tree/TreeMatcher.cs b/src/Microsoft.AspNetCore.Dispatcher/Tree/TreeMatcher.cs index ea96a14509..836ccaf22b 100644 --- a/src/Microsoft.AspNetCore.Dispatcher/Tree/TreeMatcher.cs +++ b/src/Microsoft.AspNetCore.Dispatcher/Tree/TreeMatcher.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -52,7 +51,7 @@ namespace Microsoft.AspNetCore.Dispatcher var tree = cache.Trees[i]; var tokenizer = new PathTokenizer(context.HttpContext.Request.Path); - var treenumerator = new Treenumerator(tree.Root, tokenizer); + var treenumerator = new TreeEnumerator(tree.Root, tokenizer); while (treenumerator.MoveNext()) { @@ -433,108 +432,6 @@ namespace Microsoft.AspNetCore.Dispatcher } } - private struct Treenumerator : IEnumerator - { - private readonly Stack _stack; - private readonly PathTokenizer _tokenizer; - - public Treenumerator(UrlMatchingNode root, PathTokenizer tokenizer) - { - _stack = new Stack(); - _tokenizer = tokenizer; - Current = null; - - _stack.Push(root); - } - - public UrlMatchingNode Current { get; private set; } - - object IEnumerator.Current => Current; - - public void Dispose() - { - } - - public bool MoveNext() - { - if (_stack == null) - { - return false; - } - - while (_stack.Count > 0) - { - var next = _stack.Pop(); - - // In case of wild card segment, the request path segment length can be greater - // Example: - // Template: a/{*path} - // Request Url: a/b/c/d - if (next.IsCatchAll && next.Matches.Count > 0) - { - Current = next; - return true; - } - - // Next template has the same length as the url we are trying to match - // The only possible matching segments are either our current matches or - // any catch-all segment after this segment in which the catch all is empty. - else if (next.Depth >= _tokenizer.Count) - { - if (next.Matches.Count > 0) - { - Current = next; - return true; - } - else - { - // We can stop looking as any other child node from this node will be - // either a literal, a constrained parameter or a parameter. - // (Catch alls and constrained catch alls will show up as candidate matches). - continue; - } - } - - if (next.CatchAlls != null) - { - _stack.Push(next.CatchAlls); - } - - if (next.ConstrainedCatchAlls != null) - { - _stack.Push(next.ConstrainedCatchAlls); - } - - if (next.Parameters != null) - { - _stack.Push(next.Parameters); - } - - if (next.ConstrainedParameters != null) - { - _stack.Push(next.ConstrainedParameters); - } - - if (next.Literals.Count > 0) - { - Debug.Assert(next.Depth < _tokenizer.Count); - if (next.Literals.TryGetValue(_tokenizer[next.Depth].Value, out var node)) - { - _stack.Push(node); - } - } - } - - return false; - } - - public void Reset() - { - _stack.Clear(); - Current = null; - } - } - protected override void InitializeServices(IServiceProvider services) { _constraintFactory = services.GetRequiredService(); diff --git a/src/Microsoft.AspNetCore.Routing/Tree/TreeRouter.cs b/src/Microsoft.AspNetCore.Routing/Tree/TreeRouter.cs index e7ab54341e..9152dde3bb 100644 --- a/src/Microsoft.AspNetCore.Routing/Tree/TreeRouter.cs +++ b/src/Microsoft.AspNetCore.Routing/Tree/TreeRouter.cs @@ -2,10 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections; using System.Collections.Generic; -using System.Diagnostics; -using System.Text.Encodings.Web; using System.Threading.Tasks; using Microsoft.AspNetCore.Dispatcher; using Microsoft.AspNetCore.Dispatcher.Internal; @@ -13,7 +10,6 @@ using Microsoft.AspNetCore.Routing.Internal; using Microsoft.AspNetCore.Routing.Logging; using Microsoft.AspNetCore.Routing.Template; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.ObjectPool; namespace Microsoft.AspNetCore.Routing.Tree { @@ -217,112 +213,9 @@ namespace Microsoft.AspNetCore.Routing.Tree } } - private struct TreeEnumerator : IEnumerator - { - private readonly Stack _stack; - private readonly PathTokenizer _tokenizer; - - public TreeEnumerator(UrlMatchingNode root, PathTokenizer tokenizer) - { - _stack = new Stack(); - _tokenizer = tokenizer; - Current = null; - - _stack.Push(root); - } - - public UrlMatchingNode Current { get; private set; } - - object IEnumerator.Current => Current; - - public void Dispose() - { - } - - public bool MoveNext() - { - if (_stack == null) - { - return false; - } - - while (_stack.Count > 0) - { - var next = _stack.Pop(); - - // In case of wild card segment, the request path segment length can be greater - // Example: - // Template: a/{*path} - // Request Url: a/b/c/d - if (next.IsCatchAll && next.Matches.Count > 0) - { - Current = next; - return true; - } - // Next template has the same length as the url we are trying to match - // The only possible matching segments are either our current matches or - // any catch-all segment after this segment in which the catch all is empty. - else if (next.Depth == _tokenizer.Count) - { - if (next.Matches.Count > 0) - { - Current = next; - return true; - } - else - { - // We can stop looking as any other child node from this node will be - // either a literal, a constrained parameter or a parameter. - // (Catch alls and constrained catch alls will show up as candidate matches). - continue; - } - } - - if (next.CatchAlls != null) - { - _stack.Push(next.CatchAlls); - } - - if (next.ConstrainedCatchAlls != null) - { - _stack.Push(next.ConstrainedCatchAlls); - } - - if (next.Parameters != null) - { - _stack.Push(next.Parameters); - } - - if (next.ConstrainedParameters != null) - { - _stack.Push(next.ConstrainedParameters); - } - - if (next.Literals.Count > 0) - { - UrlMatchingNode node; - Debug.Assert(next.Depth < _tokenizer.Count); - if (next.Literals.TryGetValue(_tokenizer[next.Depth].Value, out node)) - { - _stack.Push(node); - } - } - } - - return false; - } - - public void Reset() - { - _stack.Clear(); - Current = null; - } - } - private VirtualPathData GetVirtualPathForNamedRoute(VirtualPathContext context) { - OutboundMatch match; - if (_namedEntries.TryGetValue(context.RouteName, out match)) + if (_namedEntries.TryGetValue(context.RouteName, out var match)) { var path = GenerateVirtualPath(context, match.Entry, match.TemplateBinder); if (path != null)