Imported Upstream version 6.6.0.103

Former-commit-id: ed8637df0061cb6f128ae1d26d26db7734e0fa0d
This commit is contained in:
Xamarin Public Jenkins (auto-signing) 2019-10-01 09:12:40 +00:00
parent 53ae335b9c
commit 9b1ef54dc9
78 changed files with 2577 additions and 322 deletions

View File

@ -1 +1 @@
6bd4558f248b14a2a82737af0c9b1d2b0b2944d3 60a79a7b89a82334772050675ba7da0cc4f910d1

View File

@ -1 +1 @@
839127d83c8dfc3cbe1eabd09588a5b57eae1fac ed50e44c7b9748cf25b5006cd5407e8134531cab

View File

@ -1 +1 @@
faec721a749e501975809f748630ed297fd55e50 9072ff67e7c4c540bc2e40267fc5f946b65bf9a1

View File

@ -0,0 +1,107 @@
// 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.
[assembly:System.Reflection.AssemblyVersionAttribute("2.0.5.0")]
[assembly:System.CLSCompliantAttribute(true)]
[assembly:System.Diagnostics.DebuggableAttribute(System.Diagnostics.DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly:System.Reflection.AssemblyCompanyAttribute("Mono development team")]
[assembly:System.Reflection.AssemblyCopyrightAttribute("(c) Various Mono authors")]
[assembly:System.Reflection.AssemblyDefaultAliasAttribute("System.Data.DataSetExtensions.dll")]
[assembly:System.Reflection.AssemblyDescriptionAttribute("System.Data.DataSetExtensions.dll")]
[assembly:System.Reflection.AssemblyFileVersionAttribute("4.0.50524.0")]
[assembly:System.Reflection.AssemblyInformationalVersionAttribute("4.0.50524.0")]
[assembly:System.Reflection.AssemblyProductAttribute("Mono Common Language Infrastructure")]
[assembly:System.Reflection.AssemblyTitleAttribute("System.Data.DataSetExtensions.dll")]
[assembly:System.Resources.NeutralResourcesLanguageAttribute("en-US")]
[assembly:System.Resources.SatelliteContractVersionAttribute("2.0.5.0")]
[assembly:System.Runtime.CompilerServices.CompilationRelaxationsAttribute(System.Runtime.CompilerServices.CompilationRelaxations.NoStringInterning)]
[assembly:System.Runtime.CompilerServices.RuntimeCompatibilityAttribute(WrapNonExceptionThrows=true)]
[assembly:System.Runtime.InteropServices.ComCompatibleVersionAttribute(1, 0, 3300, 0)]
[assembly:System.Runtime.InteropServices.ComVisibleAttribute(false)]
[assembly:System.Security.AllowPartiallyTrustedCallersAttribute]
[assembly:System.Security.SecurityCriticalAttribute]
namespace System.Data
{
public static partial class DataRowComparer
{
public static System.Data.DataRowComparer<System.Data.DataRow> Default { get { throw null; } }
}
public sealed partial class DataRowComparer<TRow> : System.Collections.Generic.IEqualityComparer<TRow> where TRow : System.Data.DataRow
{
internal DataRowComparer() { }
public static System.Data.DataRowComparer<TRow> Default { get { throw null; } }
public bool Equals(TRow leftRow, TRow rightRow) { throw null; }
public int GetHashCode(TRow row) { throw null; }
}
public static partial class DataRowExtensions
{
public static T Field<T>(this System.Data.DataRow row, System.Data.DataColumn column) { throw null; }
public static T Field<T>(this System.Data.DataRow row, System.Data.DataColumn column, System.Data.DataRowVersion version) { throw null; }
public static T Field<T>(this System.Data.DataRow row, int columnIndex) { throw null; }
public static T Field<T>(this System.Data.DataRow row, int columnIndex, System.Data.DataRowVersion version) { throw null; }
public static T Field<T>(this System.Data.DataRow row, string columnName) { throw null; }
public static T Field<T>(this System.Data.DataRow row, string columnName, System.Data.DataRowVersion version) { throw null; }
public static void SetField<T>(this System.Data.DataRow row, System.Data.DataColumn column, T value) { }
public static void SetField<T>(this System.Data.DataRow row, int columnIndex, T value) { }
public static void SetField<T>(this System.Data.DataRow row, string columnName, T value) { }
}
public static partial class DataTableExtensions
{
public static System.Data.DataView AsDataView(this System.Data.DataTable table) { throw null; }
public static System.Data.DataView AsDataView<T>(this System.Data.EnumerableRowCollection<T> source) where T : System.Data.DataRow { throw null; }
public static System.Data.EnumerableRowCollection<System.Data.DataRow> AsEnumerable(this System.Data.DataTable source) { throw null; }
public static System.Data.DataTable CopyToDataTable<T>(this System.Collections.Generic.IEnumerable<T> source) where T : System.Data.DataRow { throw null; }
public static void CopyToDataTable<T>(this System.Collections.Generic.IEnumerable<T> source, System.Data.DataTable table, System.Data.LoadOption options) where T : System.Data.DataRow { }
public static void CopyToDataTable<T>(this System.Collections.Generic.IEnumerable<T> source, System.Data.DataTable table, System.Data.LoadOption options, System.Data.FillErrorEventHandler errorHandler) where T : System.Data.DataRow { }
}
public abstract partial class EnumerableRowCollection : System.Collections.IEnumerable
{
internal EnumerableRowCollection() { }
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; }
}
public static partial class EnumerableRowCollectionExtensions
{
public static System.Data.EnumerableRowCollection<TResult> Cast<TResult>(this System.Data.EnumerableRowCollection source) { throw null; }
public static System.Data.OrderedEnumerableRowCollection<TRow> OrderByDescending<TRow, TKey>(this System.Data.EnumerableRowCollection<TRow> source, System.Func<TRow, TKey> keySelector) { throw null; }
public static System.Data.OrderedEnumerableRowCollection<TRow> OrderByDescending<TRow, TKey>(this System.Data.EnumerableRowCollection<TRow> source, System.Func<TRow, TKey> keySelector, System.Collections.Generic.IComparer<TKey> comparer) { throw null; }
public static System.Data.OrderedEnumerableRowCollection<TRow> OrderBy<TRow, TKey>(this System.Data.EnumerableRowCollection<TRow> source, System.Func<TRow, TKey> keySelector) { throw null; }
public static System.Data.OrderedEnumerableRowCollection<TRow> OrderBy<TRow, TKey>(this System.Data.EnumerableRowCollection<TRow> source, System.Func<TRow, TKey> keySelector, System.Collections.Generic.IComparer<TKey> comparer) { throw null; }
public static System.Data.EnumerableRowCollection<S> Select<TRow, S>(this System.Data.EnumerableRowCollection<TRow> source, System.Func<TRow, S> selector) { throw null; }
public static System.Data.OrderedEnumerableRowCollection<TRow> ThenByDescending<TRow, TKey>(this System.Data.OrderedEnumerableRowCollection<TRow> source, System.Func<TRow, TKey> keySelector) { throw null; }
public static System.Data.OrderedEnumerableRowCollection<TRow> ThenByDescending<TRow, TKey>(this System.Data.OrderedEnumerableRowCollection<TRow> source, System.Func<TRow, TKey> keySelector, System.Collections.Generic.IComparer<TKey> comparer) { throw null; }
public static System.Data.OrderedEnumerableRowCollection<TRow> ThenBy<TRow, TKey>(this System.Data.OrderedEnumerableRowCollection<TRow> source, System.Func<TRow, TKey> keySelector) { throw null; }
public static System.Data.OrderedEnumerableRowCollection<TRow> ThenBy<TRow, TKey>(this System.Data.OrderedEnumerableRowCollection<TRow> source, System.Func<TRow, TKey> keySelector, System.Collections.Generic.IComparer<TKey> comparer) { throw null; }
public static System.Data.EnumerableRowCollection<TRow> Where<TRow>(this System.Data.EnumerableRowCollection<TRow> source, System.Func<TRow, bool> predicate) { throw null; }
}
public partial class EnumerableRowCollection<TRow> : System.Data.EnumerableRowCollection, System.Collections.Generic.IEnumerable<TRow>, System.Collections.IEnumerable
{
internal EnumerableRowCollection() { }
public System.Collections.Generic.IEnumerator<TRow> GetEnumerator() { throw null; }
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; }
}
public sealed partial class OrderedEnumerableRowCollection<TRow> : System.Data.EnumerableRowCollection<TRow>
{
internal OrderedEnumerableRowCollection() { }
}
public static partial class TypedTableBaseExtensions
{
public static System.Data.EnumerableRowCollection<TRow> AsEnumerable<TRow>(this System.Data.TypedTableBase<TRow> source) where TRow : System.Data.DataRow { throw null; }
public static TRow ElementAtOrDefault<TRow>(this System.Data.TypedTableBase<TRow> source, int index) where TRow : System.Data.DataRow { throw null; }
public static System.Data.OrderedEnumerableRowCollection<TRow> OrderByDescending<TRow, TKey>(this System.Data.TypedTableBase<TRow> source, System.Func<TRow, TKey> keySelector) where TRow : System.Data.DataRow { throw null; }
public static System.Data.OrderedEnumerableRowCollection<TRow> OrderByDescending<TRow, TKey>(this System.Data.TypedTableBase<TRow> source, System.Func<TRow, TKey> keySelector, System.Collections.Generic.IComparer<TKey> comparer) where TRow : System.Data.DataRow { throw null; }
public static System.Data.OrderedEnumerableRowCollection<TRow> OrderBy<TRow, TKey>(this System.Data.TypedTableBase<TRow> source, System.Func<TRow, TKey> keySelector) where TRow : System.Data.DataRow { throw null; }
public static System.Data.OrderedEnumerableRowCollection<TRow> OrderBy<TRow, TKey>(this System.Data.TypedTableBase<TRow> source, System.Func<TRow, TKey> keySelector, System.Collections.Generic.IComparer<TKey> comparer) where TRow : System.Data.DataRow { throw null; }
public static System.Data.EnumerableRowCollection<S> Select<TRow, S>(this System.Data.TypedTableBase<TRow> source, System.Func<TRow, S> selector) where TRow : System.Data.DataRow { throw null; }
public static System.Data.EnumerableRowCollection<TRow> Where<TRow>(this System.Data.TypedTableBase<TRow> source, System.Func<TRow, bool> predicate) where TRow : System.Data.DataRow { throw null; }
}
[System.SerializableAttribute]
public abstract partial class TypedTableBase<T> : System.Data.DataTable, System.Collections.Generic.IEnumerable<T>, System.Collections.IEnumerable where T : System.Data.DataRow
{
protected TypedTableBase() { }
protected TypedTableBase(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }
public System.Data.EnumerableRowCollection<TResult> Cast<TResult>() { throw null; }
public System.Collections.Generic.IEnumerator<T> GetEnumerator() { throw null; }
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; }
}
}

View File

@ -1 +1 @@
fd51a18a3a062b480d134e7d3ad089cb7c6db94b 4eab3daf447a9db125e2b7d24282b35b14aa7f64

View File

@ -1 +1 @@
faec721a749e501975809f748630ed297fd55e50 9072ff67e7c4c540bc2e40267fc5f946b65bf9a1

View File

@ -0,0 +1,107 @@
// 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.
[assembly:System.Reflection.AssemblyVersionAttribute("2.0.5.0")]
[assembly:System.CLSCompliantAttribute(true)]
[assembly:System.Diagnostics.DebuggableAttribute(System.Diagnostics.DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly:System.Reflection.AssemblyCompanyAttribute("Mono development team")]
[assembly:System.Reflection.AssemblyCopyrightAttribute("(c) Various Mono authors")]
[assembly:System.Reflection.AssemblyDefaultAliasAttribute("System.Data.DataSetExtensions.dll")]
[assembly:System.Reflection.AssemblyDescriptionAttribute("System.Data.DataSetExtensions.dll")]
[assembly:System.Reflection.AssemblyFileVersionAttribute("4.0.50524.0")]
[assembly:System.Reflection.AssemblyInformationalVersionAttribute("4.0.50524.0")]
[assembly:System.Reflection.AssemblyProductAttribute("Mono Common Language Infrastructure")]
[assembly:System.Reflection.AssemblyTitleAttribute("System.Data.DataSetExtensions.dll")]
[assembly:System.Resources.NeutralResourcesLanguageAttribute("en-US")]
[assembly:System.Resources.SatelliteContractVersionAttribute("2.0.5.0")]
[assembly:System.Runtime.CompilerServices.CompilationRelaxationsAttribute(System.Runtime.CompilerServices.CompilationRelaxations.NoStringInterning)]
[assembly:System.Runtime.CompilerServices.RuntimeCompatibilityAttribute(WrapNonExceptionThrows=true)]
[assembly:System.Runtime.InteropServices.ComCompatibleVersionAttribute(1, 0, 3300, 0)]
[assembly:System.Runtime.InteropServices.ComVisibleAttribute(false)]
[assembly:System.Security.AllowPartiallyTrustedCallersAttribute]
[assembly:System.Security.SecurityCriticalAttribute]
namespace System.Data
{
public static partial class DataRowComparer
{
public static System.Data.DataRowComparer<System.Data.DataRow> Default { get { throw null; } }
}
public sealed partial class DataRowComparer<TRow> : System.Collections.Generic.IEqualityComparer<TRow> where TRow : System.Data.DataRow
{
internal DataRowComparer() { }
public static System.Data.DataRowComparer<TRow> Default { get { throw null; } }
public bool Equals(TRow leftRow, TRow rightRow) { throw null; }
public int GetHashCode(TRow row) { throw null; }
}
public static partial class DataRowExtensions
{
public static T Field<T>(this System.Data.DataRow row, System.Data.DataColumn column) { throw null; }
public static T Field<T>(this System.Data.DataRow row, System.Data.DataColumn column, System.Data.DataRowVersion version) { throw null; }
public static T Field<T>(this System.Data.DataRow row, int columnIndex) { throw null; }
public static T Field<T>(this System.Data.DataRow row, int columnIndex, System.Data.DataRowVersion version) { throw null; }
public static T Field<T>(this System.Data.DataRow row, string columnName) { throw null; }
public static T Field<T>(this System.Data.DataRow row, string columnName, System.Data.DataRowVersion version) { throw null; }
public static void SetField<T>(this System.Data.DataRow row, System.Data.DataColumn column, T value) { }
public static void SetField<T>(this System.Data.DataRow row, int columnIndex, T value) { }
public static void SetField<T>(this System.Data.DataRow row, string columnName, T value) { }
}
public static partial class DataTableExtensions
{
public static System.Data.DataView AsDataView(this System.Data.DataTable table) { throw null; }
public static System.Data.DataView AsDataView<T>(this System.Data.EnumerableRowCollection<T> source) where T : System.Data.DataRow { throw null; }
public static System.Data.EnumerableRowCollection<System.Data.DataRow> AsEnumerable(this System.Data.DataTable source) { throw null; }
public static System.Data.DataTable CopyToDataTable<T>(this System.Collections.Generic.IEnumerable<T> source) where T : System.Data.DataRow { throw null; }
public static void CopyToDataTable<T>(this System.Collections.Generic.IEnumerable<T> source, System.Data.DataTable table, System.Data.LoadOption options) where T : System.Data.DataRow { }
public static void CopyToDataTable<T>(this System.Collections.Generic.IEnumerable<T> source, System.Data.DataTable table, System.Data.LoadOption options, System.Data.FillErrorEventHandler errorHandler) where T : System.Data.DataRow { }
}
public abstract partial class EnumerableRowCollection : System.Collections.IEnumerable
{
internal EnumerableRowCollection() { }
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; }
}
public static partial class EnumerableRowCollectionExtensions
{
public static System.Data.EnumerableRowCollection<TResult> Cast<TResult>(this System.Data.EnumerableRowCollection source) { throw null; }
public static System.Data.OrderedEnumerableRowCollection<TRow> OrderByDescending<TRow, TKey>(this System.Data.EnumerableRowCollection<TRow> source, System.Func<TRow, TKey> keySelector) { throw null; }
public static System.Data.OrderedEnumerableRowCollection<TRow> OrderByDescending<TRow, TKey>(this System.Data.EnumerableRowCollection<TRow> source, System.Func<TRow, TKey> keySelector, System.Collections.Generic.IComparer<TKey> comparer) { throw null; }
public static System.Data.OrderedEnumerableRowCollection<TRow> OrderBy<TRow, TKey>(this System.Data.EnumerableRowCollection<TRow> source, System.Func<TRow, TKey> keySelector) { throw null; }
public static System.Data.OrderedEnumerableRowCollection<TRow> OrderBy<TRow, TKey>(this System.Data.EnumerableRowCollection<TRow> source, System.Func<TRow, TKey> keySelector, System.Collections.Generic.IComparer<TKey> comparer) { throw null; }
public static System.Data.EnumerableRowCollection<S> Select<TRow, S>(this System.Data.EnumerableRowCollection<TRow> source, System.Func<TRow, S> selector) { throw null; }
public static System.Data.OrderedEnumerableRowCollection<TRow> ThenByDescending<TRow, TKey>(this System.Data.OrderedEnumerableRowCollection<TRow> source, System.Func<TRow, TKey> keySelector) { throw null; }
public static System.Data.OrderedEnumerableRowCollection<TRow> ThenByDescending<TRow, TKey>(this System.Data.OrderedEnumerableRowCollection<TRow> source, System.Func<TRow, TKey> keySelector, System.Collections.Generic.IComparer<TKey> comparer) { throw null; }
public static System.Data.OrderedEnumerableRowCollection<TRow> ThenBy<TRow, TKey>(this System.Data.OrderedEnumerableRowCollection<TRow> source, System.Func<TRow, TKey> keySelector) { throw null; }
public static System.Data.OrderedEnumerableRowCollection<TRow> ThenBy<TRow, TKey>(this System.Data.OrderedEnumerableRowCollection<TRow> source, System.Func<TRow, TKey> keySelector, System.Collections.Generic.IComparer<TKey> comparer) { throw null; }
public static System.Data.EnumerableRowCollection<TRow> Where<TRow>(this System.Data.EnumerableRowCollection<TRow> source, System.Func<TRow, bool> predicate) { throw null; }
}
public partial class EnumerableRowCollection<TRow> : System.Data.EnumerableRowCollection, System.Collections.Generic.IEnumerable<TRow>, System.Collections.IEnumerable
{
internal EnumerableRowCollection() { }
public System.Collections.Generic.IEnumerator<TRow> GetEnumerator() { throw null; }
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; }
}
public sealed partial class OrderedEnumerableRowCollection<TRow> : System.Data.EnumerableRowCollection<TRow>
{
internal OrderedEnumerableRowCollection() { }
}
public static partial class TypedTableBaseExtensions
{
public static System.Data.EnumerableRowCollection<TRow> AsEnumerable<TRow>(this System.Data.TypedTableBase<TRow> source) where TRow : System.Data.DataRow { throw null; }
public static TRow ElementAtOrDefault<TRow>(this System.Data.TypedTableBase<TRow> source, int index) where TRow : System.Data.DataRow { throw null; }
public static System.Data.OrderedEnumerableRowCollection<TRow> OrderByDescending<TRow, TKey>(this System.Data.TypedTableBase<TRow> source, System.Func<TRow, TKey> keySelector) where TRow : System.Data.DataRow { throw null; }
public static System.Data.OrderedEnumerableRowCollection<TRow> OrderByDescending<TRow, TKey>(this System.Data.TypedTableBase<TRow> source, System.Func<TRow, TKey> keySelector, System.Collections.Generic.IComparer<TKey> comparer) where TRow : System.Data.DataRow { throw null; }
public static System.Data.OrderedEnumerableRowCollection<TRow> OrderBy<TRow, TKey>(this System.Data.TypedTableBase<TRow> source, System.Func<TRow, TKey> keySelector) where TRow : System.Data.DataRow { throw null; }
public static System.Data.OrderedEnumerableRowCollection<TRow> OrderBy<TRow, TKey>(this System.Data.TypedTableBase<TRow> source, System.Func<TRow, TKey> keySelector, System.Collections.Generic.IComparer<TKey> comparer) where TRow : System.Data.DataRow { throw null; }
public static System.Data.EnumerableRowCollection<S> Select<TRow, S>(this System.Data.TypedTableBase<TRow> source, System.Func<TRow, S> selector) where TRow : System.Data.DataRow { throw null; }
public static System.Data.EnumerableRowCollection<TRow> Where<TRow>(this System.Data.TypedTableBase<TRow> source, System.Func<TRow, bool> predicate) where TRow : System.Data.DataRow { throw null; }
}
[System.SerializableAttribute]
public abstract partial class TypedTableBase<T> : System.Data.DataTable, System.Collections.Generic.IEnumerable<T>, System.Collections.IEnumerable where T : System.Data.DataRow
{
protected TypedTableBase() { }
protected TypedTableBase(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }
public System.Data.EnumerableRowCollection<TResult> Cast<TResult>() { throw null; }
public System.Collections.Generic.IEnumerator<T> GetEnumerator() { throw null; }
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; }
}
}

