public void SplitsEmptyStringsIntoNothing()
    {
        var value      = string.Empty;
        var enumerator = new SpanSplitEnumerator(value);

        Assert.False(enumerator.MoveNext());
    }
예제 #2
0
    /// <summary>
    /// Searches the command tree for a command that matches the shape of the given command name string, and its
    /// named parameters. In this case, positional parameters are not supported; they are matched against their
    /// in-source names instead.
    /// </summary>
    /// <param name="commandNameString">The named command string.</param>
    /// <param name="namedParameters">The named parameters.</param>
    /// <param name="tokenizerOptions">The tokenizer options to use.</param>
    /// <param name="searchOptions">A set of search options.</param>
    /// <returns>The matching command nodes.</returns>
    public IEnumerable <BoundCommandNode> Search
    (
        ReadOnlySpan <char> commandNameString,
        IReadOnlyDictionary <string, IReadOnlyList <string> > namedParameters,
        TokenizerOptions?tokenizerOptions = null,
        TreeSearchOptions?searchOptions   = null
    )
    {
        tokenizerOptions ??= new TokenizerOptions();
        searchOptions ??= new TreeSearchOptions();

        var splitEnumerator = new SpanSplitEnumerator(commandNameString, tokenizerOptions);

        var matchingNodes = Search(this.Root, splitEnumerator, searchOptions);
        var boundNodes    = matchingNodes
                            .Select
                            (
            c =>
            (
                IsSuccess: c.TryBind(namedParameters, out var boundCommandNode, searchOptions),
                BoundCommandNode: boundCommandNode
            )
                            )
                            .Where(kvp => kvp.IsSuccess)
                            .Select(kvp => kvp.BoundCommandNode !);

        return(boundNodes);
    }
예제 #3
0
        /// <summary>
        /// Creates a new pattern scan target given a string representation of a pattern.
        /// </summary>
        /// <param name="stringPattern">
        ///     The pattern to look for inside the given region.
        ///     Example: "11 22 33 ?? 55".
        ///     Key: ?? represents a byte that should be ignored, anything else if a hex byte. i.e. 11 represents 0x11, 1F represents 0x1F.
        /// </param>
        public SimplePatternScanData(string stringPattern)
        {
#if SPAN_API
            var enumerator = new SpanSplitEnumerator <char>(stringPattern, ' ');
#else
            var enumerator = new SpanSplitEnumerator <char>(new ReadOnlySpan <char>(stringPattern.ToCharArray()), ' ');
#endif
            var questionMarkFlag = new ReadOnlySpan <char>(_maskIgnore);

            lock (_buildLock)
            {
                _maskBuilder.Clear();
                _bytes.Clear();

                while (enumerator.MoveNext())
                {
                    if (enumerator.Current.Equals(questionMarkFlag, StringComparison.Ordinal))
                    {
                        _maskBuilder.Add(0x0);
                    }
                    else
                    {
#if SPAN_API
                        _bytes.Add(byte.Parse(enumerator.Current, NumberStyles.AllowHexSpecifier));
#else
                        _bytes.Add(byte.Parse(enumerator.Current.ToString(), NumberStyles.AllowHexSpecifier));
#endif
                        _maskBuilder.Add(0x1);
                    }
                }

                Mask  = _maskBuilder.ToArray();
                Bytes = _bytes.ToArray();
            }
        }
예제 #4
0
        public void StringSplitterEmpty()
        {
            string pattern         = "";
            var    splitEnumerator = new SpanSplitEnumerator <char>(pattern.ToCharArray(), ' ');

            Assert.True(splitEnumerator.MoveNext());
            Assert.Equal("", splitEnumerator.Current.ToString());
            Assert.False(splitEnumerator.MoveNext());
        }
    public void SplitsSingleQuotedTermIntoSingleSegment()
    {
        var value      = "\"one term\"";
        var enumerator = new SpanSplitEnumerator(value);

        Assert.True(enumerator.MoveNext());
        Assert.Equal(value, enumerator.Current.ToString());
        Assert.False(enumerator.MoveNext());
    }
    public void SplitsSingleWordIntoSingleSegment()
    {
        var value      = "bunt";
        var enumerator = new SpanSplitEnumerator(value);

        Assert.True(enumerator.MoveNext());
        Assert.Equal(value, enumerator.Current.ToString());
        Assert.False(enumerator.MoveNext());
    }
예제 #7
0
    /// <summary>
    /// Initializes a new instance of the <see cref="TokenizingEnumerator"/> struct.
    /// </summary>
    /// <param name="value">The value to tokenize.</param>
    /// <param name="tokenizerOptions">The tokenizer options.</param>
    public TokenizingEnumerator(ReadOnlySpan <char> value, TokenizerOptions?tokenizerOptions = null)
    {
        _tokenizerOptions = tokenizerOptions ?? new TokenizerOptions();

        _isInCombinedShortNameSegment = default;
        _segment         = default;
        _splitEnumerator = new SpanSplitEnumerator(value, _tokenizerOptions);
        _current         = default;
    }
