public unsafe void Implementation()
        {
            var path     = Input;
            var segments = stackalloc PathSegment[MaxCount];

            FastPathTokenizer.Tokenize(path, segments, MaxCount);
        }
Example #2
0
        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]);
        }
Example #9
0
        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);
        }