View File

@ -1 +1 @@
4048a50560e4e0704415a46f55f1b706095331b4 90d02a101ed04da6a18a169ddf1ec2799c16fcdf

View File

@ -1 +1 @@
faec721a749e501975809f748630ed297fd55e50 9072ff67e7c4c540bc2e40267fc5f946b65bf9a1

View File

@ -48,6 +48,8 @@ namespace System.Data
} }
public static partial class DataTableExtensions public static partial class DataTableExtensions
{ {
public static System.Data.DataView AsDataView(this System.Data.DataTable table) { throw null; }
public static System.Data.DataView AsDataView<T>(this System.Data.EnumerableRowCollection<T> source) where T : System.Data.DataRow { throw null; }
public static System.Data.EnumerableRowCollection<System.Data.DataRow> AsEnumerable(this System.Data.DataTable source) { throw null; } public static System.Data.EnumerableRowCollection<System.Data.DataRow> AsEnumerable(this System.Data.DataTable source) { throw null; }
public static System.Data.DataTable CopyToDataTable<T>(this System.Collections.Generic.IEnumerable<T> source) where T : System.Data.DataRow { throw null; } public static System.Data.DataTable CopyToDataTable<T>(this System.Collections.Generic.IEnumerable<T> source) where T : System.Data.DataRow { throw null; }
public static void CopyToDataTable<T>(this System.Collections.Generic.IEnumerable<T> source, System.Data.DataTable table, System.Data.LoadOption options) where T : System.Data.DataRow { } public static void CopyToDataTable<T>(this System.Collections.Generic.IEnumerable<T> source, System.Data.DataTable table, System.Data.LoadOption options) where T : System.Data.DataRow { }

View File

@ -1 +1 @@
3d6057ed36a94c8b67e4b28f2a871ff0127ea381 03f0d6f3e5645ad55d73b26135212076a5119877

View File

@ -132,6 +132,20 @@ namespace System
return div; return div;
} }
internal static uint DivRem(uint a, uint b, out uint result)
{
uint div = a / b;
result = a - (div * b);
return div;
}
internal static ulong DivRem(ulong a, ulong b, out ulong result)
{
ulong div = a / b;
result = a - (div * b);
return div;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static decimal Ceiling(decimal d) public static decimal Ceiling(decimal d)
{ {

View File

@ -218,5 +218,27 @@ namespace System.Data
Debug.Assert(null != table, "null DataTable"); Debug.Assert(null != table, "null DataTable");
return table; return table;
} }
/// <summary>
/// Creates a LinkDataView of DataRow over the input table.
/// </summary>
/// <param name="table">DataTable that the view is over.</param>
/// <returns>An instance of LinkDataView.</returns>
public static DataView AsDataView(this DataTable table)
{
throw new PlatformNotSupportedException ();
}
/// <summary>
/// Creates a LinqDataView from EnumerableDataTable
/// </summary>
/// <typeparam name="T">Type of the row in the table. Must inherit from DataRow</typeparam>
/// <param name="source">The enumerable-datatable over which view must be created.</param>
/// <returns>Generated LinkDataView of type T</returns>
public static DataView AsDataView<T>(this EnumerableRowCollection<T> source) where T : DataRow
{
throw new PlatformNotSupportedException ();
}
} }
} }

View File

@ -280,8 +280,6 @@ namespace System.IO
finally finally
{ {
StaticWatcherRunLoopManager.UnscheduleFromRunLoop(_eventStream); StaticWatcherRunLoopManager.UnscheduleFromRunLoop(_eventStream);
_eventStream.Close();
_eventStream = null;
} }
} }
} }

View File