예제 #8
0
 private static void AssertEqual <T>(T[][] items, ReadOnlySpan <T> orig, SpanSplitEnumerator <T> source) where T : IEquatable <T>
 {
     foreach (var item in items)
     {
         Assert.True(source.MoveNext());
         var slice = orig[source.Current];
         Assert.Equal(item, slice.ToArray());
     }
     Assert.False(source.MoveNext());
 }
예제 #9
0
        public SpanSplitEnumerator <char> SpanSplit()
        {
            var enumerator = new SpanSplitEnumerator <char>(_pattern, ' ');

            while (enumerator.MoveNext())
            {
            }

            return(enumerator);
        }
    public void SplitsMultipleWordsIntoMultipleSegments()
    {
        var value      = "a b c d e f g";
        var enumerator = new SpanSplitEnumerator(value);

        for (var i = 0; i < 7; i++)
        {
            Assert.True(enumerator.MoveNext());
            Assert.Equal(value[i * 2].ToString(), enumerator.Current.ToString());
        }

        Assert.False(enumerator.MoveNext());
    }
예제 #11
0
    /// <summary>
    /// Performs a depth-first search of the given node.
    /// </summary>
    /// <param name="parentNode">The node.</param>
    /// <param name="enumerator">The splitting enumerator.</param>
    /// <param name="searchOptions">A set of search options.</param>
    /// <returns>The matching nodes.</returns>
    private IEnumerable <CommandNode> Search
    (
        IParentNode parentNode,
        SpanSplitEnumerator enumerator,
        TreeSearchOptions searchOptions
    )
    {
        var commandNodes = new List <CommandNode>();

        foreach (var child in parentNode.Children)
        {
            if (!IsNodeMatch(child, enumerator, searchOptions))
            {
                continue;
            }

            switch (child)
            {
            case CommandNode commandNode:
            {
                commandNodes.Add(commandNode);
                break;
            }

            case IParentNode groupNode:
            {
                // Consume the token
                if (!enumerator.MoveNext())
                {
                    // No more tokens, so we can't continue searching
                    return(commandNodes);
                }

                var nestedResults = Search(groupNode, enumerator, searchOptions);
                commandNodes.AddRange(nestedResults);

                continue;
            }

            default:
            {
                throw new InvalidOperationException
                      (
                          "Unknown node type encountered; tree is invalid and the search cannot continue."
                      );
            }
            }
        }

        return(commandNodes);
    }
        public static int Last <T>(this SpanSplitEnumerator <T> enumerator, out ReadOnlySpan <T> last)
            where T : IEquatable <T>
        {
            int cnt = 0;

            last = null;

            while (enumerator.MoveNext())
            {
                last = enumerator.Current;
                cnt++;
            }

            return(cnt);
        }
예제 #13
0
        public static void DefaultSpanSplitEnumeratorBehavior()
        {
            var charSpanEnumerator = new SpanSplitEnumerator <string>();

            Assert.Equal(new Range(0, 0), charSpanEnumerator.Current);
            Assert.False(charSpanEnumerator.MoveNext());

            // Implicit DoesNotThrow assertion
            charSpanEnumerator.GetEnumerator();

            var stringSpanEnumerator = new SpanSplitEnumerator <string>();

            Assert.Equal(new Range(0, 0), stringSpanEnumerator.Current);
            Assert.False(stringSpanEnumerator.MoveNext());
            stringSpanEnumerator.GetEnumerator();
        }
예제 #14
0
        public void StringSplitterNormal()
        {
            string pattern = "11 22 33 ?? 55";

            string[] splitSegments = { "11", "22", "33", "??", "55" };

            // Note: ToCharArray can be omitted in .NET Standard 2.1 and Core 3.0
            var splitEnumerator = new SpanSplitEnumerator <char>(pattern.ToCharArray(), ' ');

            for (int x = 0; x < splitSegments.Length; x++)
            {
                Assert.True(splitEnumerator.MoveNext());
                Assert.Equal(splitSegments[x], splitEnumerator.Current.ToString());
            }

            Assert.False(splitEnumerator.MoveNext());
        }
예제 #15
0
        public static void ValidateArguments_OverloadWithROSSeparator()
        {
            // Default buffer
            ReadOnlySpan <char> buffer = default;

            SpanSplitEnumerator <char> enumerator = buffer.Split(default(char));

            Assert.True(enumerator.MoveNext());
            Assert.Equal(enumerator.Current, new Range(0, 0));
            Assert.False(enumerator.MoveNext());

            enumerator = buffer.Split(' ');
            Assert.True(enumerator.MoveNext());
            Assert.Equal(enumerator.Current, new Range(0, 0));
            Assert.False(enumerator.MoveNext());

            // Empty buffer
            buffer = "";

            enumerator = buffer.Split(default(char));
            Assert.True(enumerator.MoveNext());
            Assert.Equal(enumerator.Current, new Range(0, 0));
            Assert.False(enumerator.MoveNext());

            enumerator = buffer.Split(' ');
            Assert.True(enumerator.MoveNext());
            Assert.Equal(enumerator.Current, new Range(0, 0));
            Assert.False(enumerator.MoveNext());

            // Single whitespace buffer
            buffer = " ";

            enumerator = buffer.Split(default(char));
            Assert.True(enumerator.MoveNext());
            Assert.False(enumerator.MoveNext());

            enumerator = buffer.Split(' ');
            Assert.Equal(new Range(0, 0), enumerator.Current);
            Assert.True(enumerator.MoveNext());
            Assert.Equal(new Range(0, 0), enumerator.Current);
            Assert.True(enumerator.MoveNext());
            Assert.Equal(new Range(1, 1), enumerator.Current);
            Assert.False(enumerator.MoveNext());
        }
