private static void ThrowIfContainsDelimiter(string value)
{
- if (value.Contains(","))
+ if (value.Contains(",")) // string.Contains(char) is .NetCore2.1+ specific
throw new ConfigurationErrorsException(string.Format(SR.Config_base_value_cannot_contain, ","));
}
return copy;
}
}
-}
\ No newline at end of file
+}
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
+#if !netcoreapp
using System.Linq;
+#endif
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
_dataSourceAfterTrimmingProtocol = (firstIndexOfColon > -1) && ConnectionProtocol != DataSource.Protocol.None
? _workingDataSource.Substring(firstIndexOfColon + 1).Trim() : _workingDataSource;
- if (_dataSourceAfterTrimmingProtocol.Contains("/")) // Pipe paths only allow back slashes
+ // Pipe paths only allow back slashes
+#if netcoreapp
+ if (_dataSourceAfterTrimmingProtocol.Contains('/')) // string.Contains(char) is .NetCore2.1+ specific
+#else
+ if (_dataSourceAfterTrimmingProtocol.Contains("/"))
+#endif
{
if (ConnectionProtocol == DataSource.Protocol.None)
ReportSNIError(SNIProviders.INVALID_PROV);
if (_dataSourceAfterTrimmingProtocol.StartsWith(PipeBeginning) || ConnectionProtocol == Protocol.NP)
{
// If the data source is "np:servername"
- if (!_dataSourceAfterTrimmingProtocol.Contains(BackSlashSeparator))
+ if (!_dataSourceAfterTrimmingProtocol.Contains(BackSlashSeparator)) // string.Contains(char) is .NetCore2.1+ specific. Else uses Linq (perf warning)
{
PipeHostName = ServerName = _dataSourceAfterTrimmingProtocol;
InferLocalServerName();
{
string majorVersion = majorVersions[i];
- if (majorVersion.Length > 1 && majorVersion[0] == 'v' && majorVersion.Contains("."))
+ if (majorVersion.Length > 1 && majorVersion[0] == 'v' && majorVersion.Contains(".")) // string.Contains(char) is .NetCore2.1+ specific
{
int[] currentVersion = new int[] { -1, -1, -1 };
string majorVersion = majorVersions[i];
// If this looks like a key of the form v{something}.{something}, we should see if it's a usable build.
- if (majorVersion.Length > 1 && majorVersion[0] == 'v' && majorVersion.Contains("."))
+ if (majorVersion.Length > 1 && majorVersion[0] == 'v' && majorVersion.Contains(".")) // string.Contains(char) is .NetCore2.1+ specific
{
int[] currentVersion = new int[] { -1, -1, -1 };
int x_resolution, y_resolution;
try
{
- if (resolution.Contains("x"))
+ if (resolution.Contains("x")) // string.Contains(char) is .NetCore2.1+ specific
{
string[] resolutions = resolution.Split(new[] { 'x' });
x_resolution = Convert.ToInt32(resolutions[0]);
private static string NormalizeDriveName(string driveName)
{
- if (driveName.Contains("\0"))
+ if (driveName.Contains("\0")) // string.Contains(char) is .NetCore2.1+ specific
{
throw new ArgumentException(SR.Format(SR.Arg_InvalidDriveChars, driveName), nameof(driveName));
}
private static ArgumentException GetExceptionIfFragmentPresent(string partName)
{
- if (partName.Contains("#"))
+ if (partName.Contains("#")) // string.Contains(char) is .NetCore2.1+ specific
return new ArgumentException(SR.PartUriCannotHaveAFragment);
else
return null;
protected internal override Expression VisitMemberInit(MemberInitExpression node)
{
if (node.NewExpression.ArgumentCount == 0 &&
- node.NewExpression.Type.Name.Contains("<"))
+ node.NewExpression.Type.Name.Contains('<'))
{
// anonymous type constructor
Out("new");
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using Microsoft.Xunit.Performance;
+using Xunit;
+
+namespace System.Memory.Tests
+{
+ // Adapted from Perf.Span.IndexOf.cs
+ public class Perf_Span_Contains
+ {
+ private const int InnerCount = 50_000;
+
+ [Benchmark(InnerIterationCount = InnerCount)]
+ [InlineData(1)]
+ [InlineData(2)]
+ [InlineData(5)]
+ [InlineData(10)]
+ [InlineData(100)]
+ [InlineData(1000)]
+ [InlineData(2000)]
+ public void SpanContainsChar(int size)
+ {
+ Span<char> charSpan = new char[size];
+ charSpan[size / 2] = '5';
+
+ bool found = true;
+
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ for (int i = 0; i < Benchmark.InnerIterationCount; i++)
+ {
+ if (!charSpan.Contains('5'))
+ found = false;
+ }
+ }
+ }
+
+ Assert.True(found);
+ }
+
+ [Benchmark(InnerIterationCount = InnerCount)]
+ [InlineData(1)]
+ [InlineData(2)]
+ [InlineData(5)]
+ [InlineData(10)]
+ [InlineData(100)]
+ [InlineData(1000)]
+ [InlineData(2000)]
+ public void SpanIndexOfChar(int size)
+ {
+ Span<char> charSpan = new char[size];
+ charSpan[size / 2] = '5';
+
+ bool found = true;
+
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ for (int i = 0; i < Benchmark.InnerIterationCount; i++)
+ {
+ if (charSpan.IndexOf('5') < 0)
+ found = false;
+ }
+ }
+ }
+
+ Assert.True(found);
+ }
+
+ [Benchmark(InnerIterationCount = InnerCount)]
+ [InlineData(1)]
+ [InlineData(2)]
+ [InlineData(5)]
+ [InlineData(10)]
+ [InlineData(100)]
+ [InlineData(1000)]
+ [InlineData(2000)]
+ public void SpanContainsCharAsBytes(int size)
+ {
+ Span<char> charSpan = new char[size];
+ charSpan[size / 2] = '5';
+ Span<byte> byteSpan = MemoryMarshal.AsBytes(charSpan);
+
+ bool found = true;
+
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ for (int i = 0; i < Benchmark.InnerIterationCount; i++)
+ {
+ if (!charSpan.Contains('5')) // '5' = 53
+ found = false;
+ }
+ }
+ }
+
+ Assert.True(found);
+ }
+
+ [Benchmark(InnerIterationCount = InnerCount)]
+ [InlineData(1)]
+ [InlineData(2)]
+ [InlineData(5)]
+ [InlineData(10)]
+ [InlineData(100)]
+ [InlineData(1000)]
+ [InlineData(2000)]
+ public void StringContainsChar(int size)
+ {
+ string str = new string('0', size / 2) + "5";
+ if (size > 1)
+ {
+ str += new string('0', size / 2 - 1);
+ }
+
+ bool found = true;
+
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ for (int i = 0; i < Benchmark.InnerIterationCount; i++)
+ {
+ if (!str.Contains('5'))
+ found = false;
+ }
+ }
+ }
+
+ Assert.True(found);
+ }
+
+ [Benchmark(InnerIterationCount = InnerCount)]
+ [InlineData(1)]
+ [InlineData(2)]
+ [InlineData(5)]
+ [InlineData(10)]
+ [InlineData(100)]
+ [InlineData(1000)]
+ [InlineData(2000)]
+ public void StringIndexOfChar(int size)
+ {
+ string str = new string('0', size / 2) + "5";
+ if (size > 1)
+ {
+ str += new string('0', size / 2 - 1);
+ }
+
+ bool found = true;
+
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ for (int i = 0; i < Benchmark.InnerIterationCount; i++)
+ {
+ if (str.IndexOf('5') < 0)
+ found = false;
+ }
+ }
+ }
+
+ Assert.True(found);
+ }
+
+ private static string GenerateInputString(char source, int count, char replaceChar, int replacePos)
+ {
+ char[] str = new char[count];
+ for (int i = 0; i < count; i++)
+ {
+ str[i] = replaceChar;
+ }
+ str[replacePos] = replaceChar;
+
+ return new string(str);
+ }
+
+ public static IEnumerable<object[]> s_indexTestData = new List<object[]>
+ {
+ new object[] { "string1", '1' },
+ new object[] { "foobardzsdzs", 'z' },
+ new object[] { "StrIng", "I" },
+ new object[] { "\u3060", '\u305F' },
+ new object[] { "ABCDE", 'c' },
+ new object[] { "More Test's", '\'' },
+ new object[] { "Hello WorldbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbareallyreallylongHello WorldbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbareallyreallylongHello Worldbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbareallyreallylong!xyz", '~' },
+ new object[] { "Hello WorldbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbareallyreallylongHello WorldbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbareallyreallylongHello Worldbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbareallyreallylong!xyz", 'w' },
+ new object[] { "Hello Worldbbbbbbbbbbbbbbcbbbbbbbbbbbbbbbbbbba!", 'y' },
+ new object[] { GenerateInputString('A', 10, '5', 5), '5' },
+ new object[] { GenerateInputString('A', 100, 'X', 70), 'x' },
+ new object[] { GenerateInputString('A', 100, 'X', 70), 'x' },
+ new object[] { GenerateInputString('A', 1000, 'X', 500), 'X' },
+ new object[] { GenerateInputString('\u3060', 1000, 'x', 500), 'x' },
+ new object[] { GenerateInputString('\u3060', 100, '\u3059', 50), '\u3059' }
+ };
+
+ [Benchmark(InnerIterationCount = InnerCount)]
+ [MemberData(nameof(s_indexTestData))]
+ public ulong ContainsChar_StringAsSpan(string input, char value)
+ {
+ var count = 0UL;
+
+ ReadOnlySpan<char> inputSpan = input.AsSpan();
+
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ for (int i = 0; i < Benchmark.InnerIterationCount; i++)
+ {
+ if (inputSpan.Contains(value))
+ count++;
+ }
+ }
+ }
+
+ return count;
+ }
+
+ [Benchmark(InnerIterationCount = InnerCount)]
+ [MemberData(nameof(s_indexTestData))]
+ public ulong ContainsChar_String(string input, char value)
+ {
+ var count = 0UL;
+
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ for (int i = 0; i < Benchmark.InnerIterationCount; i++)
+ {
+ if (input.Contains(value))
+ count++;
+ }
+ }
+ }
+
+ return count;
+ }
+
+ [Benchmark(InnerIterationCount = InnerCount)]
+ [MemberData(nameof(s_indexTestData))]
+ public ulong ContainsChar_StringLinq(string input, char value)
+ {
+ var count = 0UL;
+
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ for (int i = 0; i < Benchmark.InnerIterationCount; i++)
+ {
+ if (Linq.Enumerable.Contains(input, value))
+ count++;
+ }
+ }
+ }
+
+ return count;
+ }
+
+ [Benchmark(InnerIterationCount = InnerCount)]
+ [MemberData(nameof(s_indexTestData))]
+ public ulong ContainsChar_StringIndexOf(string input, char value)
+ {
+ var count = 0UL;
+
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ for (int i = 0; i < Benchmark.InnerIterationCount; i++)
+ {
+ if (input.IndexOf(value) >= 0)
+ count++;
+ }
+ }
+ }
+
+ return count;
+ }
+
+ [Benchmark(InnerIterationCount = InnerCount)]
+ [MemberData(nameof(s_indexTestData))]
+ public ulong ContainsChar_Baseline(string input, char value)
+ {
+ var count = 0UL;
+
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ for (int i = 0; i < Benchmark.InnerIterationCount; i++)
+ {
+ for (var j = 0; j < input.Length; j++)
+ {
+ if (input[j] == value)
+ {
+ count++;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return count;
+ }
+ }
+}
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ProjectGuid>{18482C55-6B57-41E8-BBC4-383B9E2C7AA2}</ProjectGuid>
+ <IncludePartialFacadeTests Condition="'$(TargetGroup)' == 'netcoreapp' OR '$(TargetGroup)' == 'uap'">true</IncludePartialFacadeTests>
<Configurations>netcoreapp-Debug;netcoreapp-Release;netstandard-Debug;netstandard-Release</Configurations>
</PropertyGroup>
+ <ItemGroup Condition="'$(IncludePartialFacadeTests)' == 'true'">
+ <!-- Tests specific to the fast span -->
+ <Compile Include="Perf.Span.Contains.cs" />
+ </ItemGroup>
<ItemGroup>
<Compile Include="Perf.Base64EncodeDecode.cs" />
<Compile Include="Perf.Memory.Slice.cs" />
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.SpanTests
+{
+ // Adapted from IndexOf.T.cs
+ public static partial class ReadOnlySpanTests // .Contains<T>
+ {
+ [Fact]
+ public static void ZeroLengthContains()
+ {
+ ReadOnlySpan<int> span = new ReadOnlySpan<int>(Array.Empty<int>());
+
+ bool found = span.Contains(0);
+ Assert.False(found);
+ }
+
+ [Fact]
+ public static void TestContains()
+ {
+ for (int length = 0; length < 32; length++)
+ {
+ int[] a = new int[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = 10 * (i + 1);
+ }
+ ReadOnlySpan<int> span = new ReadOnlySpan<int>(a);
+
+ for (int targetIndex = 0; targetIndex < length; targetIndex++)
+ {
+ int target = a[targetIndex];
+ bool found = span.Contains(target);
+ Assert.True(found);
+ }
+ }
+ }
+
+ [Fact]
+ public static void TestMultipleContains()
+ {
+ for (int length = 2; length < 32; length++)
+ {
+ int[] a = new int[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = 10 * (i + 1);
+ }
+
+ a[length - 1] = 5555;
+ a[length - 2] = 5555;
+
+ ReadOnlySpan<int> span = new ReadOnlySpan<int>(a);
+ bool found = span.Contains(5555);
+ Assert.True(found);
+ }
+ }
+
+ [Fact]
+ public static void OnNoMatchForContainsMakeSureEveryElementIsCompared()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ TIntLog log = new TIntLog();
+
+ TInt[] a = new TInt[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = new TInt(10 * (i + 1), log);
+ }
+ ReadOnlySpan<TInt> span = new ReadOnlySpan<TInt>(a);
+ bool found = span.Contains(new TInt(9999, log));
+ Assert.False(found);
+
+ // Since we asked for a non-existent value, make sure each element of the array was compared once.
+ // (Strictly speaking, it would not be illegal for IndexOf to compare an element more than once but
+ // that would be a non-optimal implementation and a red flag. So we'll stick with the stricter test.)
+ Assert.Equal(a.Length, log.Count);
+ foreach (TInt elem in a)
+ {
+ int numCompares = log.CountCompares(elem.Value, 9999);
+ Assert.True(numCompares == 1, $"Expected {numCompares} == 1 for element {elem.Value}.");
+ }
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoChecksForContainsGoOutOfRange()
+ {
+ const int GuardValue = 77777;
+ const int GuardLength = 50;
+
+ void checkForOutOfRangeAccess(int x, int y)
+ {
+ if (x == GuardValue || y == GuardValue)
+ throw new Exception("Detected out of range access in IndexOf()");
+ }
+
+ for (int length = 0; length < 100; length++)
+ {
+ TInt[] a = new TInt[GuardLength + length + GuardLength];
+ for (int i = 0; i < a.Length; i++)
+ {
+ a[i] = new TInt(GuardValue, checkForOutOfRangeAccess);
+ }
+
+ for (int i = 0; i < length; i++)
+ {
+ a[GuardLength + i] = new TInt(10 * (i + 1), checkForOutOfRangeAccess);
+ }
+
+ ReadOnlySpan<TInt> span = new ReadOnlySpan<TInt>(a, GuardLength, length);
+ bool found = span.Contains(new TInt(9999, checkForOutOfRangeAccess));
+ Assert.False(found);
+ }
+ }
+
+ [Fact]
+ public static void ZeroLengthContains_String()
+ {
+ ReadOnlySpan<string> span = new ReadOnlySpan<string>(Array.Empty<string>());
+ bool found = span.Contains("a");
+ Assert.False(found);
+ }
+
+ [Fact]
+ public static void TestMatchContains_String()
+ {
+ for (int length = 0; length < 32; length++)
+ {
+ string[] a = new string[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = (10 * (i + 1)).ToString();
+ }
+ ReadOnlySpan<string> span = new ReadOnlySpan<string>(a);
+
+ for (int targetIndex = 0; targetIndex < length; targetIndex++)
+ {
+ string target = a[targetIndex];
+ bool found = span.Contains(target);
+ Assert.True(found);
+ }
+ }
+ }
+
+ [Fact]
+ public static void TestNoMatchContains_String()
+ {
+ var rnd = new Random(42);
+ for (int length = 0; length <= byte.MaxValue; length++)
+ {
+ string[] a = new string[length];
+ string target = (rnd.Next(0, 256)).ToString();
+ for (int i = 0; i < length; i++)
+ {
+ string val = (i + 1).ToString();
+ a[i] = val == target ? (target + 1) : val;
+ }
+ ReadOnlySpan<string> span = new ReadOnlySpan<string>(a);
+
+ bool found = span.Contains(target);
+ Assert.False(found);
+ }
+ }
+
+ [Fact]
+ public static void TestMultipleMatchContains_String()
+ {
+ for (int length = 2; length < 32; length++)
+ {
+ string[] a = new string[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = (10 * (i + 1)).ToString();
+ }
+
+ a[length - 1] = "5555";
+ a[length - 2] = "5555";
+
+ ReadOnlySpan<string> span = new ReadOnlySpan<string>(a);
+ bool found = span.Contains("5555");
+ Assert.True(found);
+ }
+ }
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Numerics;
+using Xunit;
+
+namespace System.SpanTests
+{
+ // Adapted from IndexOf.byte.cs
+ public static partial class ReadOnlySpanTests // .Contains<Byte>
+ {
+ [Fact]
+ public static void ZeroLengthContains_Byte()
+ {
+ ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(Array.Empty<byte>());
+
+ bool found = span.Contains<byte>(0);
+ Assert.False(found);
+ }
+
+ [Fact]
+ public static void DefaultFilledContains_Byte()
+ {
+ for (int length = 0; length <= byte.MaxValue; length++)
+ {
+ byte[] a = new byte[length];
+ ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a);
+
+ for (int i = 0; i < length; i++)
+ {
+ byte target0 = default;
+
+ bool found = span.Contains(target0);
+ Assert.True(found);
+ }
+ }
+ }
+
+ [Fact]
+ public static void TestContains_Byte()
+ {
+ for (int length = 0; length <= byte.MaxValue; length++)
+ {
+ byte[] a = new byte[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = (byte)(i + 1);
+ }
+ ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a);
+
+ for (int targetIndex = 0; targetIndex < length; targetIndex++)
+ {
+ byte target = a[targetIndex];
+
+ bool found = span.Contains(target);
+ Assert.True(found);
+ }
+ }
+ }
+
+ [Fact]
+ public static void TestNotContains_Byte()
+ {
+ var rnd = new Random(42);
+ for (int length = 0; length <= byte.MaxValue; length++)
+ {
+ byte[] a = new byte[length];
+ byte target = (byte)rnd.Next(0, 256);
+ for (int i = 0; i < length; i++)
+ {
+ byte val = (byte)(i + 1);
+ a[i] = val == target ? (byte)(target + 1) : val;
+ }
+ ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a);
+
+ bool found = span.Contains(target);
+ Assert.False(found);
+ }
+ }
+
+ [Fact]
+ public static void TestAlignmentNotContains_Byte()
+ {
+ byte[] array = new byte[4 * Vector<byte>.Count];
+ for (var i = 0; i < Vector<byte>.Count; i++)
+ {
+ var span = new ReadOnlySpan<byte>(array, i, 3 * Vector<byte>.Count);
+
+ bool found = span.Contains((byte)'1');
+ Assert.False(found);
+
+ span = new ReadOnlySpan<byte>(array, i, 3 * Vector<byte>.Count - 3);
+
+ found = span.Contains((byte)'1');
+ Assert.False(found);
+ }
+ }
+
+ [Fact]
+ public static void TestAlignmentContains_Byte()
+ {
+ byte[] array = new byte[4 * Vector<byte>.Count];
+ for (int i = 0; i < array.Length; i++)
+ {
+ array[i] = 5;
+ }
+ for (var i = 0; i < Vector<byte>.Count; i++)
+ {
+ var span = new ReadOnlySpan<byte>(array, i, 3 * Vector<byte>.Count);
+
+ bool found = span.Contains<byte>(5);
+ Assert.True(found);
+
+ span = new ReadOnlySpan<byte>(array, i, 3 * Vector<byte>.Count - 3);
+
+ found = span.Contains<byte>(5);
+ Assert.True(found);
+ }
+ }
+
+ [Fact]
+ public static void TestMultipleContains_Byte()
+ {
+ for (int length = 2; length <= byte.MaxValue; length++)
+ {
+ byte[] a = new byte[length];
+ for (int i = 0; i < length; i++)
+ {
+ byte val = (byte)(i + 1);
+ a[i] = val == 200 ? (byte)201 : val;
+ }
+
+ a[length - 1] = 200;
+ a[length - 2] = 200;
+
+ ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a);
+
+ bool found = span.Contains<byte>(200);
+ Assert.True(found);
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoContainsChecksGoOutOfRange_Byte()
+ {
+ for (int length = 0; length <= byte.MaxValue; length++)
+ {
+ byte[] a = new byte[length + 2];
+ a[0] = 99;
+ a[length + 1] = 99;
+ ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a, 1, length);
+
+ bool found = span.Contains<byte>(99);
+ Assert.False(found);
+ }
+ }
+ }
+}
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ProjectGuid>{15DB0DCC-68B4-4CFB-8BD2-F26BCCAF5A3F}</ProjectGuid>
<Compile Include="MemoryMarshal\AsReadOnlyRef.cs" />
<Compile Include="MemoryMarshal\CreateSpan.cs" />
<Compile Include="MemoryMarshal\CreateReadOnlySpan.cs" />
+ <Compile Include="ReadOnlySpan\Contains.byte.cs" />
+ <Compile Include="ReadOnlySpan\Contains.T.cs" />
<Compile Include="Span\Reflection.cs" />
</ItemGroup>
<ItemGroup>
return Array.Empty<string>();
}
}
- else if (!hostname.Contains("."))
+ else if (!hostname.Contains('.'))
{
// for a dotless name, try to resolve the FQDN. If the caller doesn't have DNS permission
// or the query fails for some reason, add only the dotless name.
using System.Collections;
using System.ComponentModel;
using System.Threading;
- using System.Linq;
using System.Xml;
using System.Xml.Serialization;
using System.Globalization;
using System.Threading;
using System.Diagnostics;
- using System.Linq;
using System.Collections.Generic;
using System.Xml.Extensions;
using System.Xml;
public static void Contains(string s, char value, bool expected)
{
Assert.Equal(expected, s.Contains(value));
+
+ ReadOnlySpan<char> span = s.AsSpan();
+ Assert.Equal(expected, span.Contains(value));
}
[Theory]
Assert.False("".AsSpan().Contains('a'));
// Use a long-enough string to incur vectorization code
- for (var length = 1; length < 250; length++)
+ const int max = 250;
+
+ for (var length = 1; length < max; length++)
{
char[] ca = new char[length];
for (int i = 0; i < length; i++)
ca[i] = (char)(i + 1);
}
- var str = new string(ca);
var span = new Span<char>(ca);
var ros = new ReadOnlySpan<char>(ca);
+ var str = new string(ca);
for (var targetIndex = 0; targetIndex < length; targetIndex++)
{
char target = ca[targetIndex];
- var found = str.Contains(target);
- Assert.True(found);
- found = span.Contains(target);
+ // Span
+ bool found = span.Contains(target);
Assert.True(found);
+ // ReadOnlySpan
found = ros.Contains(target);
Assert.True(found);
+
+ // String
+ found = str.Contains(target);
+ Assert.True(found);
+ }
+ }
+ }
+
+ [Fact]
+ public static void Contains_ZeroLength_Char()
+ {
+ // Span
+ var span = new Span<char>(Array.Empty<char>());
+ bool found = span.Contains((char)0);
+ Assert.False(found);
+
+ span = Span<char>.Empty;
+ found = span.Contains((char)0);
+ Assert.False(found);
+
+ // ReadOnlySpan
+ var ros = new ReadOnlySpan<char>(Array.Empty<char>());
+ found = ros.Contains((char)0);
+ Assert.False(found);
+
+ ros = ReadOnlySpan<char>.Empty;
+ found = ros.Contains((char)0);
+ Assert.False(found);
+
+ // String
+ found = string.Empty.Contains((char)0);
+ Assert.False(found);
+ }
+
+ [Fact]
+ public static void Contains_MultipleMatches_Char()
+ {
+ for (int length = 2; length < 32; length++)
+ {
+ var ca = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ ca[i] = (char)(i + 1);
}
+
+ ca[length - 1] = (char)200;
+ ca[length - 2] = (char)200;
+
+ // Span
+ var span = new Span<char>(ca);
+ bool found = span.Contains((char)200);
+ Assert.True(found);
+
+ // ReadOnlySpan
+ var ros = new ReadOnlySpan<char>(ca);
+ found = ros.Contains((char)200);
+ Assert.True(found);
+
+ // String
+ var str = new string(ca);
+ found = str.Contains((char)200);
+ Assert.True(found);
+ }
+ }
+
+ [Fact]
+ public static void Contains_EnsureNoChecksGoOutOfRange_Char()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ var ca = new char[length + 2];
+ ca[0] = '9';
+ ca[length + 1] = '9';
+
+ // Span
+ var span = new Span<char>(ca, 1, length);
+ bool found = span.Contains('9');
+ Assert.False(found);
+
+ // ReadOnlySpan
+ var ros = new ReadOnlySpan<char>(ca, 1, length);
+ found = ros.Contains('9');
+ Assert.False(found);
+
+ // String
+ var str = new string(ca, 1, length);
+ found = str.Contains('9');
+ Assert.False(found);
}
}
using System;
using System.Collections.Generic;
-//using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;