@ -8,7 +8,6 @@ using System.Collections.ObjectModel;
using System.Diagnostics; using System.Diagnostics;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices;
namespace System.Linq namespace System.Linq
{ {
@ -213,63 +212,6 @@ namespace System.Linq
private static ILookup<string, MethodInfo> s_seqMethods; private static ILookup<string, MethodInfo> s_seqMethods;
[PreserveDependency ("Aggregate`1", "System.Linq.Enumerable")]
[PreserveDependency ("Aggregate`2", "System.Linq.Enumerable")]
[PreserveDependency ("Aggregate`3", "System.Linq.Enumerable")]
[PreserveDependency ("All`1", "System.Linq.Enumerable")]
[PreserveDependency ("Any`1", "System.Linq.Enumerable")]
[PreserveDependency ("Append`1", "System.Linq.Enumerable")]
[PreserveDependency ("Average", "System.Linq.Enumerable")]
[PreserveDependency ("Average`1", "System.Linq.Enumerable")]
[PreserveDependency ("Cast`1", "System.Linq.Enumerable")]
[PreserveDependency ("Concat`1", "System.Linq.Enumerable")]
[PreserveDependency ("Contains`1", "System.Linq.Enumerable")]
[PreserveDependency ("Count`1", "System.Linq.Enumerable")]
[PreserveDependency ("DefaultIfEmpty`1", "System.Linq.Enumerable")]
[PreserveDependency ("Distinct`1", "System.Linq.Enumerable")]
[PreserveDependency ("ElementAt`1", "System.Linq.Enumerable")]
[PreserveDependency ("ElementAtOrDefault`1", "System.Linq.Enumerable")]
[PreserveDependency ("Except`1", "System.Linq.Enumerable")]
[PreserveDependency ("First`1", "System.Linq.Enumerable")]
[PreserveDependency ("FirstOrDefault`1", "System.Linq.Enumerable")]
[PreserveDependency ("GroupBy`2", "System.Linq.Enumerable")]
[PreserveDependency ("GroupBy`3", "System.Linq.Enumerable")]
[PreserveDependency ("GroupBy`4", "System.Linq.Enumerable")]
[PreserveDependency ("GroupJoin`4", "System.Linq.Enumerable")]
[PreserveDependency ("Intersect`1", "System.Linq.Enumerable")]
[PreserveDependency ("Join`4", "System.Linq.Enumerable")]
[PreserveDependency ("Last`1", "System.Linq.Enumerable")]
[PreserveDependency ("LastOrDefault`1", "System.Linq.Enumerable")]
[PreserveDependency ("LongCount`1", "System.Linq.Enumerable")]
[PreserveDependency ("Max`1", "System.Linq.Enumerable")]
[PreserveDependency ("Max`2", "System.Linq.Enumerable")]
[PreserveDependency ("Min`1", "System.Linq.Enumerable")]
[PreserveDependency ("Min`2", "System.Linq.Enumerable")]
[PreserveDependency ("OfType`1", "System.Linq.Enumerable")]
[PreserveDependency ("OrderBy`2", "System.Linq.Enumerable")]
[PreserveDependency ("OrderByDescending`2", "System.Linq.Enumerable")]
[PreserveDependency ("Prepend`1", "System.Linq.Enumerable")]
[PreserveDependency ("Reverse`1", "System.Linq.Enumerable")]
[PreserveDependency ("Select`2", "System.Linq.Enumerable")]
[PreserveDependency ("SelectMany`2", "System.Linq.Enumerable")]
[PreserveDependency ("SelectMany`3", "System.Linq.Enumerable")]
[PreserveDependency ("SequenceEqual`1", "System.Linq.Enumerable")]
[PreserveDependency ("Single`1", "System.Linq.Enumerable")]
[PreserveDependency ("SingleOrDefault`1", "System.Linq.Enumerable")]
[PreserveDependency ("Skip`1", "System.Linq.Enumerable")]
[PreserveDependency ("SkipLast`1", "System.Linq.Enumerable")]
[PreserveDependency ("SkipWhile`1", "System.Linq.Enumerable")]
[PreserveDependency ("Sum", "System.Linq.Enumerable")]
[PreserveDependency ("Sum`1", "System.Linq.Enumerable")]
[PreserveDependency ("Take`1", "System.Linq.Enumerable")]
[PreserveDependency ("TakeLast`1", "System.Linq.Enumerable")]
[PreserveDependency ("TakeWhile`1", "System.Linq.Enumerable")]
[PreserveDependency ("ThenBy`2", "System.Linq.Enumerable")]
[PreserveDependency ("ThenByDescending`2", "System.Linq.Enumerable")]
[PreserveDependency ("Union`1", "System.Linq.Enumerable")]
[PreserveDependency ("Where`1", "System.Linq.Enumerable")]
[PreserveDependency ("Zip`3", "System.Linq.Enumerable")]
private static MethodInfo FindEnumerableMethod(string name, ReadOnlyCollection<Expression> args, params Type[] typeArgs) private static MethodInfo FindEnumerableMethod(string name, ReadOnlyCollection<Expression> args, params Type[] typeArgs)
{ {
if (s_seqMethods == null) if (s_seqMethods == null)

View File

@ -3,11 +3,10 @@
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System.Diagnostics; using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
#if !FEATURE_PORTABLE_SPAN
using Internal.Runtime.CompilerServices; using Internal.Runtime.CompilerServices;
#endif // FEATURE_PORTABLE_SPAN
namespace System.Buffers namespace System.Buffers
{ {
@ -18,17 +17,16 @@ namespace System.Buffers
[DebuggerDisplay("{ToString(),raw}")] [DebuggerDisplay("{ToString(),raw}")]
public readonly partial struct ReadOnlySequence<T> public readonly partial struct ReadOnlySequence<T>
{ {
private readonly SequencePosition _sequenceStart; // The data is essentially two SequencePositions, however the Start and End SequencePositions are deconstructed to improve packing.
private readonly SequencePosition _sequenceEnd; private readonly object _startObject;
private readonly object _endObject;
private readonly int _startInteger;
private readonly int _endInteger;
/// <summary> /// <summary>
/// Returns empty <see cref="ReadOnlySequence{T}"/> /// Returns empty <see cref="ReadOnlySequence{T}"/>
/// </summary> /// </summary>
#if FEATURE_PORTABLE_SPAN
public static readonly ReadOnlySequence<T> Empty = new ReadOnlySequence<T>(SpanHelpers.PerTypeValues<T>.EmptyArray);
#else
public static readonly ReadOnlySequence<T> Empty = new ReadOnlySequence<T>(Array.Empty<T>()); public static readonly ReadOnlySequence<T> Empty = new ReadOnlySequence<T>(Array.Empty<T>());
#endif // FEATURE_PORTABLE_SPAN
/// <summary> /// <summary>
/// Length of the <see cref="ReadOnlySequence{T}"/>. /// Length of the <see cref="ReadOnlySequence{T}"/>.
@ -46,7 +44,7 @@ namespace System.Buffers
public bool IsSingleSegment public bool IsSingleSegment
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _sequenceStart.GetObject() == _sequenceEnd.GetObject(); get => _startObject == _endObject;
} }
/// <summary> /// <summary>
@ -54,15 +52,28 @@ namespace System.Buffers
/// </summary> /// </summary>
public ReadOnlyMemory<T> First => GetFirstBuffer(); public ReadOnlyMemory<T> First => GetFirstBuffer();
/// <summary>
/// Gets <see cref="ReadOnlySpan{T}"/> from the first segment.
/// </summary>
public ReadOnlySpan<T> FirstSpan => GetFirstSpan();
/// <summary> /// <summary>
/// A position to the start of the <see cref="ReadOnlySequence{T}"/>. /// A position to the start of the <see cref="ReadOnlySequence{T}"/>.
/// </summary> /// </summary>
public SequencePosition Start => _sequenceStart; public SequencePosition Start
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => new SequencePosition(_startObject, _startInteger);
}
/// <summary> /// <summary>
/// A position to the end of the <see cref="ReadOnlySequence{T}"/> /// A position to the end of the <see cref="ReadOnlySequence{T}"/>
/// </summary> /// </summary>
public SequencePosition End => _sequenceEnd; public SequencePosition End
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => new SequencePosition(_endObject, _endInteger);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private ReadOnlySequence(object startSegment, int startIndexAndFlags, object endSegment, int endIndexAndFlags) private ReadOnlySequence(object startSegment, int startIndexAndFlags, object endSegment, int endIndexAndFlags)
@ -73,8 +84,10 @@ namespace System.Buffers
Debug.Assert((startSegment != null && endSegment != null) || Debug.Assert((startSegment != null && endSegment != null) ||
(startSegment == null && endSegment == null && startIndexAndFlags == 0 && endIndexAndFlags == 0)); (startSegment == null && endSegment == null && startIndexAndFlags == 0 && endIndexAndFlags == 0));
_sequenceStart = new SequencePosition(startSegment, startIndexAndFlags); _startObject = startSegment;
_sequenceEnd = new SequencePosition(endSegment, endIndexAndFlags); _endObject = endSegment;
_startInteger = startIndexAndFlags;
_endInteger = endIndexAndFlags;
} }
/// <summary> /// <summary>
@ -91,24 +104,28 @@ namespace System.Buffers
(startSegment == endSegment && endIndex < startIndex)) (startSegment == endSegment && endIndex < startIndex))
ThrowHelper.ThrowArgumentValidationException(startSegment, startIndex, endSegment); ThrowHelper.ThrowArgumentValidationException(startSegment, startIndex, endSegment);
_sequenceStart = new SequencePosition(startSegment, ReadOnlySequence.SegmentToSequenceStart(startIndex)); _startObject = startSegment;
_sequenceEnd = new SequencePosition(endSegment, ReadOnlySequence.SegmentToSequenceEnd(endIndex)); _endObject = endSegment;
_startInteger = ReadOnlySequence.SegmentToSequenceStart(startIndex);
_endInteger = ReadOnlySequence.SegmentToSequenceEnd(endIndex);
} }
/// <summary> /// <summary>
/// Creates an instance of <see cref="ReadOnlySequence{T}"/> from the <see cref="T:T[]"/>. /// Creates an instance of <see cref="ReadOnlySequence{T}"/> from the array.
/// </summary> /// </summary>
public ReadOnlySequence(T[] array) public ReadOnlySequence(T[] array)
{ {
if (array == null) if (array == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
_sequenceStart = new SequencePosition(array, ReadOnlySequence.ArrayToSequenceStart(0)); _startObject = array;
_sequenceEnd = new SequencePosition(array, ReadOnlySequence.ArrayToSequenceEnd(array.Length)); _endObject = array;
_startInteger = ReadOnlySequence.ArrayToSequenceStart(0);
_endInteger = ReadOnlySequence.ArrayToSequenceEnd(array.Length);
} }
/// <summary> /// <summary>
/// Creates an instance of <see cref="ReadOnlySequence{T}"/> from the <see cref="T:T[]"/>, start and index. /// Creates an instance of <see cref="ReadOnlySequence{T}"/> from the array, start, and index.
/// </summary> /// </summary>
public ReadOnlySequence(T[] array, int start, int length) public ReadOnlySequence(T[] array, int start, int length)
{ {
@ -117,8 +134,10 @@ namespace System.Buffers
(uint)length > (uint)(array.Length - start)) (uint)length > (uint)(array.Length - start))
ThrowHelper.ThrowArgumentValidationException(array, start); ThrowHelper.ThrowArgumentValidationException(array, start);
_sequenceStart = new SequencePosition(array, ReadOnlySequence.ArrayToSequenceStart(start)); _startObject = array;
_sequenceEnd = new SequencePosition(array, ReadOnlySequence.ArrayToSequenceEnd(start + length)); _endObject = array;
_startInteger = ReadOnlySequence.ArrayToSequenceStart(start);
_endInteger = ReadOnlySequence.ArrayToSequenceEnd(start + length);
} }
/// <summary> /// <summary>
@ -127,40 +146,51 @@ namespace System.Buffers
/// </summary> /// </summary>
public ReadOnlySequence(ReadOnlyMemory<T> memory) public ReadOnlySequence(ReadOnlyMemory<T> memory)
{ {
#pragma warning disable CS8631 // TODO-NULLABLE: ILLink rewriter removing some necessary metadata (https://github.com/dotnet/corefx/pull/38983#issuecomment-506757237)
if (MemoryMarshal.TryGetMemoryManager(memory, out MemoryManager<T> manager, out int index, out int length)) if (MemoryMarshal.TryGetMemoryManager(memory, out MemoryManager<T> manager, out int index, out int length))
#pragma warning restore CS8631
{ {
_sequenceStart = new SequencePosition(manager, ReadOnlySequence.MemoryManagerToSequenceStart(index)); _startObject = manager;
_sequenceEnd = new SequencePosition(manager, ReadOnlySequence.MemoryManagerToSequenceEnd(length)); _endObject = manager;
_startInteger = ReadOnlySequence.MemoryManagerToSequenceStart(index);
_endInteger = ReadOnlySequence.MemoryManagerToSequenceEnd(length);
} }
else if (MemoryMarshal.TryGetArray(memory, out ArraySegment<T> segment)) else if (MemoryMarshal.TryGetArray(memory, out ArraySegment<T> segment))
{ {
T[] array = segment.Array; T[] array = segment.Array;
int start = segment.Offset; int start = segment.Offset;
_sequenceStart = new SequencePosition(array, ReadOnlySequence.ArrayToSequenceStart(start)); _startObject = array;
_sequenceEnd = new SequencePosition(array, ReadOnlySequence.ArrayToSequenceEnd(start + segment.Count)); _endObject = array;
_startInteger = ReadOnlySequence.ArrayToSequenceStart(start);
_endInteger = ReadOnlySequence.ArrayToSequenceEnd(start + segment.Count);
} }
else if (typeof(T) == typeof(char)) else if (typeof(T) == typeof(char))
{ {
if (!MemoryMarshal.TryGetString(((ReadOnlyMemory<char>)(object)memory), out string text, out int start, out length)) if (!MemoryMarshal.TryGetString((ReadOnlyMemory<char>)(object)memory, out string text, out int start, out length))
ThrowHelper.ThrowInvalidOperationException(); ThrowHelper.ThrowInvalidOperationException();
_sequenceStart = new SequencePosition(text, ReadOnlySequence.StringToSequenceStart(start)); _startObject = text;
_sequenceEnd = new SequencePosition(text, ReadOnlySequence.StringToSequenceEnd(start + length)); _endObject = text;
_startInteger = ReadOnlySequence.StringToSequenceStart(start);
_endInteger = ReadOnlySequence.StringToSequenceEnd(start + length);
} }
else else
{ {
// Should never be reached // Should never be reached
ThrowHelper.ThrowInvalidOperationException(); ThrowHelper.ThrowInvalidOperationException();
_sequenceStart = default; _startObject = null;
_sequenceEnd = default; _endObject = null;
_startInteger = 0;
_endInteger = 0;
} }
} }
/// <summary> /// <summary>
/// Forms a slice out of the given <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/>, with <paramref name="length"/> items /// Forms a slice out of the current <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/>, with <paramref name="length"/> items.
/// </summary> /// </summary>
/// <param name="start">The index at which to begin this slice.</param> /// <param name="start">The index at which to begin this slice.</param>
/// <param name="length">The length of the slice</param> /// <param name="length">The length of the slice.</param>
/// <returns>A slice that consists of <paramref name="length" /> elements from the current instance starting at index <paramref name="start" />.</returns>
public ReadOnlySequence<T> Slice(long start, long length) public ReadOnlySequence<T> Slice(long start, long length)
{ {
if (start < 0 || length < 0) if (start < 0 || length < 0)
@ -169,11 +199,11 @@ namespace System.Buffers
SequencePosition begin; SequencePosition begin;
SequencePosition end; SequencePosition end;
int startIndex = GetIndex(_sequenceStart); int startIndex = GetIndex(_startInteger);
int endIndex = GetIndex(_sequenceEnd); int endIndex = GetIndex(_endInteger);
object startObject = _sequenceStart.GetObject(); object startObject = _startObject;
object endObject = _sequenceEnd.GetObject(); object endObject = _endObject;
if (startObject != endObject) if (startObject != endObject)
{ {
@ -232,23 +262,30 @@ namespace System.Buffers
} }
/// <summary> /// <summary>
/// Forms a slice out of the given <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/>, ending at <paramref name="end"/> (inclusive). /// Forms a slice out of the current <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/> and ending at <paramref name="end"/> (exclusive).
/// </summary> /// </summary>
/// <param name="start">The index at which to begin this slice.</param> /// <param name="start">The index at which to begin this slice.</param>
/// <param name="end">The end (inclusive) of the slice</param> /// <param name="end">The ending (exclusive) <see cref="SequencePosition"/> of the slice.</param>
/// <returns>A slice that consists of items from the <paramref name="start" /> index to, but not including, the <paramref name="end" /> sequence position in the current read-only sequence.</returns>
public ReadOnlySequence<T> Slice(long start, SequencePosition end) public ReadOnlySequence<T> Slice(long start, SequencePosition end)
{ {
if (start < 0) if (start < 0)
ThrowHelper.ThrowStartOrEndArgumentValidationException(start); ThrowHelper.ThrowStartOrEndArgumentValidationException(start);
uint startIndex = (uint)GetIndex(_startInteger);
object startObject = _startObject;
uint endIndex = (uint)GetIndex(_endInteger);
object endObject = _endObject;
uint sliceEndIndex = (uint)GetIndex(end); uint sliceEndIndex = (uint)GetIndex(end);
object sliceEndObject = end.GetObject(); object sliceEndObject = end.GetObject();
uint startIndex = (uint)GetIndex(_sequenceStart); if (sliceEndObject == null)
object startObject = _sequenceStart.GetObject(); {
sliceEndObject = _startObject;
uint endIndex = (uint)GetIndex(_sequenceEnd); sliceEndIndex = startIndex;
object endObject = _sequenceEnd.GetObject(); }
// Single-Segment Sequence // Single-Segment Sequence
if (startObject == endObject) if (startObject == endObject)
@ -300,25 +337,32 @@ namespace System.Buffers
FoundInFirstSegment: FoundInFirstSegment:
// startIndex + start <= int.MaxValue // startIndex + start <= int.MaxValue
Debug.Assert(start <= int.MaxValue - startIndex); Debug.Assert(start <= int.MaxValue - startIndex);
return SliceImpl(new SequencePosition(startObject, (int)startIndex + (int)start), end); return SliceImpl(new SequencePosition(startObject, (int)startIndex + (int)start), new SequencePosition(sliceEndObject, (int)sliceEndIndex));
} }
/// <summary> /// <summary>
/// Forms a slice out of the given <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/>, with <paramref name="length"/> items /// Forms a slice out of the current <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/>, with <paramref name="length"/> items.
/// </summary> /// </summary>
/// <param name="start">The starting (inclusive) <see cref="SequencePosition"/> at which to begin this slice.</param> /// <param name="start">The starting (inclusive) <see cref="SequencePosition"/> at which to begin this slice.</param>
/// <param name="length">The length of the slice</param> /// <param name="length">The length of the slice.</param>
/// <returns>A slice that consists of <paramref name="length" /> elements from the current instance starting at sequence position <paramref name="start" />.</returns>
public ReadOnlySequence<T> Slice(SequencePosition start, long length) public ReadOnlySequence<T> Slice(SequencePosition start, long length)
{ {
uint startIndex = (uint)GetIndex(_startInteger);
object startObject = _startObject;
uint endIndex = (uint)GetIndex(_endInteger);
object endObject = _endObject;
// Check start before length // Check start before length
uint sliceStartIndex = (uint)GetIndex(start); uint sliceStartIndex = (uint)GetIndex(start);
object sliceStartObject = start.GetObject(); object sliceStartObject = start.GetObject();
uint startIndex = (uint)GetIndex(_sequenceStart); if (sliceStartObject == null)
object startObject = _sequenceStart.GetObject(); {
sliceStartIndex = startIndex;
uint endIndex = (uint)GetIndex(_sequenceEnd); sliceStartObject = _startObject;
object endObject = _sequenceEnd.GetObject(); }
// Single-Segment Sequence // Single-Segment Sequence
if (startObject == endObject) if (startObject == endObject)
@ -376,35 +420,39 @@ namespace System.Buffers
FoundInFirstSegment: FoundInFirstSegment:
// sliceStartIndex + length <= int.MaxValue // sliceStartIndex + length <= int.MaxValue
Debug.Assert(length <= int.MaxValue - sliceStartIndex); Debug.Assert(length <= int.MaxValue - sliceStartIndex);
return SliceImpl(start, new SequencePosition(sliceStartObject, (int)sliceStartIndex + (int)length)); return SliceImpl(new SequencePosition(sliceStartObject, (int)sliceStartIndex), new SequencePosition(sliceStartObject, (int)sliceStartIndex + (int)length));
} }
/// <summary> /// <summary>
/// Forms a slice out of the given <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/>, with <paramref name="length"/> items /// Forms a slice out of the current <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/>, with <paramref name="length"/> items.
/// </summary> /// </summary>
/// <param name="start">The index at which to begin this slice.</param> /// <param name="start">The index at which to begin this slice.</param>
/// <param name="length">The length of the slice</param> /// <param name="length">The length of the slice.</param>
/// <returns>A slice that consists of <paramref name="length" /> elements from the current instance starting at index <paramref name="start" />.</returns>
public ReadOnlySequence<T> Slice(int start, int length) => Slice((long)start, length); public ReadOnlySequence<T> Slice(int start, int length) => Slice((long)start, length);
/// <summary> /// <summary>
/// Forms a slice out of the given <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/>, ending at <paramref name="end"/> (inclusive). /// Forms a slice out of the current <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/> and ending at <paramref name="end"/> (exclusive).
/// </summary> /// </summary>
/// <param name="start">The index at which to begin this slice.</param> /// <param name="start">The index at which to begin this slice.</param>
/// <param name="end">The end (inclusive) of the slice</param> /// <param name="end">The ending (exclusive) <see cref="SequencePosition"/> of the slice.</param>
/// <returns>A slice that consists of items from the <paramref name="start" /> index to, but not including, the <paramref name="end" /> sequence position in the current read-only sequence.</returns>
public ReadOnlySequence<T> Slice(int start, SequencePosition end) => Slice((long)start, end); public ReadOnlySequence<T> Slice(int start, SequencePosition end) => Slice((long)start, end);
/// <summary> /// <summary>
/// Forms a slice out of the given <see cref="ReadOnlySequence{T}"/>, beginning at '<paramref name="start"/>, with <paramref name="length"/> items /// Forms a slice out of the current <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/>, with <paramref name="length"/> items.
/// </summary> /// </summary>
/// <param name="start">The starting (inclusive) <see cref="SequencePosition"/> at which to begin this slice.</param> /// <param name="start">The starting (inclusive) <see cref="SequencePosition"/> at which to begin this slice.</param>
/// <param name="length">The length of the slice</param> /// <param name="length">The length of the slice.</param>
/// <returns>A slice that consists of <paramref name="length" /> elements from the current instance starting at sequence position <paramref name="start" />.</returns>
public ReadOnlySequence<T> Slice(SequencePosition start, int length) => Slice(start, (long)length); public ReadOnlySequence<T> Slice(SequencePosition start, int length) => Slice(start, (long)length);
/// <summary> /// <summary>
/// Forms a slice out of the given <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/>, ending at <paramref name="end"/> (inclusive). /// Forms a slice out of the given <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/>, ending at <paramref name="end"/> (exclusive).
/// </summary> /// </summary>
/// <param name="start">The starting (inclusive) <see cref="SequencePosition"/> at which to begin this slice.</param> /// <param name="start">The starting (inclusive) <see cref="SequencePosition"/> at which to begin this slice.</param>
/// <param name="end">The ending (inclusive) <see cref="SequencePosition"/> of the slice</param> /// <param name="end">The ending (exclusive) <see cref="SequencePosition"/> of the slice.</param>
/// <returns>A slice that consists of items from the <paramref name="start" /> sequence position to, but not including, the <paramref name="end" /> sequence position in the current read-only sequence.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlySequence<T> Slice(SequencePosition start, SequencePosition end) public ReadOnlySequence<T> Slice(SequencePosition start, SequencePosition end)
{ {
@ -413,20 +461,23 @@ namespace System.Buffers
} }
/// <summary> /// <summary>
/// Forms a slice out of the given <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/>, ending at the existing <see cref="ReadOnlySequence{T}"/>'s end. /// Forms a slice out of the current <see cref="ReadOnlySequence{T}" />, beginning at a specified sequence position and continuing to the end of the read-only sequence.
/// </summary> /// </summary>
/// <param name="start">The starting (inclusive) <see cref="SequencePosition"/> at which to begin this slice.</param> /// <param name="start">The starting (inclusive) <see cref="SequencePosition"/> at which to begin this slice.</param>
/// <returns>A slice starting at sequence position <paramref name="start" /> and continuing to the end of the current read-only sequence.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlySequence<T> Slice(SequencePosition start) public ReadOnlySequence<T> Slice(SequencePosition start)
{ {
BoundsCheck(start); bool positionIsNotNull = start.GetObject() != null;
return SliceImpl(start, _sequenceEnd); BoundsCheck(start, positionIsNotNull);
return SliceImpl(positionIsNotNull ? start : Start);
} }
/// <summary> /// <summary>
/// Forms a slice out of the given <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/>, ending at the existing <see cref="ReadOnlySequence{T}"/>'s end. /// Forms a slice out of the current <see cref="ReadOnlySequence{T}" /> , beginning at a specified index and continuing to the end of the read-only sequence.
/// </summary> /// </summary>
/// <param name="start">The start index at which to begin this slice.</param> /// <param name="start">The start index at which to begin this slice.</param>
/// <returns>A slice starting at index <paramref name="start" /> and continuing to the end of the current read-only sequence.</returns>
public ReadOnlySequence<T> Slice(long start) public ReadOnlySequence<T> Slice(long start)
{ {
if (start < 0) if (start < 0)
@ -435,8 +486,8 @@ namespace System.Buffers
if (start == 0) if (start == 0)
return this; return this;
SequencePosition begin = Seek(_sequenceStart, _sequenceEnd, start, ExceptionArgument.start); SequencePosition begin = Seek(start, ExceptionArgument.start);
return SliceImpl(begin, _sequenceEnd); return SliceImpl(begin);
} }
/// <inheritdoc /> /// <inheritdoc />
@ -454,19 +505,7 @@ namespace System.Buffers
if (Length < int.MaxValue) if (Length < int.MaxValue)
{ {
#if !FEATURE_PORTABLE_SPAN return string.Create((int)Length, charSequence, (span, sequence) => sequence.CopyTo(span));
return string.Create((int)Length, charSequence, (span, sequence) =>
{
foreach (ReadOnlyMemory<char> readOnlyMemory in sequence)
{
ReadOnlySpan<char> sourceSpan = readOnlyMemory.Span;
sourceSpan.CopyTo(span);
span = span.Slice(sourceSpan.Length);
}
});
#else
return new string(charSequence.ToArray());
#endif
} }
} }
@ -481,7 +520,13 @@ namespace System.Buffers
/// <summary> /// <summary>
/// Returns a new <see cref="SequencePosition"/> at an <paramref name="offset"/> from the start of the sequence. /// Returns a new <see cref="SequencePosition"/> at an <paramref name="offset"/> from the start of the sequence.
/// </summary> /// </summary>
public SequencePosition GetPosition(long offset) => GetPosition(offset, _sequenceStart); public SequencePosition GetPosition(long offset)
{
if (offset < 0)
ThrowHelper.ThrowArgumentOutOfRangeException_OffsetOutOfRange();
return Seek(offset);
}
/// <summary> /// <summary>
/// Returns a new <see cref="SequencePosition"/> at an <paramref name="offset"/> from the <paramref name="origin"/> /// Returns a new <see cref="SequencePosition"/> at an <paramref name="offset"/> from the <paramref name="origin"/>
@ -491,7 +536,7 @@ namespace System.Buffers
if (offset < 0) if (offset < 0)
ThrowHelper.ThrowArgumentOutOfRangeException_OffsetOutOfRange(); ThrowHelper.ThrowArgumentOutOfRangeException_OffsetOutOfRange();
return Seek(origin, _sequenceEnd, offset, ExceptionArgument.offset); return Seek(origin, offset);
} }
/// <summary> /// <summary>
@ -592,4 +637,4 @@ namespace System.Buffers
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int StringToSequenceEnd(int endIndex) => endIndex | StringEndMask; public static int StringToSequenceEnd(int endIndex) => endIndex | StringEndMask;
} }
} }

View File