예제 #16
0
    /// <summary>
    /// Determines whether a node matches the current state of the enumerator.
    /// </summary>
    /// <param name="node">The node.</param>
    /// <param name="enumerator">The tokenizer.</param>
    /// <param name="searchOptions">A set of search options.</param>
    /// <returns>true if the node matches; otherwise, false.</returns>
    private bool IsNodeMatch(IChildNode node, SpanSplitEnumerator enumerator, TreeSearchOptions searchOptions)
    {
        if (!enumerator.MoveNext())
        {
            return(false);
        }

        if (enumerator.Current.Equals(node.Key, searchOptions.KeyComparison))
        {
            return(true);
        }

        foreach (var alias in node.Aliases)
        {
            if (enumerator.Current.Equals(alias, searchOptions.KeyComparison))
            {
                return(true);
            }
        }

        return(false);
    }
예제 #17
0
        public static void ValidateArguments_OverloadWithoutSeparator()
        {
            ReadOnlySpan <char> buffer = default;

            SpanSplitEnumerator <char> enumerator = buffer.Split();

            Assert.True(enumerator.MoveNext());
            Assert.Equal(new Range(0, 0), enumerator.Current);
            Assert.False(enumerator.MoveNext());

            buffer     = "";
            enumerator = buffer.Split();
            Assert.True(enumerator.MoveNext());
            Assert.Equal(new Range(0, 0), enumerator.Current);
            Assert.False(enumerator.MoveNext());

            buffer     = " ";
            enumerator = buffer.Split();
            Assert.True(enumerator.MoveNext());
            Assert.Equal(new Range(0, 0), enumerator.Current);
            Assert.True(enumerator.MoveNext());
            Assert.Equal(new Range(1, 1), enumerator.Current);
            Assert.False(enumerator.MoveNext());
        }
예제 #18
0
        public static void ValidateArguments_OverloadWithStringSeparator()
        {
            // Default buffer
            ReadOnlySpan <char> buffer = default;

            SpanSplitEnumerator <char> enumerator = buffer.Split(null); // null is treated as empty string

            Assert.True(enumerator.MoveNext());
            Assert.Equal(enumerator.Current, new Range(0, 0));
            Assert.False(enumerator.MoveNext());

            enumerator = buffer.Split("");
            Assert.True(enumerator.MoveNext());
            Assert.Equal(enumerator.Current, new Range(0, 0));
            Assert.False(enumerator.MoveNext());

            enumerator = buffer.Split(" ");
            Assert.True(enumerator.MoveNext());
            Assert.Equal(enumerator.Current, new Range(0, 0));
            Assert.False(enumerator.MoveNext());

            // Empty buffer
            buffer = "";

            enumerator = buffer.Split(null);
            Assert.True(enumerator.MoveNext());
            Assert.Equal(enumerator.Current, new Range(0, 0));
            Assert.False(enumerator.MoveNext());

            enumerator = buffer.Split("");
            Assert.True(enumerator.MoveNext());
            Assert.Equal(enumerator.Current, new Range(0, 0));
            Assert.False(enumerator.MoveNext());

            enumerator = buffer.Split(" ");
            Assert.True(enumerator.MoveNext());
            Assert.Equal(enumerator.Current, new Range(0, 0));
            Assert.False(enumerator.MoveNext());

            // Single whitespace buffer
            buffer = " ";

            enumerator = buffer.Split(null); // null is treated as empty string
            Assert.True(enumerator.MoveNext());
            Assert.Equal(enumerator.Current, new Range(0, 0));
            Assert.True(enumerator.MoveNext());
            Assert.Equal(enumerator.Current, new Range(1, 1));
            Assert.False(enumerator.MoveNext());

            enumerator = buffer.Split("");
            Assert.True(enumerator.MoveNext());
            Assert.Equal(enumerator.Current, new Range(0, 0));
            Assert.True(enumerator.MoveNext());
            Assert.Equal(enumerator.Current, new Range(1, 1));
            Assert.False(enumerator.MoveNext());

            enumerator = buffer.Split(" ");
            Assert.Equal(enumerator.Current, new Range(0, 0));
            Assert.True(enumerator.MoveNext());
            Assert.Equal(enumerator.Current, new Range(0, 0));
            Assert.True(enumerator.MoveNext());
            Assert.Equal(enumerator.Current, new Range(1, 1));
            Assert.False(enumerator.MoveNext());
        }