/// <summary>
        /// Returns a value indicating whether any of the specified characters occurs within this string.
        /// </summary>
        /// <param name="value">The current string.</param>
        /// <param name="characters">The characters to seek.</param>
        /// <param name="comparisonType">One of the enumeration values that specifies the rules for the character matching.</param>
        /// <returns>
        /// <see langword="true" /> if <i>any</i> of the specified characters occurs within the string; otherwise,
        /// <see langword="false" />.
        /// </returns>
        /// <exception cref="T:System.ArgumentNullException">
        /// <paramref name="characters" /> is <see langword="null" />.
        /// </exception>
        /// <exception cref="T:System.ArgumentException">
        /// <paramref name="comparisonType" /> is not a valid <see cref="CharacterComparison" /> value.
        /// </exception>
        public static bool ContainsAny(this string?value, CharacterComparison comparisonType, params char[] characters)
        {
            if (value is null)
            {
                return(false);
            }

            if (characters is null)
            {
                throw new ArgumentNullException(nameof(characters));
            }

            var comparer = CharacterComparer.FromComparison(comparisonType);

            if (characters.Length == 0)
            {
                return(false);
            }

            foreach (var t in characters)
            {
                foreach (var c in value.AsSpan())
                {
                    if (comparer.Compare(c, t) == 0)
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
        /// <summary>
        /// Gets the beginning of a string value until the <i>first</i> occurrence of the given <paramref name="match"/>
        /// or the whole string when the <paramref name="match"/> is not present.
        /// </summary>
        /// <param name="value">The value that might contain the match.</param>
        /// <param name="match">The string to search for.</param>
        /// <param name="comparisonType">One of the enumeration values that specifies the rules for the character matching.</param>
        /// <returns>The sub-string from beginning till the found match or the whole string if the match is not present.</returns>
        /// <exception cref="T:System.ArgumentNullException">
        /// <paramref name="value" /> is <see langword="null" />.
        /// </exception>
        /// <exception cref="T:System.ArgumentException">
        /// <paramref name="comparisonType" /> is not a valid <see cref="T:System.StringComparison" /> value.
        /// </exception>
        public static string Until(this string?value, char match, CharacterComparison comparisonType)
        {
            if (value is null)
            {
                throw new ArgumentNullException(nameof(value));
            }

            var characterComparer = CharacterComparer.FromComparison(comparisonType);
            var spannedValue      = value.AsSpan();

            // do not allocate only find a window of match inside value
            var matchIndex     = -1;
            var iterationIndex = 0;

            foreach (var c in spannedValue)
            {
                if (characterComparer.Compare(c, match) == 0)
                {
                    matchIndex = iterationIndex;
                    break;
                }
                iterationIndex++;
            }

            if (matchIndex < 0)
            {
                return(value);
            }

            // do not substring to avoid re-iterating from 0 to match-index
            // just pointer slice the left side of the string and re-allocate
            // into new string
            return(spannedValue.Slice(0, matchIndex).ToString());
        }
        /// <summary>
        /// Returns a value indicating whether all of the specified characters occur within this string.
        /// </summary>
        /// <param name="value">The current string.</param>
        /// <param name="characters">The characters to seek.</param>
        /// <param name="comparisonType">One of the enumeration values that specifies the rules for the character matching.</param>
        /// <returns>
        /// <see langword="true" /> if <i>all</i> of the specified characters occur within the string; otherwise,
        /// <see langword="false" />.
        /// </returns>
        /// <exception cref="T:System.ArgumentNullException">
        /// <paramref name="characters" /> is <see langword="null" />.
        /// </exception>
        /// <exception cref="T:System.ArgumentException">
        /// <paramref name="comparisonType" /> is not a valid <see cref="CharacterComparison" /> value.
        /// </exception>
        public static bool ContainsAll(this string?value, CharacterComparison comparisonType, params char[] characters)
        {
            if (value is null)
            {
                return(false);
            }

            if (characters is null)
            {
                throw new ArgumentNullException(nameof(characters));
            }

            var characterComparer = CharacterComparer.FromComparison(comparisonType);

            if (characters.Length == 0)
            {
                return(false);
            }

            // implementation that avoid allocation of extra strings or char arrays
            // but pay for that by double iterating over string length item at worst case
            var lookup = new bool[characters.Length];

            for (var i = 0; i < characters.Length; i++)
            {
                foreach (var c in value.AsSpan())
                {
                    if (characterComparer.Compare(c, characters[i]) == 0)
                    {
                        lookup[i] = true;
                    }
                }
            }

            for (var i = 0; i < characters.Length; i++)
            {
                if (!lookup[i])
                {
                    return(false);
                }
            }

            return(true);
        }