@ -4,10 +4,8 @@
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
#if !netstandard
using Internal.Runtime.CompilerServices; using Internal.Runtime.CompilerServices;
#endif
namespace System.Buffers namespace System.Buffers
{ {
@ -26,9 +24,9 @@ namespace System.Buffers
} }
SequenceType type = GetSequenceType(); SequenceType type = GetSequenceType();
object endObject = _sequenceEnd.GetObject(); object endObject = _endObject;
int startIndex = GetIndex(position); int startIndex = GetIndex(position);
int endIndex = GetIndex(_sequenceEnd); int endIndex = GetIndex(_endInteger);
if (type == SequenceType.MultiSegment) if (type == SequenceType.MultiSegment)
{ {
@ -83,15 +81,15 @@ namespace System.Buffers
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private ReadOnlyMemory<T> GetFirstBuffer() private ReadOnlyMemory<T> GetFirstBuffer()
{ {
object startObject = _sequenceStart.GetObject(); object startObject = _startObject;
if (startObject == null) if (startObject == null)
return default; return default;
int startIndex = _sequenceStart.GetInteger(); int startIndex = _startInteger;
int endIndex = _sequenceEnd.GetInteger(); int endIndex = _endInteger;
bool isMultiSegment = startObject != _sequenceEnd.GetObject(); bool isMultiSegment = startObject != _endObject;
// The highest bit of startIndex and endIndex are used to infer the sequence type // The highest bit of startIndex and endIndex are used to infer the sequence type
// The code below is structured this way for performance reasons and is equivalent to the following: // The code below is structured this way for performance reasons and is equivalent to the following:
@ -104,44 +102,51 @@ namespace System.Buffers
// Highest bit of startIndex: A = startIndex >> 31 // Highest bit of startIndex: A = startIndex >> 31
// Highest bit of endIndex: B = endIndex >> 31 // Highest bit of endIndex: B = endIndex >> 31
// A == 0 && B == 0 means SequenceType.MultiSegment
// Equivalent to startIndex >= 0 && endIndex >= 0
if ((startIndex | endIndex) >= 0)
{
ReadOnlyMemory<T> memory = ((ReadOnlySequenceSegment<T>)startObject).Memory;
if (isMultiSegment)
{
return memory.Slice(startIndex);
}
return memory.Slice(startIndex, endIndex - startIndex);
}
else
{
return GetFirstBufferSlow(startObject, isMultiSegment);
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private ReadOnlyMemory<T> GetFirstBufferSlow(object startObject, bool isMultiSegment)
{
if (isMultiSegment)
ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached();
int startIndex = _startInteger;
int endIndex = _endInteger;
Debug.Assert(startIndex < 0 || endIndex < 0);
// A == 0 && B == 1 means SequenceType.Array
if (startIndex >= 0) if (startIndex >= 0)
{ {
// A == 0 && B == 0 means SequenceType.MultiSegment Debug.Assert(endIndex < 0);
// A == 0 && B == 1 means SequenceType.Array return new ReadOnlyMemory<T>((T[])startObject, startIndex, (endIndex & ReadOnlySequence.IndexBitMask) - startIndex);
if (endIndex >= 0) // SequenceType.MultiSegment
{
ReadOnlyMemory<T> memory = ((ReadOnlySequenceSegment<T>)startObject).Memory;
if (isMultiSegment)
{
return memory.Slice(startIndex);
}
return memory.Slice(startIndex, endIndex - startIndex);
}
else // endIndex < 0, SequenceType.Array
{
if (isMultiSegment)
ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached();
return new ReadOnlyMemory<T>((T[])startObject, startIndex, (endIndex & ReadOnlySequence.IndexBitMask) - startIndex);
}
} }
else // startIndex < 0 else
{ {
if (isMultiSegment)
ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached();
// A == 1 && B == 1 means SequenceType.String
// A == 1 && B == 0 means SequenceType.MemoryManager
// The type == char check here is redundant. However, we still have it to allow // The type == char check here is redundant. However, we still have it to allow
// the JIT to see when that the code is unreachable and eliminate it. // the JIT to see when that the code is unreachable and eliminate it.
if (typeof(T) == typeof(char) && endIndex < 0) // SequenceType.String // A == 1 && B == 1 means SequenceType.String
if (typeof(T) == typeof(char) && endIndex < 0)
{ {
// No need to remove the FlagBitMask since (endIndex - startIndex) == (endIndex & ReadOnlySequence.IndexBitMask) - (startIndex & ReadOnlySequence.IndexBitMask) // No need to remove the FlagBitMask since (endIndex - startIndex) == (endIndex & ReadOnlySequence.IndexBitMask) - (startIndex & ReadOnlySequence.IndexBitMask)
return (ReadOnlyMemory<T>)(object)((string)startObject).AsMemory((startIndex & ReadOnlySequence.IndexBitMask), endIndex - startIndex); return (ReadOnlyMemory<T>)(object)((string)startObject).AsMemory(startIndex & ReadOnlySequence.IndexBitMask, endIndex - startIndex);
} }
else // endIndex >= 0, SequenceType.MemoryManager else // endIndex >= 0, A == 1 && B == 0 means SequenceType.MemoryManager
{ {
startIndex &= ReadOnlySequence.IndexBitMask; startIndex &= ReadOnlySequence.IndexBitMask;
return ((MemoryManager<T>)startObject).Memory.Slice(startIndex, endIndex - startIndex); return ((MemoryManager<T>)startObject).Memory.Slice(startIndex, endIndex - startIndex);
@ -150,13 +155,90 @@ namespace System.Buffers
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private SequencePosition Seek(in SequencePosition start, in SequencePosition end, long offset, ExceptionArgument argument) private ReadOnlySpan<T> GetFirstSpan()
{ {
int startIndex = GetIndex(start); object startObject = _startObject;
int endIndex = GetIndex(end);
object startObject = start.GetObject(); if (startObject == null)
object endObject = end.GetObject(); return default;
int startIndex = _startInteger;
int endIndex = _endInteger;
bool isMultiSegment = startObject != _endObject;
// The highest bit of startIndex and endIndex are used to infer the sequence type
// The code below is structured this way for performance reasons and is equivalent to the following:
// SequenceType type = GetSequenceType();
// if (type == SequenceType.MultiSegment) { ... }
// else if (type == SequenceType.Array) { ... }
// else if (type == SequenceType.String){ ... }
// else if (type == SequenceType.MemoryManager) { ... }
// Highest bit of startIndex: A = startIndex >> 31
// Highest bit of endIndex: B = endIndex >> 31
// A == 0 && B == 0 means SequenceType.MultiSegment
// Equivalent to startIndex >= 0 && endIndex >= 0
if ((startIndex | endIndex) >= 0)
{
ReadOnlySpan<T> span = ((ReadOnlySequenceSegment<T>)startObject).Memory.Span;
if (isMultiSegment)
{
return span.Slice(startIndex);
}
return span.Slice(startIndex, endIndex - startIndex);
}
else
{
return GetFirstSpanSlow(startObject, isMultiSegment);
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private ReadOnlySpan<T> GetFirstSpanSlow(object startObject, bool isMultiSegment)
{
if (isMultiSegment)
ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached();
int startIndex = _startInteger;
int endIndex = _endInteger;
Debug.Assert(startIndex < 0 || endIndex < 0);
// A == 0 && B == 1 means SequenceType.Array
if (startIndex >= 0)
{
Debug.Assert(endIndex < 0);
ReadOnlySpan<T> span = (T[])startObject;
return span.Slice(startIndex, (endIndex & ReadOnlySequence.IndexBitMask) - startIndex);
}
else
{
// The type == char check here is redundant. However, we still have it to allow
// the JIT to see when that the code is unreachable and eliminate it.
// A == 1 && B == 1 means SequenceType.String
if (typeof(T) == typeof(char) && endIndex < 0)
{
var memory = (ReadOnlyMemory<T>)(object)((string)startObject).AsMemory();
// No need to remove the FlagBitMask since (endIndex - startIndex) == (endIndex & ReadOnlySequence.IndexBitMask) - (startIndex & ReadOnlySequence.IndexBitMask)
return memory.Span.Slice(startIndex & ReadOnlySequence.IndexBitMask, endIndex - startIndex);
}
else // endIndex >= 0, A == 1 && B == 0 means SequenceType.MemoryManager
{
startIndex &= ReadOnlySequence.IndexBitMask;
return ((MemoryManager<T>)startObject).Memory.Span.Slice(startIndex, endIndex - startIndex);
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal SequencePosition Seek(long offset, ExceptionArgument exceptionArgument = ExceptionArgument.offset)
{
object startObject = _startObject;
object endObject = _endObject;
int startIndex = GetIndex(_startInteger);
int endIndex = GetIndex(_endInteger);
if (startObject != endObject) if (startObject != endObject)
{ {
@ -173,13 +255,49 @@ namespace System.Buffers
ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange(); ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange();
// End of segment. Move to start of next. // End of segment. Move to start of next.
return SeekMultiSegment(startSegment.Next, endObject, endIndex, offset - currentLength, argument); return SeekMultiSegment(startSegment.Next, endObject, endIndex, offset - currentLength, exceptionArgument);
} }
Debug.Assert(startObject == endObject); Debug.Assert(startObject == endObject);
if (endIndex - startIndex < offset) if (endIndex - startIndex < offset)
ThrowHelper.ThrowArgumentOutOfRangeException(argument); ThrowHelper.ThrowArgumentOutOfRangeException(exceptionArgument);
// Single segment Seek
IsSingleSegment:
return new SequencePosition(startObject, startIndex + (int)offset);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private SequencePosition Seek(in SequencePosition start, long offset)
{
object startObject = start.GetObject();
object endObject = _endObject;
int startIndex = GetIndex(start);
int endIndex = GetIndex(_endInteger);
if (startObject != endObject)
{
Debug.Assert(startObject != null);
var startSegment = (ReadOnlySequenceSegment<T>)startObject;
int currentLength = startSegment.Memory.Length - startIndex;
// Position in start segment, defer to single segment seek
if (currentLength > offset)
goto IsSingleSegment;
if (currentLength < 0)
ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange();
// End of segment. Move to start of next.
return SeekMultiSegment(startSegment.Next, endObject, endIndex, offset - currentLength, ExceptionArgument.offset);
}
Debug.Assert(startObject == endObject);
if (endIndex - startIndex < offset)
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.offset);
// Single segment Seek // Single segment Seek
IsSingleSegment: IsSingleSegment:
@ -189,7 +307,7 @@ namespace System.Buffers
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
private static SequencePosition SeekMultiSegment(ReadOnlySequenceSegment<T> currentSegment, object endObject, int endIndex, long offset, ExceptionArgument argument) private static SequencePosition SeekMultiSegment(ReadOnlySequenceSegment<T> currentSegment, object endObject, int endIndex, long offset, ExceptionArgument argument)
{ {
Debug.Assert(currentSegment != null); Debug.Assert(currentSegment != null); // currentSegment parameter is marked as nullable as the parameter is reused/reassigned in the body
Debug.Assert(offset >= 0); Debug.Assert(offset >= 0);
while (currentSegment != null && currentSegment != endObject) while (currentSegment != null && currentSegment != endObject)
@ -213,14 +331,15 @@ namespace System.Buffers
return new SequencePosition(currentSegment, (int)offset); return new SequencePosition(currentSegment, (int)offset);
} }
private void BoundsCheck(in SequencePosition position) private void BoundsCheck(in SequencePosition position, bool positionIsNotNull)
{ {
uint sliceStartIndex = (uint)GetIndex(position); uint sliceStartIndex = (uint)GetIndex(position);
uint startIndex = (uint)GetIndex(_sequenceStart);
uint endIndex = (uint)GetIndex(_sequenceEnd);
object startObject = _sequenceStart.GetObject(); object startObject = _startObject;
object endObject = _sequenceEnd.GetObject(); object endObject = _endObject;
uint startIndex = (uint)GetIndex(_startInteger);
uint endIndex = (uint)GetIndex(_endInteger);
// Single-Segment Sequence // Single-Segment Sequence
if (startObject == endObject) if (startObject == endObject)
@ -235,8 +354,15 @@ namespace System.Buffers
// Multi-Segment Sequence // Multi-Segment Sequence
// Storing this in a local since it is used twice within InRange() // Storing this in a local since it is used twice within InRange()
ulong startRange = (ulong)(((ReadOnlySequenceSegment<T>)startObject).RunningIndex + startIndex); ulong startRange = (ulong)(((ReadOnlySequenceSegment<T>)startObject).RunningIndex + startIndex);
long runningIndex = 0;
if (positionIsNotNull)
{
Debug.Assert(position.GetObject() != null);
runningIndex = ((ReadOnlySequenceSegment<T>)position.GetObject()).RunningIndex;
}
if (!InRange( if (!InRange(
(ulong)(((ReadOnlySequenceSegment<T>)position.GetObject()).RunningIndex + sliceStartIndex), (ulong)(runningIndex + sliceStartIndex),
startRange, startRange,
(ulong)(((ReadOnlySequenceSegment<T>)endObject).RunningIndex + endIndex))) (ulong)(((ReadOnlySequenceSegment<T>)endObject).RunningIndex + endIndex)))
{ {
@ -247,11 +373,11 @@ namespace System.Buffers
private void BoundsCheck(uint sliceStartIndex, object sliceStartObject, uint sliceEndIndex, object sliceEndObject) private void BoundsCheck(uint sliceStartIndex, object sliceStartObject, uint sliceEndIndex, object sliceEndObject)
{ {
uint startIndex = (uint)GetIndex(_sequenceStart); object startObject = _startObject;
uint endIndex = (uint)GetIndex(_sequenceEnd); object endObject = _endObject;
object startObject = _sequenceStart.GetObject(); uint startIndex = (uint)GetIndex(_startInteger);
object endObject = _sequenceEnd.GetObject(); uint endIndex = (uint)GetIndex(_endInteger);
// Single-Segment Sequence // Single-Segment Sequence
if (startObject == endObject) if (startObject == endObject)
@ -271,8 +397,18 @@ namespace System.Buffers
// This optimization works because we know sliceStartIndex, sliceEndIndex, startIndex, and endIndex are all >= 0 // This optimization works because we know sliceStartIndex, sliceEndIndex, startIndex, and endIndex are all >= 0
Debug.Assert(sliceStartIndex >= 0 && startIndex >= 0 && endIndex >= 0); Debug.Assert(sliceStartIndex >= 0 && startIndex >= 0 && endIndex >= 0);
ulong sliceStartRange = (ulong)(((ReadOnlySequenceSegment<T>)sliceStartObject).RunningIndex + sliceStartIndex); ulong sliceStartRange = sliceStartIndex;
ulong sliceEndRange = (ulong)(((ReadOnlySequenceSegment<T>)sliceEndObject).RunningIndex + sliceEndIndex); ulong sliceEndRange = sliceEndIndex;
if (sliceStartObject != null)
{
sliceStartRange += (ulong)((ReadOnlySequenceSegment<T>)sliceStartObject).RunningIndex;
}
if (sliceEndObject != null)
{
sliceEndRange += (ulong)((ReadOnlySequenceSegment<T>)sliceEndObject).RunningIndex;
}
if (sliceStartRange > sliceEndRange) if (sliceStartRange > sliceEndRange)
ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange(); ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange();
@ -322,12 +458,15 @@ namespace System.Buffers
// start >> 31 = 0, end >> 31 = -1 // start >> 31 = 0, end >> 31 = -1
// 2 * 0 + (-1) = -1, result = (SequenceType)1 // 2 * 0 + (-1) = -1, result = (SequenceType)1
return (SequenceType)(-(2 * (_sequenceStart.GetInteger() >> 31) + (_sequenceEnd.GetInteger() >> 31))); return (SequenceType)(-(2 * (_startInteger >> 31) + (_endInteger >> 31)));
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int GetIndex(in SequencePosition position) => position.GetInteger() & ReadOnlySequence.IndexBitMask; private static int GetIndex(in SequencePosition position) => position.GetInteger() & ReadOnlySequence.IndexBitMask;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int GetIndex(int Integer) => Integer & ReadOnlySequence.IndexBitMask;
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private ReadOnlySequence<T> SliceImpl(in SequencePosition start, in SequencePosition end) private ReadOnlySequence<T> SliceImpl(in SequencePosition start, in SequencePosition end)
{ {
@ -337,19 +476,34 @@ namespace System.Buffers
return new ReadOnlySequence<T>( return new ReadOnlySequence<T>(
start.GetObject(), start.GetObject(),
GetIndex(start) | (_sequenceStart.GetInteger() & ReadOnlySequence.FlagBitMask), GetIndex(start) | (_startInteger & ReadOnlySequence.FlagBitMask),
end.GetObject(), end.GetObject(),
GetIndex(end) | (_sequenceEnd.GetInteger() & ReadOnlySequence.FlagBitMask) GetIndex(end) | (_endInteger & ReadOnlySequence.FlagBitMask)
);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private ReadOnlySequence<T> SliceImpl(in SequencePosition start)
{
// In this method we reset high order bits from indices
// of positions that were passed in
// and apply type bits specific for current ReadOnlySequence type
return new ReadOnlySequence<T>(
start.GetObject(),
GetIndex(start) | (_startInteger & ReadOnlySequence.FlagBitMask),
_endObject,
_endInteger
); );
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private long GetLength() private long GetLength()
{ {
int startIndex = GetIndex(_sequenceStart); object startObject = _startObject;
int endIndex = GetIndex(_sequenceEnd); object endObject = _endObject;
object startObject = _sequenceStart.GetObject(); int startIndex = GetIndex(_startInteger);
object endObject = _sequenceEnd.GetObject(); int endIndex = GetIndex(_endInteger);
if (startObject != endObject) if (startObject != endObject)
{ {
@ -365,7 +519,7 @@ namespace System.Buffers
internal bool TryGetReadOnlySequenceSegment(out ReadOnlySequenceSegment<T> startSegment, out int startIndex, out ReadOnlySequenceSegment<T> endSegment, out int endIndex) internal bool TryGetReadOnlySequenceSegment(out ReadOnlySequenceSegment<T> startSegment, out int startIndex, out ReadOnlySequenceSegment<T> endSegment, out int endIndex)
{ {
object startObject = _sequenceStart.GetObject(); object startObject = _startObject;
// Default or not MultiSegment // Default or not MultiSegment
if (startObject == null || GetSequenceType() != SequenceType.MultiSegment) if (startObject == null || GetSequenceType() != SequenceType.MultiSegment)
@ -376,13 +530,13 @@ namespace System.Buffers
endIndex = 0; endIndex = 0;
return false; return false;
} }
Debug.Assert(_sequenceEnd.GetObject() != null); Debug.Assert(_endObject != null);
startSegment = (ReadOnlySequenceSegment<T>)startObject; startSegment = (ReadOnlySequenceSegment<T>)startObject;
startIndex = GetIndex(_sequenceStart); startIndex = GetIndex(_startInteger);
endSegment = (ReadOnlySequenceSegment<T>)_sequenceEnd.GetObject(); endSegment = (ReadOnlySequenceSegment<T>)_endObject;
endIndex = GetIndex(_sequenceEnd); endIndex = GetIndex(_endInteger);
return true; return true;
} }
@ -394,10 +548,10 @@ namespace System.Buffers
return false; return false;
} }
Debug.Assert(_sequenceStart.GetObject() != null); Debug.Assert(_startObject != null);
int startIndex = GetIndex(_sequenceStart); int startIndex = GetIndex(_startInteger);
segment = new ArraySegment<T>((T[])_sequenceStart.GetObject(), startIndex, GetIndex(_sequenceEnd) - startIndex); segment = new ArraySegment<T>((T[])_startObject, startIndex, GetIndex(_endInteger) - startIndex);
return true; return true;
} }
@ -411,11 +565,11 @@ namespace System.Buffers
return false; return false;
} }
Debug.Assert(_sequenceStart.GetObject() != null); Debug.Assert(_startObject != null);
start = GetIndex(_sequenceStart); start = GetIndex(_startInteger);
length = GetIndex(_sequenceEnd) - start; length = GetIndex(_endInteger) - start;
text = (string)_sequenceStart.GetObject(); text = (string)_startObject;
return true; return true;
} }
@ -432,7 +586,7 @@ namespace System.Buffers
// The case, value < start, is invalid. // The case, value < start, is invalid.
// In that case, (value - start) would underflow becoming larger than int.MaxValue. // In that case, (value - start) would underflow becoming larger than int.MaxValue.
// (end - start) can never underflow and hence must be within 0 and int.MaxValue. // (end - start) can never underflow and hence must be within 0 and int.MaxValue.
// So, we will correctly return false. // So, we will correctly return false.
// The case, value > end, is invalid. // The case, value > end, is invalid.
@ -441,7 +595,7 @@ namespace System.Buffers
// In all other cases, value is valid, and we return true. // In all other cases, value is valid, and we return true.
// Equivalent to: return (start <= value && value <= start) // Equivalent to: return (start <= value && value <= end)
return (value - start) <= (end - start); return (value - start) <= (end - start);
} }
@ -458,7 +612,7 @@ namespace System.Buffers
// The case, value < start, is invalid. // The case, value < start, is invalid.
// In that case, (value - start) would underflow becoming larger than long.MaxValue. // In that case, (value - start) would underflow becoming larger than long.MaxValue.
// (end - start) can never underflow and hence must be within 0 and long.MaxValue. // (end - start) can never underflow and hence must be within 0 and long.MaxValue.
// So, we will correctly return false. // So, we will correctly return false.
// The case, value > end, is invalid. // The case, value > end, is invalid.
@ -470,5 +624,79 @@ namespace System.Buffers
// Equivalent to: return (start <= value && value <= start) // Equivalent to: return (start <= value && value <= start)
return (value - start) <= (end - start); return (value - start) <= (end - start);
} }
/// <summary>
/// Helper to efficiently prepare the <see cref="SequenceReader{T}"/>
/// </summary>
/// <param name="first">The first span in the sequence.</param>
/// <param name="next">The next position.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void GetFirstSpan(out ReadOnlySpan<T> first, out SequencePosition next)
{
first = default;
next = default;
object startObject = _startObject;
int startIndex = _startInteger;
if (startObject != null)
{
bool hasMultipleSegments = startObject != _endObject;
int endIndex = _endInteger;
if (startIndex >= 0)
{
if (endIndex >= 0)
{
// Positive start and end index == ReadOnlySequenceSegment<T>
ReadOnlySequenceSegment<T> segment = (ReadOnlySequenceSegment<T>)startObject;
next = new SequencePosition(segment.Next, 0);
first = segment.Memory.Span;
if (hasMultipleSegments)
{
first = first.Slice(startIndex);
}
else
{
first = first.Slice(startIndex, endIndex - startIndex);
}
}
else
{
// Positive start and negative end index == T[]
if (hasMultipleSegments)
ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached();
first = new ReadOnlySpan<T>((T[])startObject, startIndex, (endIndex & ReadOnlySequence.IndexBitMask) - startIndex);
}
}
else
{
first = GetFirstSpanSlow(startObject, startIndex, endIndex, hasMultipleSegments);
}
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static ReadOnlySpan<T> GetFirstSpanSlow(object startObject, int startIndex, int endIndex, bool hasMultipleSegments)
{
Debug.Assert(startIndex < 0);
if (hasMultipleSegments)
ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached();
// The type == char check here is redundant. However, we still have it to allow
// the JIT to see when that the code is unreachable and eliminate it.
if (typeof(T) == typeof(char) && endIndex < 0)
{
// Negative start and negative end index == string
ReadOnlySpan<char> spanOfChar = ((string)startObject).AsSpan(startIndex & ReadOnlySequence.IndexBitMask, endIndex - startIndex);
return MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As<char, T>(ref MemoryMarshal.GetReference(spanOfChar)), spanOfChar.Length);
}
else
{
// Negative start and positive end index == MemoryManager<T>
startIndex &= ReadOnlySequence.IndexBitMask;
return ((MemoryManager<T>)startObject).Memory.Span.Slice(startIndex, endIndex - startIndex);
}
}
} }
} }

View File

@ -67,12 +67,34 @@ namespace System.Buffers
public static implicit operator StandardFormat(char symbol) => new StandardFormat(symbol); public static implicit operator StandardFormat(char symbol) => new StandardFormat(symbol);
/// <summary> /// <summary>
/// Converts a classic .NET format string into a StandardFormat /// Converts a <see cref="ReadOnlySpan{Char}"/> into a StandardFormat
/// </summary> /// </summary>
public static StandardFormat Parse(ReadOnlySpan<char> format) public static StandardFormat Parse(ReadOnlySpan<char> format)
{ {
ParseHelper(format, out StandardFormat standardFormat, throws: true);
return standardFormat;
}
/// <summary>
/// Converts a classic .NET format string into a StandardFormat
/// </summary>
public static StandardFormat Parse(string format) => format == null ? default : Parse(format.AsSpan());
/// <summary>
/// Tries to convert a <see cref="ReadOnlySpan{Char}"/> into a StandardFormat. A return value indicates whether the conversion succeeded or failed.
/// </summary>
public static bool TryParse(ReadOnlySpan<char> format, out StandardFormat result)
{
return ParseHelper(format, out result);
}
private static bool ParseHelper(ReadOnlySpan<char> format, out StandardFormat standardFormat, bool throws = false)
{
standardFormat = default;
if (format.Length == 0) if (format.Length == 0)
return default; return true;
char symbol = format[0]; char symbol = format[0];
byte precision; byte precision;
@ -87,24 +109,23 @@ namespace System.Buffers
{ {
uint digit = format[srcIndex] - 48u; // '0' uint digit = format[srcIndex] - 48u; // '0'
if (digit > 9) if (digit > 9)
throw new FormatException(SR.Format(SR.Argument_CannotParsePrecision, MaxPrecision)); {
return throws ? throw new FormatException(SR.Format(SR.Argument_CannotParsePrecision, MaxPrecision)) : false;
}
parsedPrecision = parsedPrecision * 10 + digit; parsedPrecision = parsedPrecision * 10 + digit;
if (parsedPrecision > MaxPrecision) if (parsedPrecision > MaxPrecision)
throw new FormatException(SR.Format(SR.Argument_PrecisionTooLarge, MaxPrecision)); {
return throws ? throw new FormatException(SR.Format(SR.Argument_PrecisionTooLarge, MaxPrecision)) : false;
}
} }
precision = (byte)parsedPrecision; precision = (byte)parsedPrecision;
} }
return new StandardFormat(symbol, precision); standardFormat = new StandardFormat(symbol, precision);
return true;
} }
/// <summary>
/// Converts a classic .NET format string into a StandardFormat
/// </summary>
public static StandardFormat Parse(string format) => format == null ? default : Parse(format.AsSpan());
/// <summary> /// <summary>
/// Returns true if both the Symbol and Precision are equal. /// Returns true if both the Symbol and Precision are equal.
/// </summary> /// </summary>
@ -125,40 +146,54 @@ namespace System.Buffers
/// </summary> /// </summary>
public override string ToString() public override string ToString()
{ {
unsafe Span<char> buffer = stackalloc char[FormatStringLength];
int charsWritten = Format(buffer);
return new string(buffer.Slice(0, charsWritten));
}
/// <summary>The exact buffer length required by <see cref="Format"/>.</summary>
internal const int FormatStringLength = 3;
/// <summary>
/// Formats the format in classic .NET format.
/// </summary>
internal int Format(Span<char> destination)
{
Debug.Assert(destination.Length == FormatStringLength);
int count = 0;
char symbol = Symbol;
if (symbol != default &&
(uint)destination.Length == FormatStringLength) // to eliminate bounds checks
{ {
const int MaxLength = 4; destination[0] = symbol;
char* pBuffer = stackalloc char[MaxLength]; count = 1;
int dstIndex = 0; uint precision = Precision;
char symbol = Symbol; if (precision != NoPrecision)
if (symbol != default)
{ {
pBuffer[dstIndex++] = symbol; // Note that Precision is stored as a byte, so in theory it could contain
// values > MaxPrecision (99). But all supported mechanisms for creating a
// StandardFormat limit values to being <= MaxPrecision, so the only way a value
// could be larger than that is if unsafe code or the equivalent were used
// to force a larger invalid value in, in which case we don't need to
// guarantee such an invalid value is properly roundtripped through here;
// we just need to make sure things aren't corrupted further.
byte precision = Precision; if (precision >= 10)
if (precision != NoPrecision)
{ {
if (precision >= 100) uint div = Math.DivRem(precision, 10, out precision);
{ destination[1] = (char)('0' + div % 10);
pBuffer[dstIndex++] = (char)('0' + (precision / 100) % 10); count = 2;
precision = (byte)(precision % 100);
}
if (precision >= 10)
{
pBuffer[dstIndex++] = (char)('0' + (precision / 10) % 10);
precision = (byte)(precision % 10);
}
pBuffer[dstIndex++] = (char)('0' + precision);
} }
destination[count] = (char)('0' + precision);
count++;
} }
Debug.Assert(dstIndex <= MaxLength);
return new string(pBuffer, startIndex: 0, length: dstIndex);
} }
return count;
} }
/// <summary> /// <summary>

View File

@ -57,5 +57,29 @@ namespace System.Runtime.InteropServices
{ {
return sequence.TryGetString(out text, out start, out length); return sequence.TryGetString(out text, out start, out length);
} }
/// <summary>
/// Try to read the given type out of the buffer if possible. Warning: this is dangerous to use with arbitrary
/// structs- see remarks for full details.
/// </summary>
/// <remarks>
/// IMPORTANT: The read is a straight copy of bits. If a struct depends on specific state of it's members to
/// behave correctly this can lead to exceptions, etc. If reading endian specific integers, use the explicit
/// overloads such as <see cref="SequenceReaderExtensions.TryReadLittleEndian(ref SequenceReader{byte}, out int)"/>
/// </remarks>
/// <returns>
/// True if successful. <paramref name="value"/> will be default if failed (due to lack of space).
/// </returns>
#if __MonoCS__
public static bool TryRead<T>(ref SequenceReader<byte> reader, out T value)
{
throw new PlatformNotSupportedException();
}
#else
public static bool TryRead<T>(ref SequenceReader<byte> reader, out T value) where T : unmanaged
{
return reader.TryRead<T>(out value);
}
#endif
} }
} }

View File

@ -41,7 +41,7 @@ static partial class Consts
// Use these assembly version constants to make code more maintainable. // Use these assembly version constants to make code more maintainable.
// //
public const string MonoVersion = "6.6.0.102"; public const string MonoVersion = "6.6.0.103";
public const string MonoCompany = "Mono development team"; public const string MonoCompany = "Mono development team";
public const string MonoProduct = "Mono Common Language Infrastructure"; public const string MonoProduct = "Mono Common Language Infrastructure";
public const string MonoCopyright = "(c) Various Mono authors"; public const string MonoCopyright = "(c) Various Mono authors";

View File

@ -38,7 +38,7 @@ doc-update-recursive:
@echo "do not recurse the Facades folder" @echo "do not recurse the Facades folder"
System System.Core System.ComponentModel.DataAnnotations System.Numerics System.Numerics.Vectors System.Runtime.Serialization System.Transactions System.Xml \ System System.Core System.ComponentModel.DataAnnotations System.Numerics System.Numerics.Vectors System.Runtime.Serialization System.Transactions System.Xml \
System.ComponentModel.Composition System.ServiceModel System.Xml.Linq System.Data System.IO.Compression.FileSystem System.Runtime.InteropServices.RuntimeInformation \ System.ComponentModel.Composition System.ServiceModel System.Xml.Linq System.Data System.Data.DataSetExtensions System.IO.Compression.FileSystem System.Runtime.InteropServices.RuntimeInformation \
System.ServiceProcess System.Security System.Net.Http.WebRequest System.Net.Http System.ServiceProcess System.IO.Compression System.IdentityModel System.Web \ System.ServiceProcess System.Security System.Net.Http.WebRequest System.Net.Http System.ServiceProcess System.IO.Compression System.IdentityModel System.Web \
Facades/System.Drawing.Primitives Facades/System.Drawing.Common System.Drawing System.Web.Services: Facades/System.Drawing.Primitives Facades/System.Drawing.Common System.Drawing System.Web.Services:

View File

@ -22,13 +22,13 @@ ifeq ($(PROFILE),build)
LIB_MCS_FLAGS += -d:SYSTEM_WEB_IMPLEMENTATION LIB_MCS_FLAGS += -d:SYSTEM_WEB_IMPLEMENTATION
else ifeq ($(PROFILE),wasm) else ifeq ($(PROFILE),wasm)
LIB_MCS_FLAGS += -d:SYSTEM_WEB_IMPLEMENTATION -unsafe LIB_MCS_FLAGS += -d:SYSTEM_WEB_IMPLEMENTATION -unsafe
LIB_REFS += System.Transactions System.Runtime.Serialization System.Data LIB_REFS += System.Transactions System.Runtime.Serialization System.Data System.Data.DataSetExtensions
else ifeq ($(PROFILE),xammac_net_4_5) else ifeq ($(PROFILE),xammac_net_4_5)
LIB_REFS += System.Web.Services System.Transactions System.Runtime.Serialization System.Data LIB_REFS += System.Web.Services System.Transactions System.Runtime.Serialization System.Data System.Data.DataSetExtensions
else ifeq (2.1, $(FRAMEWORK_VERSION)) else ifeq (2.1, $(FRAMEWORK_VERSION))
LIB_REFS += System.Web.Services System.Transactions System.Runtime.Serialization System.Data LIB_REFS += System.Web.Services System.Transactions System.Runtime.Serialization System.Data System.Data.DataSetExtensions
else else
LIB_REFS += System.Web System.Transactions System.Runtime.Serialization System.Data LIB_REFS += System.Web System.Transactions System.Runtime.Serialization System.Data System.Data.DataSetExtensions
endif endif
ifneq (,$(filter build net_4_x, $(PROFILE))) ifneq (,$(filter build net_4_x, $(PROFILE)))

View File

@ -1 +1 @@
319613988894e958c40cdcd218190a7ad2d6b27d fb4d2c7be36bfbed1a1cb06fa9f7d9e3243ddfed

View File

@ -77,6 +77,7 @@ mobile_common_dirs_parallel := \
System.Numerics \ System.Numerics \
System.Numerics.Vectors \ System.Numerics.Vectors \
System.Data \ System.Data \
System.Data.DataSetExtensions \
Mono.Data.Sqlite \ Mono.Data.Sqlite \
System.Data.Services.Client \ System.Data.Services.Client \
System.IO.Compression \ System.IO.Compression \
@ -179,6 +180,7 @@ wasm_dirs_parallel := \
System.ServiceModel.Internals \ System.ServiceModel.Internals \
System.Runtime.Serialization \ System.Runtime.Serialization \
System.Data \ System.Data \
System.Data.DataSetExtensions \
System.Xml.Linq \ System.Xml.Linq \
System.Numerics \ System.Numerics \
System.Numerics.Vectors \ System.Numerics.Vectors \
@ -213,6 +215,7 @@ xammac_4_5_dirs_parallel := \
System.Transactions \ System.Transactions \
System.EnterpriseServices \ System.EnterpriseServices \
System.Data \ System.Data \
System.Data.DataSetExtensions \
System.Runtime.Serialization \ System.Runtime.Serialization \
System.Xml.Linq \ System.Xml.Linq \
Mono.Data.Sqlite \ Mono.Data.Sqlite \

View File

@ -0,0 +1,185 @@
// 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.Diagnostics;
namespace System.Buffers
{
/// <summary>
/// Represents a heap-based, array-backed output sink into which <typeparam name="T"/> data can be written.
/// </summary>
public sealed class ArrayBufferWriter<T> : IBufferWriter<T>
{
private T[] _buffer;
private int _index;
private const int DefaultInitialBufferSize = 256;
/// <summary>
/// Creates an instance of an <see cref="ArrayBufferWriter{T}"/>, in which data can be written to,
/// with the default initial capacity.
/// </summary>
public ArrayBufferWriter()
{
_buffer = Array.Empty<T>();
_index = 0;
}
/// <summary>
/// Creates an instance of an <see cref="ArrayBufferWriter{T}"/>, in which data can be written to,
/// with an initial capacity specified.
/// </summary>
/// <param name="initialCapacity">The minimum capacity with which to initialize the underlying buffer.</param>
/// <exception cref="ArgumentException">
/// Thrown when <paramref name="initialCapacity"/> is not positive (i.e. less than or equal to 0).
/// </exception>
public ArrayBufferWriter(int initialCapacity)
{
if (initialCapacity <= 0)
throw new ArgumentException(nameof(initialCapacity));
_buffer = new T[initialCapacity];
_index = 0;
}
/// <summary>
/// Returns the data written to the underlying buffer so far, as a <see cref="ReadOnlyMemory{T}"/>.
/// </summary>
public ReadOnlyMemory<T> WrittenMemory => _buffer.AsMemory(0, _index);
/// <summary>
/// Returns the data written to the underlying buffer so far, as a <see cref="ReadOnlySpan{T}"/>.
/// </summary>
public ReadOnlySpan<T> WrittenSpan => _buffer.AsSpan(0, _index);
/// <summary>
/// Returns the amount of data written to the underlying buffer so far.
/// </summary>
public int WrittenCount => _index;
/// <summary>
/// Returns the total amount of space within the underlying buffer.
/// </summary>
public int Capacity => _buffer.Length;
/// <summary>
/// Returns the amount of space available that can still be written into without forcing the underlying buffer to grow.
/// </summary>
public int FreeCapacity => _buffer.Length - _index;
/// <summary>
/// Clears the data written to the underlying buffer.
/// </summary>
/// <remarks>
/// You must clear the <see cref="ArrayBufferWriter{T}"/> before trying to re-use it.
/// </remarks>
public void Clear()
{
Debug.Assert(_buffer.Length >= _index);
_buffer.AsSpan(0, _index).Clear();
_index = 0;
}
/// <summary>
/// Notifies <see cref="IBufferWriter{T}"/> that <paramref name="count"/> amount of data was written to the output <see cref="Span{T}"/>/<see cref="Memory{T}"/>
/// </summary>
/// <exception cref="ArgumentException">
/// Thrown when <paramref name="count"/> is negative.
/// </exception>
/// <exception cref="InvalidOperationException">
/// Thrown when attempting to advance past the end of the underlying buffer.
/// </exception>
/// <remarks>
/// You must request a new buffer after calling Advance to continue writing more data and cannot write to a previously acquired buffer.
/// </remarks>
public void Advance(int count)
{
if (count < 0)
throw new ArgumentException(nameof(count));
if (_index > _buffer.Length - count)
ThrowInvalidOperationException_AdvancedTooFar(_buffer.Length);
_index += count;
}
/// <summary>
/// Returns a <see cref="Memory{T}"/> to write to that is at least the requested length (specified by <paramref name="sizeHint"/>).
/// If no <paramref name="sizeHint"/> is provided (or it's equal to <code>0</code>), some non-empty buffer is returned.
/// </summary>
/// <exception cref="ArgumentException">
/// Thrown when <paramref name="sizeHint"/> is negative.
/// </exception>
/// <remarks>
/// This will never return an empty <see cref="Memory{T}"/>.
/// </remarks>
/// <remarks>
/// There is no guarantee that successive calls will return the same buffer or the same-sized buffer.
/// </remarks>
/// <remarks>
/// You must request a new buffer after calling Advance to continue writing more data and cannot write to a previously acquired buffer.
/// </remarks>
public Memory<T> GetMemory(int sizeHint = 0)
{
CheckAndResizeBuffer(sizeHint);
Debug.Assert(_buffer.Length > _index);
return _buffer.AsMemory(_index);
}
/// <summary>
/// Returns a <see cref="Span{T}"/> to write to that is at least the requested length (specified by <paramref name="sizeHint"/>).
/// If no <paramref name="sizeHint"/> is provided (or it's equal to <code>0</code>), some non-empty buffer is returned.
/// </summary>
/// <exception cref="ArgumentException">
/// Thrown when <paramref name="sizeHint"/> is negative.
/// </exception>
/// <remarks>
/// This will never return an empty <see cref="Span{T}"/>.
/// </remarks>
/// <remarks>
/// There is no guarantee that successive calls will return the same buffer or the same-sized buffer.
/// </remarks>
/// <remarks>
/// You must request a new buffer after calling Advance to continue writing more data and cannot write to a previously acquired buffer.
/// </remarks>
public Span<T> GetSpan(int sizeHint = 0)
{
CheckAndResizeBuffer(sizeHint);
Debug.Assert(_buffer.Length > _index);
return _buffer.AsSpan(_index);
}
private void CheckAndResizeBuffer(int sizeHint)
{
if (sizeHint < 0)
throw new ArgumentException(nameof(sizeHint));
if (sizeHint == 0)
{
sizeHint = 1;
}
if (sizeHint > FreeCapacity)
{
int growBy = Math.Max(sizeHint, _buffer.Length);
if (_buffer.Length == 0)
{
growBy = Math.Max(growBy, DefaultInitialBufferSize);
}
int newSize = checked(_buffer.Length + growBy);
Array.Resize(ref _buffer, newSize);
}
Debug.Assert(FreeCapacity > 0 && FreeCapacity >= sizeHint);
}
private static void ThrowInvalidOperationException_AdvancedTooFar(int capacity)
{
throw new InvalidOperationException(SR.Format(SR.BufferWriterAdvancedTooFar, capacity));
}
}
}

View File

@ -0,0 +1,128 @@
// 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.
namespace System.Diagnostics.CodeAnalysis
{
/// <summary>Specifies that null is allowed as an input even if the corresponding type disallows it.</summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class AllowNullAttribute : Attribute { }
/// <summary>Specifies that null is disallowed as an input even if the corresponding type allows it.</summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class DisallowNullAttribute : Attribute { }
/// <summary>Specifies that an output may be null even if the corresponding type disallows it.</summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class MaybeNullAttribute : Attribute { }
/// <summary>Specifies that an output will not be null even if the corresponding type allows it.</summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class NotNullAttribute : Attribute { }
/// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter may be null even if the corresponding type disallows it.</summary>
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class MaybeNullWhenAttribute : Attribute
{
/// <summary>Initializes the attribute with the specified return value condition.</summary>
/// <param name="returnValue">
/// The return value condition. If the method returns this value, the associated parameter may be null.
/// </param>
public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
/// <summary>Gets the return value condition.</summary>
public bool ReturnValue { get; }
}
/// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter will not be null even if the corresponding type allows it.</summary>
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class NotNullWhenAttribute : Attribute
{
/// <summary>Initializes the attribute with the specified return value condition.</summary>
/// <param name="returnValue">
/// The return value condition. If the method returns this value, the associated parameter will not be null.
/// </param>
public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
/// <summary>Gets the return value condition.</summary>
public bool ReturnValue { get; }
}
/// <summary>Specifies that the output will be non-null if the named parameter is non-null.</summary>
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class NotNullIfNotNullAttribute : Attribute
{
/// <summary>Initializes the attribute with the associated parameter name.</summary>
/// <param name="parameterName">
/// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null.
/// </param>
public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName;
/// <summary>Gets the associated parameter name.</summary>
public string ParameterName { get; }
}
/// <summary>Applied to a method that will never return under any circumstance.</summary>
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class DoesNotReturnAttribute : Attribute { }
/// <summary>Specifies that the method will not return if the associated Boolean parameter is passed the specified value.</summary>
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class DoesNotReturnIfAttribute : Attribute
{
/// <summary>Initializes the attribute with the specified parameter value.</summary>
/// <param name="parameterValue">
/// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to
/// the associated parameter matches this value.
/// </param>
public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue;
/// <summary>Gets the condition parameter value.</summary>
public bool ParameterValue { get; }
}
}

View File

@ -26,4 +26,5 @@ partial class SR
public const string Arg_SwitchExpressionException = "Non-exhaustive switch expression failed to match its input."; public const string Arg_SwitchExpressionException = "Non-exhaustive switch expression failed to match its input.";
public const string SwitchExpressionException_UnmatchedValue = "Unmatched value was {0}."; public const string SwitchExpressionException_UnmatchedValue = "Unmatched value was {0}.";
public const string Argument_InvalidRandomRange = "Range of random number does not contain at least one possibility."; public const string Argument_InvalidRandomRange = "Range of random number does not contain at least one possibility.";
public const string BufferWriterAdvancedTooFar = "Cannot advance past the end of the buffer, which has a size of {0}.";
} }

View File

@ -0,0 +1,778 @@
// 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.Diagnostics;
using System.Runtime.CompilerServices;
namespace System.Buffers
{
#if __MonoCS__
public ref partial struct SequenceReader<T> where T : IEquatable<T>
#else
public ref partial struct SequenceReader<T> where T : unmanaged, IEquatable<T>
#endif
{
/// <summary>
/// Try to read everything up to the given <paramref name="delimiter"/>.
/// </summary>
/// <param name="span">The read data, if any.</param>
/// <param name="delimiter">The delimiter to look for.</param>
/// <param name="advancePastDelimiter">True to move past the <paramref name="delimiter"/> if found.</param>
/// <returns>True if the <paramref name="delimiter"/> was found.</returns>
public bool TryReadTo(out ReadOnlySpan<T> span, T delimiter, bool advancePastDelimiter = true)
{
ReadOnlySpan<T> remaining = UnreadSpan;
int index = remaining.IndexOf(delimiter);
if (index != -1)
{
span = index == 0 ? default : remaining.Slice(0, index);
AdvanceCurrentSpan(index + (advancePastDelimiter ? 1 : 0));
return true;
}
return TryReadToSlow(out span, delimiter, advancePastDelimiter);
}
private bool TryReadToSlow(out ReadOnlySpan<T> span, T delimiter, bool advancePastDelimiter)
{
if (!TryReadToInternal(out ReadOnlySequence<T> sequence, delimiter, advancePastDelimiter, CurrentSpan.Length - CurrentSpanIndex))
{
span = default;
return false;
}
span = sequence.IsSingleSegment ? sequence.First.Span : sequence.ToArray();
return true;
}
/// <summary>
/// Try to read everything up to the given <paramref name="delimiter"/>, ignoring delimiters that are
/// preceded by <paramref name="delimiterEscape"/>.
/// </summary>
/// <param name="span">The read data, if any.</param>
/// <param name="delimiter">The delimiter to look for.</param>
/// <param name="delimiterEscape">If found prior to <paramref name="delimiter"/> it will skip that occurrence.</param>
/// <param name="advancePastDelimiter">True to move past the <paramref name="delimiter"/> if found.</param>
/// <returns>True if the <paramref name="delimiter"/> was found.</returns>
public bool TryReadTo(out ReadOnlySpan<T> span, T delimiter, T delimiterEscape, bool advancePastDelimiter = true)
{
ReadOnlySpan<T> remaining = UnreadSpan;
int index = remaining.IndexOf(delimiter);
if ((index > 0 && !remaining[index - 1].Equals(delimiterEscape)) || index == 0)
{
span = remaining.Slice(0, index);
AdvanceCurrentSpan(index + (advancePastDelimiter ? 1 : 0));
return true;
}
// This delimiter might be skipped, go down the slow path
return TryReadToSlow(out span, delimiter, delimiterEscape, index, advancePastDelimiter);
}
private bool TryReadToSlow(out ReadOnlySpan<T> span, T delimiter, T delimiterEscape, int index, bool advancePastDelimiter)
{
if (!TryReadToSlow(out ReadOnlySequence<T> sequence, delimiter, delimiterEscape, index, advancePastDelimiter))
{
span = default;
return false;
}
Debug.Assert(sequence.Length > 0);
span = sequence.IsSingleSegment ? sequence.First.Span : sequence.ToArray();
return true;
}
private bool TryReadToSlow(out ReadOnlySequence<T> sequence, T delimiter, T delimiterEscape, int index, bool advancePastDelimiter)
{
SequenceReader<T> copy = this;
ReadOnlySpan<T> remaining = UnreadSpan;
bool priorEscape = false;
do
{
if (index >= 0)
{
if (index == 0 && priorEscape)
{
// We were in the escaped state, so skip this delimiter
priorEscape = false;
Advance(index + 1);
remaining = UnreadSpan;
goto Continue;
}
else if (index > 0 && remaining[index - 1].Equals(delimiterEscape))
{
// This delimiter might be skipped
// Count our escapes
int escapeCount = 1;
int i = index - 2;
for (; i >= 0; i--)
{
if (!remaining[i].Equals(delimiterEscape))
break;
}
if (i < 0 && priorEscape)
{
// Started and ended with escape, increment once more
escapeCount++;
}
escapeCount += index - 2 - i;
if ((escapeCount & 1) != 0)
{
// An odd escape count means we're currently escaped,
// skip the delimiter and reset escaped state.
Advance(index + 1);
priorEscape = false;
remaining = UnreadSpan;
goto Continue;
}
}
// Found the delimiter. Move to it, slice, then move past it.
AdvanceCurrentSpan(index);
sequence = Sequence.Slice(copy.Position, Position);
if (advancePastDelimiter)
{
Advance(1);
}
return true;
}
else
{
// No delimiter, need to check the end of the span for odd number of escapes then advance
if (remaining.Length > 0 && remaining[remaining.Length - 1].Equals(delimiterEscape))
{
int escapeCount = 1;
int i = remaining.Length - 2;
for (; i >= 0; i--)
{
if (!remaining[i].Equals(delimiterEscape))
break;
}
escapeCount += remaining.Length - 2 - i;
if (i < 0 && priorEscape)
priorEscape = (escapeCount & 1) == 0; // equivalent to incrementing escapeCount before setting priorEscape
else
priorEscape = (escapeCount & 1) != 0;
}
else
{
priorEscape = false;
}
}
// Nothing in the current span, move to the end, checking for the skip delimiter
AdvanceCurrentSpan(remaining.Length);
remaining = CurrentSpan;
Continue:
index = remaining.IndexOf(delimiter);
} while (!End);
// Didn't find anything, reset our original state.
this = copy;
sequence = default;
return false;
}
/// <summary>
/// Try to read everything up to the given <paramref name="delimiter"/>.
/// </summary>
/// <param name="sequence">The read data, if any.</param>
/// <param name="delimiter">The delimiter to look for.</param>
/// <param name="advancePastDelimiter">True to move past the <paramref name="delimiter"/> if found.</param>
/// <returns>True if the <paramref name="delimiter"/> was found.</returns>
public bool TryReadTo(out ReadOnlySequence<T> sequence, T delimiter, bool advancePastDelimiter = true)
{
return TryReadToInternal(out sequence, delimiter, advancePastDelimiter);
}
private bool TryReadToInternal(out ReadOnlySequence<T> sequence, T delimiter, bool advancePastDelimiter, int skip = 0)
{
Debug.Assert(skip >= 0);
SequenceReader<T> copy = this;
if (skip > 0)
Advance(skip);
ReadOnlySpan<T> remaining = UnreadSpan;
while (_moreData)
{
int index = remaining.IndexOf(delimiter);
if (index != -1)
{
// Found the delimiter. Move to it, slice, then move past it.
if (index > 0)
{
AdvanceCurrentSpan(index);
}
sequence = Sequence.Slice(copy.Position, Position);
if (advancePastDelimiter)
{
Advance(1);
}
return true;
}
AdvanceCurrentSpan(remaining.Length);
remaining = CurrentSpan;
}
// Didn't find anything, reset our original state.
this = copy;
sequence = default;
return false;
}
/// <summary>
/// Try to read everything up to the given <paramref name="delimiter"/>, ignoring delimiters that are
/// preceded by <paramref name="delimiterEscape"/>.
/// </summary>
/// <param name="sequence">The read data, if any.</param>
/// <param name="delimiter">The delimiter to look for.</param>
/// <param name="delimiterEscape">If found prior to <paramref name="delimiter"/> it will skip that occurrence.</param>
/// <param name="advancePastDelimiter">True to move past the <paramref name="delimiter"/> if found.</param>
/// <returns>True if the <paramref name="delimiter"/> was found.</returns>
public bool TryReadTo(out ReadOnlySequence<T> sequence, T delimiter, T delimiterEscape, bool advancePastDelimiter = true)
{
SequenceReader<T> copy = this;
ReadOnlySpan<T> remaining = UnreadSpan;
bool priorEscape = false;
while (_moreData)
{
int index = remaining.IndexOf(delimiter);
if (index != -1)
{
if (index == 0 && priorEscape)
{
// We were in the escaped state, so skip this delimiter
priorEscape = false;
Advance(index + 1);
remaining = UnreadSpan;
continue;
}
else if (index > 0 && remaining[index - 1].Equals(delimiterEscape))
{
// This delimiter might be skipped
// Count our escapes
int escapeCount = 0;
for (int i = index; i > 0 && remaining[i - 1].Equals(delimiterEscape); i--, escapeCount++)
;
if (escapeCount == index && priorEscape)
{
// Started and ended with escape, increment once more
escapeCount++;
}
priorEscape = false;
if ((escapeCount & 1) != 0)
{
// Odd escape count means we're in the escaped state, so skip this delimiter
Advance(index + 1);
remaining = UnreadSpan;
continue;
}
}
// Found the delimiter. Move to it, slice, then move past it.
if (index > 0)
{
Advance(index);
}
sequence = Sequence.Slice(copy.Position, Position);
if (advancePastDelimiter)
{
Advance(1);
}
return true;
}
// No delimiter, need to check the end of the span for odd number of escapes then advance
{
int escapeCount = 0;
for (int i = remaining.Length; i > 0 && remaining[i - 1].Equals(delimiterEscape); i--, escapeCount++)
;
if (priorEscape && escapeCount == remaining.Length)
{
escapeCount++;
}
priorEscape = escapeCount % 2 != 0;
}
// Nothing in the current span, move to the end, checking for the skip delimiter
Advance(remaining.Length);
remaining = CurrentSpan;
}
// Didn't find anything, reset our original state.
this = copy;
sequence = default;
return false;
}
/// <summary>
/// Try to read everything up to the given <paramref name="delimiters"/>.
/// </summary>
/// <param name="span">The read data, if any.</param>
/// <param name="delimiters">The delimiters to look for.</param>
/// <param name="advancePastDelimiter">True to move past the first found instance of any of the given <paramref name="delimiters"/>.</param>
/// <returns>True if any of the <paramref name="delimiters"/> were found.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryReadToAny(out ReadOnlySpan<T> span, ReadOnlySpan<T> delimiters, bool advancePastDelimiter = true)
{
ReadOnlySpan<T> remaining = UnreadSpan;
int index = delimiters.Length == 2
? remaining.IndexOfAny(delimiters[0], delimiters[1])
: remaining.IndexOfAny(delimiters);
if (index != -1)
{
span = remaining.Slice(0, index);
Advance(index + (advancePastDelimiter ? 1 : 0));
return true;
}
return TryReadToAnySlow(out span, delimiters, advancePastDelimiter);
}
private bool TryReadToAnySlow(out ReadOnlySpan<T> span, ReadOnlySpan<T> delimiters, bool advancePastDelimiter)
{
if (!TryReadToAnyInternal(out ReadOnlySequence<T> sequence, delimiters, advancePastDelimiter, CurrentSpan.Length - CurrentSpanIndex))
{
span = default;
return false;
}
span = sequence.IsSingleSegment ? sequence.First.Span : sequence.ToArray();
return true;
}
/// <summary>
/// Try to read everything up to the given <paramref name="delimiters"/>.
/// </summary>
/// <param name="sequence">The read data, if any.</param>
/// <param name="delimiters">The delimiters to look for.</param>
/// <param name="advancePastDelimiter">True to move past the first found instance of any of the given <paramref name="delimiters"/>.</param>
/// <returns>True if any of the <paramref name="delimiters"/> were found.</returns>
public bool TryReadToAny(out ReadOnlySequence<T> sequence, ReadOnlySpan<T> delimiters, bool advancePastDelimiter = true)
{
return TryReadToAnyInternal(out sequence, delimiters, advancePastDelimiter);
}
private bool TryReadToAnyInternal(out ReadOnlySequence<T> sequence, ReadOnlySpan<T> delimiters, bool advancePastDelimiter, int skip = 0)
{
SequenceReader<T> copy = this;
if (skip > 0)
Advance(skip);
ReadOnlySpan<T> remaining = UnreadSpan;
while (!End)
{
int index = delimiters.Length == 2
? remaining.IndexOfAny(delimiters[0], delimiters[1])
: remaining.IndexOfAny(delimiters);
if (index != -1)
{
// Found one of the delimiters. Move to it, slice, then move past it.
if (index > 0)
{
AdvanceCurrentSpan(index);
}
sequence = Sequence.Slice(copy.Position, Position);
if (advancePastDelimiter)
{
Advance(1);
}
return true;
}
Advance(remaining.Length);
remaining = CurrentSpan;
}
// Didn't find anything, reset our original state.
this = copy;
sequence = default;
return false;
}
/// <summary>
/// Try to read data until the entire given <paramref name="delimiter"/> matches.
/// </summary>
/// <param name="sequence">The read data, if any.</param>
/// <param name="delimiter">The multi (T) delimiter.</param>
/// <param name="advancePastDelimiter">True to move past the <paramref name="delimiter"/> if found.</param>
/// <returns>True if the <paramref name="delimiter"/> was found.</returns>
public bool TryReadTo(out ReadOnlySequence<T> sequence, ReadOnlySpan<T> delimiter, bool advancePastDelimiter = true)
{
if (delimiter.Length == 0)
{
sequence = default;
return true;
}
SequenceReader<T> copy = this;
bool advanced = false;
while (!End)
{
if (!TryReadTo(out sequence, delimiter[0], advancePastDelimiter: false))
{
this = copy;
return false;
}
if (delimiter.Length == 1)
{
if (advancePastDelimiter)
{
Advance(1);
}
return true;
}
if (IsNext(delimiter))
{
// Probably a faster way to do this, potentially by avoiding the Advance in the previous TryReadTo call
if (advanced)
{
sequence = copy.Sequence.Slice(copy.Consumed, Consumed - copy.Consumed);
}
if (advancePastDelimiter)
{
Advance(delimiter.Length);
}
return true;
}
else
{
Advance(1);
advanced = true;
}
}
this = copy;
sequence = default;
return false;
}
/// <summary>
/// Advance until the given <paramref name="delimiter"/>, if found.
/// </summary>
/// <param name="delimiter">The delimiter to search for.</param>
/// <param name="advancePastDelimiter">True to move past the <paramref name="delimiter"/> if found.</param>
/// <returns>True if the given <paramref name="delimiter"/> was found.</returns>
public bool TryAdvanceTo(T delimiter, bool advancePastDelimiter = true)
{
ReadOnlySpan<T> remaining = UnreadSpan;
int index = remaining.IndexOf(delimiter);
if (index != -1)
{
Advance(advancePastDelimiter ? index + 1 : index);
return true;
}
return TryReadToInternal(out _, delimiter, advancePastDelimiter);
}
/// <summary>
/// Advance until any of the given <paramref name="delimiters"/>, if found.
/// </summary>
/// <param name="delimiters">The delimiters to search for.</param>
/// <param name="advancePastDelimiter">True to move past the first found instance of any of the given <paramref name="delimiters"/>.</param>
/// <returns>True if any of the given <paramref name="delimiters"/> were found.</returns>
public bool TryAdvanceToAny(ReadOnlySpan<T> delimiters, bool advancePastDelimiter = true)
{
ReadOnlySpan<T> remaining = UnreadSpan;
int index = remaining.IndexOfAny(delimiters);
if (index != -1)
{
AdvanceCurrentSpan(index + (advancePastDelimiter ? 1 : 0));
return true;
}
return TryReadToAnyInternal(out _, delimiters, advancePastDelimiter);
}
/// <summary>
/// Advance past consecutive instances of the given <paramref name="value"/>.
/// </summary>
/// <returns>How many positions the reader has been advanced.</returns>
public long AdvancePast(T value)
{
long start = Consumed;
do
{
// Advance past all matches in the current span
int i;
for (i = CurrentSpanIndex; i < CurrentSpan.Length && CurrentSpan[i].Equals(value); i++)
{
}
int advanced = i - CurrentSpanIndex;
if (advanced == 0)
{
// Didn't advance at all in this span, exit.
break;
}
AdvanceCurrentSpan(advanced);
// If we're at postion 0 after advancing and not at the End,
// we're in a new span and should continue the loop.
} while (CurrentSpanIndex == 0 && !End);
return Consumed - start;
}
/// <summary>
/// Skip consecutive instances of any of the given <paramref name="values"/>.
/// </summary>
/// <returns>How many positions the reader has been advanced.</returns>
public long AdvancePastAny(ReadOnlySpan<T> values)
{
long start = Consumed;
do
{
// Advance past all matches in the current span
int i;
for (i = CurrentSpanIndex; i < CurrentSpan.Length && values.IndexOf(CurrentSpan[i]) != -1; i++)
{
}
int advanced = i - CurrentSpanIndex;
if (advanced == 0)
{
// Didn't advance at all in this span, exit.
break;
}
AdvanceCurrentSpan(advanced);
// If we're at postion 0 after advancing and not at the End,
// we're in a new span and should continue the loop.
} while (CurrentSpanIndex == 0 && !End);
return Consumed - start;
}
/// <summary>
/// Advance past consecutive instances of any of the given values.
/// </summary>
/// <returns>How many positions the reader has been advanced.</returns>
public long AdvancePastAny(T value0, T value1, T value2, T value3)
{
long start = Consumed;
do
{
// Advance past all matches in the current span
int i;
for (i = CurrentSpanIndex; i < CurrentSpan.Length; i++)
{
T value = CurrentSpan[i];
if (!value.Equals(value0) && !value.Equals(value1) && !value.Equals(value2) && !value.Equals(value3))
{
break;
}
}
int advanced = i - CurrentSpanIndex;
if (advanced == 0)
{
// Didn't advance at all in this span, exit.
break;
}
AdvanceCurrentSpan(advanced);
// If we're at postion 0 after advancing and not at the End,
// we're in a new span and should continue the loop.
} while (CurrentSpanIndex == 0 && !End);
return Consumed - start;
}
/// <summary>
/// Advance past consecutive instances of any of the given values.
/// </summary>
/// <returns>How many positions the reader has been advanced.</returns>
public long AdvancePastAny(T value0, T value1, T value2)
{
long start = Consumed;
do
{
// Advance past all matches in the current span
int i;
for (i = CurrentSpanIndex; i < CurrentSpan.Length; i++)
{
T value = CurrentSpan[i];
if (!value.Equals(value0) && !value.Equals(value1) && !value.Equals(value2))
{
break;
}
}
int advanced = i - CurrentSpanIndex;
if (advanced == 0)
{
// Didn't advance at all in this span, exit.
break;
}
AdvanceCurrentSpan(advanced);
// If we're at postion 0 after advancing and not at the End,
// we're in a new span and should continue the loop.
} while (CurrentSpanIndex == 0 && !End);
return Consumed - start;
}
/// <summary>
/// Advance past consecutive instances of any of the given values.
/// </summary>
/// <returns>How many positions the reader has been advanced.</returns>
public long AdvancePastAny(T value0, T value1)
{
long start = Consumed;
do
{
// Advance past all matches in the current span
int i;
for (i = CurrentSpanIndex; i < CurrentSpan.Length; i++)
{
T value = CurrentSpan[i];
if (!value.Equals(value0) && !value.Equals(value1))
{
break;
}
}
int advanced = i - CurrentSpanIndex;
if (advanced == 0)
{
// Didn't advance at all in this span, exit.
break;
}
AdvanceCurrentSpan(advanced);
// If we're at postion 0 after advancing and not at the End,
// we're in a new span and should continue the loop.
} while (CurrentSpanIndex == 0 && !End);
return Consumed - start;
}
/// <summary>
/// Check to see if the given <paramref name="next"/> value is next.
/// </summary>
/// <param name="next">The value to compare the next items to.</param>
/// <param name="advancePast">Move past the <paramref name="next"/> value if found.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsNext(T next, bool advancePast = false)
{
if (End)
return false;
if (CurrentSpan[CurrentSpanIndex].Equals(next))
{
if (advancePast)
{
AdvanceCurrentSpan(1);
}
return true;
}
return false;
}
/// <summary>
/// Check to see if the given <paramref name="next"/> values are next.
/// </summary>
/// <param name="next">The span to compare the next items to.</param>
/// <param name="advancePast">Move past the <paramref name="next"/> values if found.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsNext(ReadOnlySpan<T> next, bool advancePast = false)
{
ReadOnlySpan<T> unread = UnreadSpan;
if (unread.StartsWith(next))
{
if (advancePast)
{
AdvanceCurrentSpan(next.Length);
}
return true;
}
// Only check the slow path if there wasn't enough to satisfy next
return unread.Length < next.Length && IsNextSlow(next, advancePast);
}
private unsafe bool IsNextSlow(ReadOnlySpan<T> next, bool advancePast)
{
ReadOnlySpan<T> currentSpan = UnreadSpan;
// We should only come in here if we need more data than we have in our current span
Debug.Assert(currentSpan.Length < next.Length);
int fullLength = next.Length;
SequencePosition nextPosition = _nextPosition;
while (next.StartsWith(currentSpan))
{
if (next.Length == currentSpan.Length)
{
// Fully matched
if (advancePast)
{
Advance(fullLength);
}
return true;
}
// Need to check the next segment
while (true)
{
if (!Sequence.TryGet(ref nextPosition, out ReadOnlyMemory<T> nextSegment, advance: true))
{
// Nothing left
return false;
}
if (nextSegment.Length > 0)
{
next = next.Slice(currentSpan.Length);
currentSpan = nextSegment.Span;
if (currentSpan.Length > next.Length)
{
currentSpan = currentSpan.Slice(0, next.Length);
}
break;
}
}
}
return false;
}
}
}

View File

@ -0,0 +1,449 @@
// 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.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading;
using Internal.Runtime.CompilerServices;
namespace System.Buffers
{
#if __MonoCS__
public ref partial struct SequenceReader<T> where T : IEquatable<T>
#else
public ref partial struct SequenceReader<T> where T : unmanaged, IEquatable<T>
#endif
{
private SequencePosition _currentPosition;
private SequencePosition _nextPosition;
private bool _moreData;
#if __MonoCS__
private long _length;
#else
private readonly long _length;
#endif
/// <summary>
/// Create a <see cref="SequenceReader{T}"/> over the given <see cref="ReadOnlySequence{T}"/>.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public SequenceReader(ReadOnlySequence<T> sequence)
{
CurrentSpanIndex = 0;
Consumed = 0;
Sequence = sequence;
_currentPosition = sequence.Start;
_length = -1;
sequence.GetFirstSpan(out ReadOnlySpan<T> first, out _nextPosition);
CurrentSpan = first;
_moreData = first.Length > 0;
if (!_moreData && !sequence.IsSingleSegment)
{
_moreData = true;
GetNextSpan();
}
}
/// <summary>
/// True when there is no more data in the <see cref="Sequence"/>.
/// </summary>
#if __MonoCS__
public bool End => !_moreData;
#else
public readonly bool End => !_moreData;
#endif
/// <summary>
/// The underlying <see cref="ReadOnlySequence{T}"/> for the reader.
/// </summary>
#if __MonoCS__
public ReadOnlySequence<T> Sequence { get; }
#else
public readonly ReadOnlySequence<T> Sequence { get; }
#endif
/// <summary>
/// The current position in the <see cref="Sequence"/>.
/// </summary>
#if __MonoCS__
public SequencePosition Position
=> Sequence.GetPosition(CurrentSpanIndex, _currentPosition);
#else
public readonly SequencePosition Position
=> Sequence.GetPosition(CurrentSpanIndex, _currentPosition);
#endif
/// <summary>
/// The current segment in the <see cref="Sequence"/> as a span.
/// </summary>
#if __MonoCS__
public ReadOnlySpan<T> CurrentSpan { get; private set; }
#else
public ReadOnlySpan<T> CurrentSpan { readonly get; private set; }
#endif
/// <summary>
/// The index in the <see cref="CurrentSpan"/>.
/// </summary>
#if __MonoCS__
public int CurrentSpanIndex { get; private set; }
#else
public int CurrentSpanIndex { readonly get; private set; }
#endif
/// <summary>
/// The unread portion of the <see cref="CurrentSpan"/>.
/// </summary>
#if __MonoCS__
public ReadOnlySpan<T> UnreadSpan
#else
public readonly ReadOnlySpan<T> UnreadSpan
#endif
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => CurrentSpan.Slice(CurrentSpanIndex);
}
/// <summary>
/// The total number of <typeparamref name="T"/>'s processed by the reader.
/// </summary>
#if __MonoCS__
public long Consumed { get; private set; }
#else
public long Consumed { readonly get; private set; }
#endif
/// <summary>
/// Remaining <typeparamref name="T"/>'s in the reader's <see cref="Sequence"/>.
/// </summary>
#if __MonoCS__
public long Remaining => Length - Consumed;
#else
public readonly long Remaining => Length - Consumed;
#endif
/// <summary>
/// Count of <typeparamref name="T"/> in the reader's <see cref="Sequence"/>.
/// </summary>
#if __MonoCS__
public long Length
#else
public readonly long Length
#endif
{
get
{
if (_length < 0)
{
unsafe {
fixed (long* lenPtr = &_length)
// Cast-away readonly to initialize lazy field
Volatile.Write(ref Unsafe.AsRef<long>(lenPtr), Sequence.Length);
}
}
return _length;
}
}
/// <summary>
/// Peeks at the next value without advancing the reader.
/// </summary>
/// <param name="value">The next value or default if at the end.</param>
/// <returns>False if at the end of the reader.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#if __MonoCS__
public bool TryPeek(out T value)
#else
public readonly bool TryPeek(out T value)
#endif
{
if (_moreData)
{
value = CurrentSpan[CurrentSpanIndex];
return true;
}
else
{
value = default;
return false;
}
}
/// <summary>
/// Read the next value and advance the reader.
/// </summary>
/// <param name="value">The next value or default if at the end.</param>
/// <returns>False if at the end of the reader.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryRead(out T value)
{
if (End)
{
value = default;
return false;
}
value = CurrentSpan[CurrentSpanIndex];
CurrentSpanIndex++;
Consumed++;
if (CurrentSpanIndex >= CurrentSpan.Length)
{
GetNextSpan();
}
return true;
}
/// <summary>
/// Move the reader back the specified number of items.
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown if trying to rewind a negative amount or more than <see cref="Consumed"/>.
/// </exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Rewind(long count)
{
if ((ulong)count > (ulong)Consumed)
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count);
}
Consumed -= count;
if (CurrentSpanIndex >= count)
{
CurrentSpanIndex -= (int)count;
_moreData = true;
}
else
{
// Current segment doesn't have enough data, scan backward through segments
RetreatToPreviousSpan(Consumed);
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private void RetreatToPreviousSpan(long consumed)
{
ResetReader();
Advance(consumed);
}
private void ResetReader()
{
CurrentSpanIndex = 0;
Consumed = 0;
_currentPosition = Sequence.Start;
_nextPosition = _currentPosition;
if (Sequence.TryGet(ref _nextPosition, out ReadOnlyMemory<T> memory, advance: true))
{
_moreData = true;
if (memory.Length == 0)
{
CurrentSpan = default;
// No data in the first span, move to one with data
GetNextSpan();
}
else
{
CurrentSpan = memory.Span;
}
}
else
{
// No data in any spans and at end of sequence
_moreData = false;
CurrentSpan = default;
}
}
/// <summary>
/// Get the next segment with available data, if any.
/// </summary>
private void GetNextSpan()
{
if (!Sequence.IsSingleSegment)
{
SequencePosition previousNextPosition = _nextPosition;
while (Sequence.TryGet(ref _nextPosition, out ReadOnlyMemory<T> memory, advance: true))
{
_currentPosition = previousNextPosition;
if (memory.Length > 0)
{
CurrentSpan = memory.Span;
CurrentSpanIndex = 0;
return;
}
else
{
CurrentSpan = default;
CurrentSpanIndex = 0;
previousNextPosition = _nextPosition;
}
}
}
_moreData = false;
}
/// <summary>
/// Move the reader ahead the specified number of items.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Advance(long count)
{
const long TooBigOrNegative = unchecked((long)0xFFFFFFFF80000000);
if ((count & TooBigOrNegative) == 0 && CurrentSpan.Length - CurrentSpanIndex > (int)count)
{
CurrentSpanIndex += (int)count;
Consumed += count;
}
else
{
// Can't satisfy from the current span
AdvanceToNextSpan(count);
}
}
/// <summary>
/// Unchecked helper to avoid unnecessary checks where you know count is valid.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void AdvanceCurrentSpan(long count)
{
Debug.Assert(count >= 0);
Consumed += count;
CurrentSpanIndex += (int)count;
if (CurrentSpanIndex >= CurrentSpan.Length)
GetNextSpan();
}
/// <summary>
/// Only call this helper if you know that you are advancing in the current span
/// with valid count and there is no need to fetch the next one.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void AdvanceWithinSpan(long count)
{
Debug.Assert(count >= 0);
Consumed += count;
CurrentSpanIndex += (int)count;
Debug.Assert(CurrentSpanIndex < CurrentSpan.Length);
}
private void AdvanceToNextSpan(long count)
{
if (count < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count);
}
Consumed += count;
while (_moreData)
{
int remaining = CurrentSpan.Length - CurrentSpanIndex;
if (remaining > count)
{
CurrentSpanIndex += (int)count;
count = 0;
break;
}
// As there may not be any further segments we need to
// push the current index to the end of the span.
CurrentSpanIndex += remaining;
count -= remaining;
Debug.Assert(count >= 0);
GetNextSpan();
if (count == 0)
{
break;
}
}
if (count != 0)
{
// Not enough data left- adjust for where we actually ended and throw
Consumed -= count;
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count);
}
}
/// <summary>
/// Copies data from the current <see cref="Position"/> to the given <paramref name="destination"/> span if there
/// is enough data to fill it.
/// </summary>
/// <remarks>
/// This API is used to copy a fixed amount of data out of the sequence if possible. It does not advance
/// the reader. To look ahead for a specific stream of data <see cref="IsNext(ReadOnlySpan{T}, bool)"/> can be used.
/// </remarks>
/// <param name="destination">Destination span to copy to.</param>
/// <returns>True if there is enough data to completely fill the <paramref name="destination"/> span.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#if __MonoCS__
public bool TryCopyTo(Span<T> destination)
#else
public readonly bool TryCopyTo(Span<T> destination)
#endif
{
// This API doesn't advance to facilitate conditional advancement based on the data returned.
// We don't provide an advance option to allow easier utilizing of stack allocated destination spans.
// (Because we can make this method readonly we can guarantee that we won't capture the span.)
ReadOnlySpan<T> firstSpan = UnreadSpan;
if (firstSpan.Length >= destination.Length)
{
firstSpan.Slice(0, destination.Length).CopyTo(destination);
return true;
}
// Not enough in the current span to satisfy the request, fall through to the slow path
return TryCopyMultisegment(destination);
}
#if __MonoCS__
internal bool TryCopyMultisegment(Span<T> destination)
#else
internal readonly bool TryCopyMultisegment(Span<T> destination)
#endif
{
// If we don't have enough to fill the requested buffer, return false
if (Remaining < destination.Length)
return false;
ReadOnlySpan<T> firstSpan = UnreadSpan;
Debug.Assert(firstSpan.Length < destination.Length);
firstSpan.CopyTo(destination);
int copied = firstSpan.Length;
SequencePosition next = _nextPosition;
while (Sequence.TryGet(ref next, out ReadOnlyMemory<T> nextSegment, true))
{
if (nextSegment.Length > 0)
{
ReadOnlySpan<T> nextSpan = nextSegment.Span;
int toCopy = Math.Min(nextSpan.Length, destination.Length - copied);
nextSpan.Slice(0, toCopy).CopyTo(destination.Slice(copied));
copied += toCopy;
if (copied >= destination.Length)
{
break;
}
}
}
return true;
}
}
}

View File

@ -0,0 +1,187 @@
// 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.Buffers.Binary;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Internal.Runtime.CompilerServices;
namespace System.Buffers
{
#if !__MonoCS__
public static partial class SequenceReaderExtensions
{
/// <summary>
/// Try to read the given type out of the buffer if possible. Warning: this is dangerous to use with arbitrary
/// structs- see remarks for full details.
/// </summary>
/// <remarks>
/// IMPORTANT: The read is a straight copy of bits. If a struct depends on specific state of it's members to
/// behave correctly this can lead to exceptions, etc. If reading endian specific integers, use the explicit
/// overloads such as <see cref="TryReadLittleEndian(ref SequenceReader{byte}, out short)"/>
/// </remarks>
/// <returns>
/// True if successful. <paramref name="value"/> will be default if failed (due to lack of space).
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static unsafe bool TryRead<T>(ref this SequenceReader<byte> reader, out T value) where T : unmanaged
{
ReadOnlySpan<byte> span = reader.UnreadSpan;
if (span.Length < sizeof(T))
return TryReadMultisegment(ref reader, out value);
value = Unsafe.ReadUnaligned<T>(ref MemoryMarshal.GetReference(span));
reader.Advance(sizeof(T));
return true;
}
private static unsafe bool TryReadMultisegment<T>(ref SequenceReader<byte> reader, out T value) where T : unmanaged
{
Debug.Assert(reader.UnreadSpan.Length < sizeof(T));
// Not enough data in the current segment, try to peek for the data we need.
T buffer = default;
Span<byte> tempSpan = new Span<byte>(&buffer, sizeof(T));
if (!reader.TryCopyTo(tempSpan))
{
value = default;
return false;
}
value = Unsafe.ReadUnaligned<T>(ref MemoryMarshal.GetReference(tempSpan));
reader.Advance(sizeof(T));
return true;
}
/// <summary>
/// Reads an <see cref="short"/> as little endian.
/// </summary>
/// <returns>False if there wasn't enough data for an <see cref="short"/>.</returns>
public static bool TryReadLittleEndian(ref this SequenceReader<byte> reader, out short value)
{
if (BitConverter.IsLittleEndian)
{
return reader.TryRead(out value);
}
return TryReadReverseEndianness(ref reader, out value);
}
/// <summary>
/// Reads an <see cref="short"/> as big endian.
/// </summary>
/// <returns>False if there wasn't enough data for an <see cref="short"/>.</returns>
public static bool TryReadBigEndian(ref this SequenceReader<byte> reader, out short value)
{
if (!BitConverter.IsLittleEndian)
{
return reader.TryRead(out value);
}
return TryReadReverseEndianness(ref reader, out value);
}
private static bool TryReadReverseEndianness(ref SequenceReader<byte> reader, out short value)
{
if (reader.TryRead(out value))
{
value = BinaryPrimitives.ReverseEndianness(value);
return true;
}
return false;
}
/// <summary>
/// Reads an <see cref="int"/> as little endian.
/// </summary>
/// <returns>False if there wasn't enough data for an <see cref="int"/>.</returns>
public static bool TryReadLittleEndian(ref this SequenceReader<byte> reader, out int value)
{
if (BitConverter.IsLittleEndian)
{
return reader.TryRead(out value);
}
return TryReadReverseEndianness(ref reader, out value);
}
/// <summary>
/// Reads an <see cref="int"/> as big endian.
/// </summary>
/// <returns>False if there wasn't enough data for an <see cref="int"/>.</returns>
public static bool TryReadBigEndian(ref this SequenceReader<byte> reader, out int value)
{
if (!BitConverter.IsLittleEndian)
{
return reader.TryRead(out value);
}
return TryReadReverseEndianness(ref reader, out value);
}
private static bool TryReadReverseEndianness(ref SequenceReader<byte> reader, out int value)
{
if (reader.TryRead(out value))
{
value = BinaryPrimitives.ReverseEndianness(value);
return true;
}
return false;
}
/// <summary>
/// Reads an <see cref="long"/> as little endian.
/// </summary>
/// <returns>False if there wasn't enough data for an <see cref="long"/>.</returns>
public static bool TryReadLittleEndian(ref this SequenceReader<byte> reader, out long value)
{
if (BitConverter.IsLittleEndian)
{
return reader.TryRead(out value);
}
return TryReadReverseEndianness(ref reader, out value);
}
/// <summary>
/// Reads an <see cref="long"/> as big endian.
/// </summary>
/// <returns>False if there wasn't enough data for an <see cref="long"/>.</returns>
public static bool TryReadBigEndian(ref this SequenceReader<byte> reader, out long value)
{
if (!BitConverter.IsLittleEndian)
{
return reader.TryRead(out value);
}
return TryReadReverseEndianness(ref reader, out value);
}
private static bool TryReadReverseEndianness(ref SequenceReader<byte> reader, out long value)
{
if (reader.TryRead(out value))
{
value = BinaryPrimitives.ReverseEndianness(value);
return true;
}
return false;
}
}
#else
public static partial class SequenceReaderExtensions
{
public static bool TryReadBigEndian(this System.Buffers.SequenceReader<byte> reader, out short value) => throw new PlatformNotSupportedException();
public static bool TryReadBigEndian(this System.Buffers.SequenceReader<byte> reader, out int value) => throw new PlatformNotSupportedException();
public static bool TryReadBigEndian(this System.Buffers.SequenceReader<byte> reader, out long value) => throw new PlatformNotSupportedException();
public static bool TryReadLittleEndian(this System.Buffers.SequenceReader<byte> reader, out short value) => throw new PlatformNotSupportedException();
public static bool TryReadLittleEndian(this System.Buffers.SequenceReader<byte> reader, out int value) => throw new PlatformNotSupportedException();
public static bool TryReadLittleEndian(this System.Buffers.SequenceReader<byte> reader, out long value) => throw new PlatformNotSupportedException();
}
#endif
}

View File

@ -1 +1 @@
1bfb37576d4b00841ddf9fd40c66d4e0ecdda8b2 d3b87d5ca787d43652ead46e2ed22cd62e293e8f

View File

@ -1 +1 @@
105fd43c2eec436dcc253a39312c91086c6842f0 e42d54426a1e1d3f1060ba459bf0d7df12630269

View File

@ -1 +1 @@
51372251532be100f5a10fbf3bbc3ddd77ddaa14 cfcf4af8929d3bc8e81a03420da6247493229048

View File

@ -1 +1 @@
2793ab92b134507d7d8a85615bc63a23b2750359 954a63d9fe84b3433462ac32843883482f105840

View File

@ -1 +1 @@
cab1d0a4f39f9199d221a3825546f9e0bb4cb2de cf1cd597492462c59672f2550d25cb1bf1ae63e5

View File

@ -1 +1 @@
a6694cc82436c21501c424b4c279164ce30d2147 4c4d81e0fb06844904ef14d21102e50067085a36

View File

@ -1 +1 @@
3371ccf43d2cb10c02ba09d1de5edacb61d6565e 5ffcec35a847d1faa4aba05efb9a9bdd2b70c1b6

View File

@ -1 +1 @@
54644b539cc9675291076c315786c5954c2f5368 5e1d3ea9834fefadd99b1af3b286bad69f927ee0

View File

@ -1 +1 @@
5dc82bce4a906fc8fb135be826d8b98ece1f68e6 e3b29c54067694c176ab5a6ca5072b8258392587

View File

@ -1 +1 @@
105fd43c2eec436dcc253a39312c91086c6842f0 e42d54426a1e1d3f1060ba459bf0d7df12630269

View File

@ -1 +1 @@
51372251532be100f5a10fbf3bbc3ddd77ddaa14 cfcf4af8929d3bc8e81a03420da6247493229048

View File

@ -1 +1 @@
2793ab92b134507d7d8a85615bc63a23b2750359 954a63d9fe84b3433462ac32843883482f105840

View File

@ -1 +1 @@
cab1d0a4f39f9199d221a3825546f9e0bb4cb2de cf1cd597492462c59672f2550d25cb1bf1ae63e5

View File

@ -1 +1 @@
a6694cc82436c21501c424b4c279164ce30d2147 4c4d81e0fb06844904ef14d21102e50067085a36

View File

@ -1 +1 @@
3371ccf43d2cb10c02ba09d1de5edacb61d6565e 5ffcec35a847d1faa4aba05efb9a9bdd2b70c1b6

View File

@ -1 +1 @@
54644b539cc9675291076c315786c5954c2f5368 5e1d3ea9834fefadd99b1af3b286bad69f927ee0

View File

@ -1 +1 @@
d91e9f2ba309685046e8c0278b5f520245ec8ba4 b06e35d757ace14193649bdf4f5b152bc571d141

View File

@ -1 +1 @@
5dc82bce4a906fc8fb135be826d8b98ece1f68e6 e3b29c54067694c176ab5a6ca5072b8258392587

View File

@ -1 +1 @@
105fd43c2eec436dcc253a39312c91086c6842f0 e42d54426a1e1d3f1060ba459bf0d7df12630269

View File

@ -1 +1 @@
51372251532be100f5a10fbf3bbc3ddd77ddaa14 cfcf4af8929d3bc8e81a03420da6247493229048

View File

@ -1 +1 @@
2793ab92b134507d7d8a85615bc63a23b2750359 954a63d9fe84b3433462ac32843883482f105840

View File

@ -1 +1 @@
cab1d0a4f39f9199d221a3825546f9e0bb4cb2de cf1cd597492462c59672f2550d25cb1bf1ae63e5

View File

@ -1 +1 @@
a6694cc82436c21501c424b4c279164ce30d2147 4c4d81e0fb06844904ef14d21102e50067085a36

View File

@ -1 +1 @@
3371ccf43d2cb10c02ba09d1de5edacb61d6565e 5ffcec35a847d1faa4aba05efb9a9bdd2b70c1b6

View File

@ -1 +1 @@
54644b539cc9675291076c315786c5954c2f5368 5e1d3ea9834fefadd99b1af3b286bad69f927ee0

View File

@ -1 +1 @@
d91e9f2ba309685046e8c0278b5f520245ec8ba4 b06e35d757ace14193649bdf4f5b152bc571d141

View File

@ -1 +1 @@
5dc82bce4a906fc8fb135be826d8b98ece1f68e6 e3b29c54067694c176ab5a6ca5072b8258392587

View File

@ -1 +1 @@
105fd43c2eec436dcc253a39312c91086c6842f0 e42d54426a1e1d3f1060ba459bf0d7df12630269

View File

@ -1 +1 @@
51372251532be100f5a10fbf3bbc3ddd77ddaa14 cfcf4af8929d3bc8e81a03420da6247493229048

View File

@ -1 +1 @@
2793ab92b134507d7d8a85615bc63a23b2750359 954a63d9fe84b3433462ac32843883482f105840

View File

@ -1 +1 @@
ed3d7b2f62629386d2f075b759c4338f9b9a0bb6 cfd49d3591a858bb8db85758014dede8ba686b02

View File

@ -1 +1 @@
a6694cc82436c21501c424b4c279164ce30d2147 4c4d81e0fb06844904ef14d21102e50067085a36

View File

@ -1 +1 @@
3371ccf43d2cb10c02ba09d1de5edacb61d6565e 5ffcec35a847d1faa4aba05efb9a9bdd2b70c1b6

View File

@ -1 +1 @@
54644b539cc9675291076c315786c5954c2f5368 5e1d3ea9834fefadd99b1af3b286bad69f927ee0

View File

@ -1 +1 @@
d91e9f2ba309685046e8c0278b5f520245ec8ba4 b06e35d757ace14193649bdf4f5b152bc571d141

View File

@ -1 +1 @@
7eda1257bb7379dc71d06dce3c1201ed81cd3f0b 5babb952b153b1e6415a6258886e26f26f65fbe4

View File

@ -1 +1 @@
#define FULL_VERSION "explicit/d8441de" #define FULL_VERSION "explicit/5281037"

View File

@ -1496,10 +1496,10 @@ distclean-generic:
maintainer-clean-generic: maintainer-clean-generic:
@echo "This command is intended for maintainers to use" @echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild." @echo "it deletes files that may require special tools to rebuild."
@CROSS_COMPILE_TRUE@clean-local:
@HOST_WIN32_TRUE@clean-local:
@CROSS_COMPILE_TRUE@test-local: @CROSS_COMPILE_TRUE@test-local:
@HOST_WIN32_TRUE@test-local: @HOST_WIN32_TRUE@test-local:
@CROSS_COMPILE_TRUE@clean-local:
@HOST_WIN32_TRUE@clean-local:
clean: clean-am clean: clean-am
clean-am: clean-checkPROGRAMS clean-generic clean-libtool clean-local \ clean-am: clean-checkPROGRAMS clean-generic clean-libtool clean-local \

View File

@ -525,8 +525,8 @@ distclean-generic:
maintainer-clean-generic: maintainer-clean-generic:
@echo "This command is intended for maintainers to use" @echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild." @echo "it deletes files that may require special tools to rebuild."
@ENABLE_MSVC_FALSE@install-exec-local:
@ENABLE_MSVC_FALSE@clean-local: @ENABLE_MSVC_FALSE@clean-local:
@ENABLE_MSVC_FALSE@install-exec-local:
clean: clean-am clean: clean-am
clean-am: clean-generic clean-libtool clean-local mostlyclean-am clean-am: clean-generic clean-libtool clean-local mostlyclean-am

Binary file not shown.

View File

@ -1 +1 @@
22836cf4aaad797479c8ce1812d597180405f3e4 3903db99821777febb3c3b60bc05f2c1f4b2f971

Binary file not shown.

View File

@ -1 +1 @@
4ca83106df207b50c5e5310bcbdde9fd72e77295 d50e4a46f861fe0c7905f64676ce12f431ed2997

Binary file not shown.

View File

@ -1 +1 @@
588b607c4e4812dcf7c9fda74bf270b251289401 2304597c43edfde4984443151e1a69a88ac01036

View File

@ -6,9 +6,9 @@
#, fuzzy #, fuzzy
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: mono 6.6.0.102\n" "Project-Id-Version: mono 6.6.0.103\n"
"Report-Msgid-Bugs-To: http://www.mono-project.com/Bugs\n" "Report-Msgid-Bugs-To: http://www.mono-project.com/Bugs\n"
"POT-Creation-Date: 2019-09-27 08:30+0000\n" "POT-Creation-Date: 2019-10-01 08:31+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"

Binary file not shown.

View File

@ -1 +1 @@
0b3067267bd1ad9cbbeaf0bbef9a27dcc27b5c40 913bf0f69f37b176ccc2c874b93a2ceac857015a