Move TreeEnumerator to shared source (#494)

This commit is contained in:
Jass Bagga 2017-11-15 11:17:59 -08:00 committed by GitHub
parent b67c63927c
commit e2bcefc3d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 121 additions and 212 deletions

View File

@ -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;
}
}
}

View File

@ -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<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)
{
_constraintFactory = services.GetRequiredService<IConstraintFactory>();

View File

@ -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<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)
{
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)