public unsafe void Implementation() { var path = Input; var segments = stackalloc PathSegment[MaxCount]; FastPathTokenizer.Tokenize(path, segments, MaxCount); }
public unsafe override Task MatchAsync(HttpContext httpContext, IEndpointFeature feature) { if (httpContext == null) { throw new ArgumentNullException(nameof(httpContext)); } if (feature == null) { throw new ArgumentNullException(nameof(feature)); } var states = _states; var current = 0; var path = httpContext.Request.Path.Value; var buffer = stackalloc PathSegment[32]; var count = FastPathTokenizer.Tokenize(path, buffer, 32); for (var i = 0; i < count; i++) { current = states[current].Transitions.GetDestination(buffer, i, path); } var matches = new List <(Endpoint, RouteValueDictionary)>(); var candidates = states[current].Matches; for (var i = 0; i < candidates.Length; i++) { var values = new RouteValueDictionary(); var parameters = candidates[i].Parameters; if (parameters != null) { for (var j = 0; j < parameters.Length; j++) { var parameter = parameters[j]; if (parameter != null && buffer[j].Length == 0) { goto notmatch; } else if (parameter != null) { var value = path.Substring(buffer[j].Start, buffer[j].Length); values.Add(parameter, value); } } } matches.Add((candidates[i].Endpoint, values)); notmatch :; } feature.Endpoint = matches.Count == 0 ? null : matches[0].Item1; feature.Values = matches.Count == 0 ? null : matches[0].Item2; return(Task.CompletedTask); }
[Fact] // Note: tokenizing a truly empty string is undefined. public void Tokenize_EmptyPath() { // Arrange var segments = stackalloc PathSegment[32]; // Act var count = FastPathTokenizer.Tokenize("/", segments, 1); // Assert Assert.Equal(0, count); }
public void Tokenize_SingleSegment() { // Arrange var segments = stackalloc PathSegment[32]; // Act var count = FastPathTokenizer.Tokenize("/abc", segments, 1); // Assert Assert.Equal(1, count); Assert.Equal(new PathSegment(1, 3), segments[0]); }
public void Tokenize_EmptySegments() { // Arrange var segments = stackalloc PathSegment[32]; // Act var count = FastPathTokenizer.Tokenize("///c", segments, 3); // Assert Assert.Equal(3, count); Assert.Equal(new PathSegment(1, 0), segments[0]); Assert.Equal(new PathSegment(2, 0), segments[1]); Assert.Equal(new PathSegment(3, 1), segments[2]); }
public void Tokenize_LongerSegments() { // Arrange var segments = stackalloc PathSegment[32]; // Act var count = FastPathTokenizer.Tokenize("/aaa/bb/ccccc", segments, 3); // Assert Assert.Equal(3, count); Assert.Equal(new PathSegment(1, 3), segments[0]); Assert.Equal(new PathSegment(5, 2), segments[1]); Assert.Equal(new PathSegment(8, 5), segments[2]); }
[Fact] // Empty trailing / is ignored public void Tokenize_WithSomeSegments_TrailingSlash() { // Arrange var segments = stackalloc PathSegment[32]; // Act var count = FastPathTokenizer.Tokenize("/a/b/c/", segments, 3); // Assert Assert.Equal(3, count); Assert.Equal(new PathSegment(1, 1), segments[0]); Assert.Equal(new PathSegment(3, 1), segments[1]); Assert.Equal(new PathSegment(5, 1), segments[2]); }
public void Tokenize_TooManySegments() { // Arrange var segments = stackalloc PathSegment[32]; // Act var count = FastPathTokenizer.Tokenize("/a/b/c/d", segments, 3); // Assert Assert.Equal(3, count); Assert.Equal(new PathSegment(1, 1), segments[0]); Assert.Equal(new PathSegment(3, 1), segments[1]); Assert.Equal(new PathSegment(5, 1), segments[2]); }
public unsafe override Task MatchAsync(HttpContext httpContext, IEndpointFeature feature) { if (httpContext == null) { throw new ArgumentNullException(nameof(httpContext)); } if (feature == null) { throw new ArgumentNullException(nameof(feature)); } var state = _state; var path = httpContext.Request.Path.Value; var buffer = stackalloc PathSegment[32]; var count = FastPathTokenizer.Tokenize(path, buffer, 32); var i = 0; var candidates = new List <Candidate>(); while (i < state.Instructions.Length) { var instruction = state.Instructions[i]; switch (instruction.Code) { case InstructionCode.Accept: { if (count == instruction.Depth) { candidates.Add(state.Candidates[instruction.Payload]); } i++; break; } case InstructionCode.Branch: { var table = state.Tables[instruction.Payload]; i = table.GetDestination(buffer, count, path); break; } case InstructionCode.Jump: { i = instruction.Payload; break; } } } var matches = new List <(Endpoint, RouteValueDictionary)>(); for (i = 0; i < candidates.Count; i++) { var values = new RouteValueDictionary(); var parameters = candidates[i].Parameters; if (parameters != null) { for (var j = 0; j < parameters.Length; j++) { var parameter = parameters[j]; if (parameter != null && buffer[j].Length == 0) { goto notmatch; } else if (parameter != null) { var value = path.Substring(buffer[j].Start, buffer[j].Length); values.Add(parameter, value); } } } matches.Add((candidates[i].Endpoint, values)); notmatch :; } feature.Endpoint = matches.Count == 0 ? null : matches[0].Item1; feature.Values = matches.Count == 0 ? null : matches[0].Item2; return(Task.CompletedTask); }