Move TreeEnumerator to shared source (#494)
This commit is contained in:
parent
b67c63927c
commit
e2bcefc3d0
|
|
@ -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<UrlMatchingNode>
|
||||||
|
{
|
||||||
|
private readonly Stack<UrlMatchingNode> _stack;
|
||||||
|
private readonly PathTokenizer _tokenizer;
|
||||||
|
|
||||||
|
public TreeEnumerator(UrlMatchingNode root, PathTokenizer tokenizer)
|
||||||
|
{
|
||||||
|
_stack = new Stack<UrlMatchingNode>();
|
||||||
|
_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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
@ -52,7 +51,7 @@ namespace Microsoft.AspNetCore.Dispatcher
|
||||||
var tree = cache.Trees[i];
|
var tree = cache.Trees[i];
|
||||||
var tokenizer = new PathTokenizer(context.HttpContext.Request.Path);
|
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())
|
while (treenumerator.MoveNext())
|
||||||
{
|
{
|
||||||
|
|
@ -433,108 +432,6 @@ namespace Microsoft.AspNetCore.Dispatcher
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct Treenumerator : IEnumerator<UrlMatchingNode>
|
|
||||||
{
|
|
||||||
private readonly Stack<UrlMatchingNode> _stack;
|
|
||||||
private readonly PathTokenizer _tokenizer;
|
|
||||||
|
|
||||||
public Treenumerator(UrlMatchingNode root, PathTokenizer tokenizer)
|
|
||||||
{
|
|
||||||
_stack = new Stack<UrlMatchingNode>();
|
|
||||||
_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)
|
protected override void InitializeServices(IServiceProvider services)
|
||||||
{
|
{
|
||||||
_constraintFactory = services.GetRequiredService<IConstraintFactory>();
|
_constraintFactory = services.GetRequiredService<IConstraintFactory>();
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Text.Encodings.Web;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Dispatcher;
|
using Microsoft.AspNetCore.Dispatcher;
|
||||||
using Microsoft.AspNetCore.Dispatcher.Internal;
|
using Microsoft.AspNetCore.Dispatcher.Internal;
|
||||||
|
|
@ -13,7 +10,6 @@ using Microsoft.AspNetCore.Routing.Internal;
|
||||||
using Microsoft.AspNetCore.Routing.Logging;
|
using Microsoft.AspNetCore.Routing.Logging;
|
||||||
using Microsoft.AspNetCore.Routing.Template;
|
using Microsoft.AspNetCore.Routing.Template;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.ObjectPool;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Tree
|
namespace Microsoft.AspNetCore.Routing.Tree
|
||||||
{
|
{
|
||||||
|
|
@ -217,112 +213,9 @@ namespace Microsoft.AspNetCore.Routing.Tree
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct TreeEnumerator : IEnumerator<UrlMatchingNode>
|
|
||||||
{
|
|
||||||
private readonly Stack<UrlMatchingNode> _stack;
|
|
||||||
private readonly PathTokenizer _tokenizer;
|
|
||||||
|
|
||||||
public TreeEnumerator(UrlMatchingNode root, PathTokenizer tokenizer)
|
|
||||||
{
|
|
||||||
_stack = new Stack<UrlMatchingNode>();
|
|
||||||
_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)
|
private VirtualPathData GetVirtualPathForNamedRoute(VirtualPathContext context)
|
||||||
{
|
{
|
||||||
OutboundMatch match;
|
if (_namedEntries.TryGetValue(context.RouteName, out var match))
|
||||||
if (_namedEntries.TryGetValue(context.RouteName, out match))
|
|
||||||
{
|
{
|
||||||
var path = GenerateVirtualPath(context, match.Entry, match.TemplateBinder);
|
var path = GenerateVirtualPath(context, match.Entry, match.TemplateBinder);
|
||||||
if (path != null)
|
if (path != null)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue