Imported Upstream version 6.6.0.103
Former-commit-id: ed8637df0061cb6f128ae1d26d26db7734e0fa0d
This commit is contained in:
parent
53ae335b9c
commit
9b1ef54dc9
@ -1 +1 @@
|
||||
6bd4558f248b14a2a82737af0c9b1d2b0b2944d3
|
||||
60a79a7b89a82334772050675ba7da0cc4f910d1
|
@ -1 +1 @@
|
||||
839127d83c8dfc3cbe1eabd09588a5b57eae1fac
|
||||
ed50e44c7b9748cf25b5006cd5407e8134531cab
|
@ -1 +1 @@
|
||||
faec721a749e501975809f748630ed297fd55e50
|
||||
9072ff67e7c4c540bc2e40267fc5f946b65bf9a1
|
107
external/api-snapshot/profiles/monodroid/System.Data.DataSetExtensions.cs
vendored
Normal file
107
external/api-snapshot/profiles/monodroid/System.Data.DataSetExtensions.cs
vendored
Normal 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; }
|
||||
}
|
||||
}
|
@ -1 +1 @@
|
||||
fd51a18a3a062b480d134e7d3ad089cb7c6db94b
|
||||
4eab3daf447a9db125e2b7d24282b35b14aa7f64
|
@ -1 +1 @@
|
||||
faec721a749e501975809f748630ed297fd55e50
|
||||
9072ff67e7c4c540bc2e40267fc5f946b65bf9a1
|
107
external/api-snapshot/profiles/monotouch/System.Data.DataSetExtensions.cs
vendored
Normal file
107
external/api-snapshot/profiles/monotouch/System.Data.DataSetExtensions.cs
vendored
Normal 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; }
|
||||
}
|
||||
}
|
@ -1 +1 @@
|
||||
4048a50560e4e0704415a46f55f1b706095331b4
|
||||
90d02a101ed04da6a18a169ddf1ec2799c16fcdf
|
@ -1 +1 @@
|
||||
faec721a749e501975809f748630ed297fd55e50
|
||||
9072ff67e7c4c540bc2e40267fc5f946b65bf9a1
|
@ -48,6 +48,8 @@ namespace System.Data
|
||||
}
|
||||
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 { }
|
||||
|
@ -1 +1 @@
|
||||
3d6057ed36a94c8b67e4b28f2a871ff0127ea381
|
||||
03f0d6f3e5645ad55d73b26135212076a5119877
|
@ -132,6 +132,20 @@ namespace System
|
||||
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)]
|
||||
public static decimal Ceiling(decimal d)
|
||||
{
|
||||
|
@ -218,5 +218,27 @@ namespace System.Data
|
||||
Debug.Assert(null != table, "null DataTable");
|
||||
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 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -280,8 +280,6 @@ namespace System.IO
|
||||
finally
|
||||
{
|
||||
StaticWatcherRunLoopManager.UnscheduleFromRunLoop(_eventStream);
|
||||
_eventStream.Close();
|
||||
_eventStream = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace System.Linq
|
||||
{
|
||||
@ -213,63 +212,6 @@ namespace System.Linq
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
if (s_seqMethods == null)
|
||||
|
@ -3,11 +3,10 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
#if !FEATURE_PORTABLE_SPAN
|
||||
using Internal.Runtime.CompilerServices;
|
||||
#endif // FEATURE_PORTABLE_SPAN
|
||||
|
||||
namespace System.Buffers
|
||||
{
|
||||
@ -18,17 +17,16 @@ namespace System.Buffers
|
||||
[DebuggerDisplay("{ToString(),raw}")]
|
||||
public readonly partial struct ReadOnlySequence<T>
|
||||
{
|
||||
private readonly SequencePosition _sequenceStart;
|
||||
private readonly SequencePosition _sequenceEnd;
|
||||
// The data is essentially two SequencePositions, however the Start and End SequencePositions are deconstructed to improve packing.
|
||||
private readonly object _startObject;
|
||||
private readonly object _endObject;
|
||||
private readonly int _startInteger;
|
||||
private readonly int _endInteger;
|
||||
|
||||
/// <summary>
|
||||
/// Returns empty <see cref="ReadOnlySequence{T}"/>
|
||||
/// </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>());
|
||||
#endif // FEATURE_PORTABLE_SPAN
|
||||
|
||||
/// <summary>
|
||||
/// Length of the <see cref="ReadOnlySequence{T}"/>.
|
||||
@ -46,7 +44,7 @@ namespace System.Buffers
|
||||
public bool IsSingleSegment
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => _sequenceStart.GetObject() == _sequenceEnd.GetObject();
|
||||
get => _startObject == _endObject;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -54,15 +52,28 @@ namespace System.Buffers
|
||||
/// </summary>
|
||||
public ReadOnlyMemory<T> First => GetFirstBuffer();
|
||||
|
||||
/// <summary>
|
||||
/// Gets <see cref="ReadOnlySpan{T}"/> from the first segment.
|
||||
/// </summary>
|
||||
public ReadOnlySpan<T> FirstSpan => GetFirstSpan();
|
||||
|
||||
/// <summary>
|
||||
/// A position to the start of the <see cref="ReadOnlySequence{T}"/>.
|
||||
/// </summary>
|
||||
public SequencePosition Start => _sequenceStart;
|
||||
public SequencePosition Start
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => new SequencePosition(_startObject, _startInteger);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A position to the end of the <see cref="ReadOnlySequence{T}"/>
|
||||
/// </summary>
|
||||
public SequencePosition End => _sequenceEnd;
|
||||
public SequencePosition End
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => new SequencePosition(_endObject, _endInteger);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private ReadOnlySequence(object startSegment, int startIndexAndFlags, object endSegment, int endIndexAndFlags)
|
||||
@ -73,8 +84,10 @@ namespace System.Buffers
|
||||
Debug.Assert((startSegment != null && endSegment != null) ||
|
||||
(startSegment == null && endSegment == null && startIndexAndFlags == 0 && endIndexAndFlags == 0));
|
||||
|
||||
_sequenceStart = new SequencePosition(startSegment, startIndexAndFlags);
|
||||
_sequenceEnd = new SequencePosition(endSegment, endIndexAndFlags);
|
||||
_startObject = startSegment;
|
||||
_endObject = endSegment;
|
||||
_startInteger = startIndexAndFlags;
|
||||
_endInteger = endIndexAndFlags;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -91,24 +104,28 @@ namespace System.Buffers
|
||||
(startSegment == endSegment && endIndex < startIndex))
|
||||
ThrowHelper.ThrowArgumentValidationException(startSegment, startIndex, endSegment);
|
||||
|
||||
_sequenceStart = new SequencePosition(startSegment, ReadOnlySequence.SegmentToSequenceStart(startIndex));
|
||||
_sequenceEnd = new SequencePosition(endSegment, ReadOnlySequence.SegmentToSequenceEnd(endIndex));
|
||||
_startObject = startSegment;
|
||||
_endObject = endSegment;
|
||||
_startInteger = ReadOnlySequence.SegmentToSequenceStart(startIndex);
|
||||
_endInteger = ReadOnlySequence.SegmentToSequenceEnd(endIndex);
|
||||
}
|
||||
|
||||
/// <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>
|
||||
public ReadOnlySequence(T[] array)
|
||||
{
|
||||
if (array == null)
|
||||
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
|
||||
|
||||
_sequenceStart = new SequencePosition(array, ReadOnlySequence.ArrayToSequenceStart(0));
|
||||
_sequenceEnd = new SequencePosition(array, ReadOnlySequence.ArrayToSequenceEnd(array.Length));
|
||||
_startObject = array;
|
||||
_endObject = array;
|
||||
_startInteger = ReadOnlySequence.ArrayToSequenceStart(0);
|
||||
_endInteger = ReadOnlySequence.ArrayToSequenceEnd(array.Length);
|
||||
}
|
||||
|
||||
/// <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>
|
||||
public ReadOnlySequence(T[] array, int start, int length)
|
||||
{
|
||||
@ -117,8 +134,10 @@ namespace System.Buffers
|
||||
(uint)length > (uint)(array.Length - start))
|
||||
ThrowHelper.ThrowArgumentValidationException(array, start);
|
||||
|
||||
_sequenceStart = new SequencePosition(array, ReadOnlySequence.ArrayToSequenceStart(start));
|
||||
_sequenceEnd = new SequencePosition(array, ReadOnlySequence.ArrayToSequenceEnd(start + length));
|
||||
_startObject = array;
|
||||
_endObject = array;
|
||||
_startInteger = ReadOnlySequence.ArrayToSequenceStart(start);
|
||||
_endInteger = ReadOnlySequence.ArrayToSequenceEnd(start + length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -127,40 +146,51 @@ namespace System.Buffers
|
||||
/// </summary>
|
||||
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))
|
||||
#pragma warning restore CS8631
|
||||
{
|
||||
_sequenceStart = new SequencePosition(manager, ReadOnlySequence.MemoryManagerToSequenceStart(index));
|
||||
_sequenceEnd = new SequencePosition(manager, ReadOnlySequence.MemoryManagerToSequenceEnd(length));
|
||||
_startObject = manager;
|
||||
_endObject = manager;
|
||||
_startInteger = ReadOnlySequence.MemoryManagerToSequenceStart(index);
|
||||
_endInteger = ReadOnlySequence.MemoryManagerToSequenceEnd(length);
|
||||
}
|
||||
else if (MemoryMarshal.TryGetArray(memory, out ArraySegment<T> segment))
|
||||
{
|
||||
T[] array = segment.Array;
|
||||
int start = segment.Offset;
|
||||
_sequenceStart = new SequencePosition(array, ReadOnlySequence.ArrayToSequenceStart(start));
|
||||
_sequenceEnd = new SequencePosition(array, ReadOnlySequence.ArrayToSequenceEnd(start + segment.Count));
|
||||
_startObject = array;
|
||||
_endObject = array;
|
||||
_startInteger = ReadOnlySequence.ArrayToSequenceStart(start);
|
||||
_endInteger = ReadOnlySequence.ArrayToSequenceEnd(start + segment.Count);
|
||||
}
|
||||
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();
|
||||
|
||||
_sequenceStart = new SequencePosition(text, ReadOnlySequence.StringToSequenceStart(start));
|
||||
_sequenceEnd = new SequencePosition(text, ReadOnlySequence.StringToSequenceEnd(start + length));
|
||||
_startObject = text;
|
||||
_endObject = text;
|
||||
_startInteger = ReadOnlySequence.StringToSequenceStart(start);
|
||||
_endInteger = ReadOnlySequence.StringToSequenceEnd(start + length);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Should never be reached
|
||||
ThrowHelper.ThrowInvalidOperationException();
|
||||
_sequenceStart = default;
|
||||
_sequenceEnd = default;
|
||||
_startObject = null;
|
||||
_endObject = null;
|
||||
_startInteger = 0;
|
||||
_endInteger = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// <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)
|
||||
{
|
||||
if (start < 0 || length < 0)
|
||||
@ -169,11 +199,11 @@ namespace System.Buffers
|
||||
SequencePosition begin;
|
||||
SequencePosition end;
|
||||
|
||||
int startIndex = GetIndex(_sequenceStart);
|
||||
int endIndex = GetIndex(_sequenceEnd);
|
||||
int startIndex = GetIndex(_startInteger);
|
||||
int endIndex = GetIndex(_endInteger);
|
||||
|
||||
object startObject = _sequenceStart.GetObject();
|
||||
object endObject = _sequenceEnd.GetObject();
|
||||
object startObject = _startObject;
|
||||
object endObject = _endObject;
|
||||
|
||||
if (startObject != endObject)
|
||||
{
|
||||
@ -232,23 +262,30 @@ namespace System.Buffers
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// <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)
|
||||
{
|
||||
if (start < 0)
|
||||
ThrowHelper.ThrowStartOrEndArgumentValidationException(start);
|
||||
|
||||
uint startIndex = (uint)GetIndex(_startInteger);
|
||||
object startObject = _startObject;
|
||||
|
||||
uint endIndex = (uint)GetIndex(_endInteger);
|
||||
object endObject = _endObject;
|
||||
|
||||
uint sliceEndIndex = (uint)GetIndex(end);
|
||||
object sliceEndObject = end.GetObject();
|
||||
|
||||
uint startIndex = (uint)GetIndex(_sequenceStart);
|
||||
object startObject = _sequenceStart.GetObject();
|
||||
|
||||
uint endIndex = (uint)GetIndex(_sequenceEnd);
|
||||
object endObject = _sequenceEnd.GetObject();
|
||||
if (sliceEndObject == null)
|
||||
{
|
||||
sliceEndObject = _startObject;
|
||||
sliceEndIndex = startIndex;
|
||||
}
|
||||
|
||||
// Single-Segment Sequence
|
||||
if (startObject == endObject)
|
||||
@ -300,25 +337,32 @@ namespace System.Buffers
|
||||
FoundInFirstSegment:
|
||||
// startIndex + start <= int.MaxValue
|
||||
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>
|
||||
/// 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>
|
||||
/// <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)
|
||||
{
|
||||
uint startIndex = (uint)GetIndex(_startInteger);
|
||||
object startObject = _startObject;
|
||||
|
||||
uint endIndex = (uint)GetIndex(_endInteger);
|
||||
object endObject = _endObject;
|
||||
|
||||
// Check start before length
|
||||
uint sliceStartIndex = (uint)GetIndex(start);
|
||||
object sliceStartObject = start.GetObject();
|
||||
|
||||
uint startIndex = (uint)GetIndex(_sequenceStart);
|
||||
object startObject = _sequenceStart.GetObject();
|
||||
|
||||
uint endIndex = (uint)GetIndex(_sequenceEnd);
|
||||
object endObject = _sequenceEnd.GetObject();
|
||||
if (sliceStartObject == null)
|
||||
{
|
||||
sliceStartIndex = startIndex;
|
||||
sliceStartObject = _startObject;
|
||||
}
|
||||
|
||||
// Single-Segment Sequence
|
||||
if (startObject == endObject)
|
||||
@ -376,35 +420,39 @@ namespace System.Buffers
|
||||
FoundInFirstSegment:
|
||||
// sliceStartIndex + length <= int.MaxValue
|
||||
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>
|
||||
/// 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>
|
||||
/// <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);
|
||||
|
||||
/// <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>
|
||||
/// <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);
|
||||
|
||||
/// <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>
|
||||
/// <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);
|
||||
|
||||
/// <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>
|
||||
/// <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)]
|
||||
public ReadOnlySequence<T> Slice(SequencePosition start, SequencePosition end)
|
||||
{
|
||||
@ -413,20 +461,23 @@ namespace System.Buffers
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// <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)]
|
||||
public ReadOnlySequence<T> Slice(SequencePosition start)
|
||||
{
|
||||
BoundsCheck(start);
|
||||
return SliceImpl(start, _sequenceEnd);
|
||||
bool positionIsNotNull = start.GetObject() != null;
|
||||
BoundsCheck(start, positionIsNotNull);
|
||||
return SliceImpl(positionIsNotNull ? start : Start);
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// <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)
|
||||
{
|
||||
if (start < 0)
|
||||
@ -435,8 +486,8 @@ namespace System.Buffers
|
||||
if (start == 0)
|
||||
return this;
|
||||
|
||||
SequencePosition begin = Seek(_sequenceStart, _sequenceEnd, start, ExceptionArgument.start);
|
||||
return SliceImpl(begin, _sequenceEnd);
|
||||
SequencePosition begin = Seek(start, ExceptionArgument.start);
|
||||
return SliceImpl(begin);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -454,19 +505,7 @@ namespace System.Buffers
|
||||
|
||||
if (Length < int.MaxValue)
|
||||
{
|
||||
#if !FEATURE_PORTABLE_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
|
||||
return string.Create((int)Length, charSequence, (span, sequence) => sequence.CopyTo(span));
|
||||
}
|
||||
}
|
||||
|
||||
@ -481,7 +520,13 @@ namespace System.Buffers
|
||||
/// <summary>
|
||||
/// Returns a new <see cref="SequencePosition"/> at an <paramref name="offset"/> from the start of the sequence.
|
||||
/// </summary>
|
||||
public SequencePosition GetPosition(long offset) => GetPosition(offset, _sequenceStart);
|
||||
public SequencePosition GetPosition(long offset)
|
||||
{
|
||||
if (offset < 0)
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException_OffsetOutOfRange();
|
||||
|
||||
return Seek(offset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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)
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException_OffsetOutOfRange();
|
||||
|
||||
return Seek(origin, _sequenceEnd, offset, ExceptionArgument.offset);
|
||||
return Seek(origin, offset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -4,10 +4,8 @@
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
#if !netstandard
|
||||
using System.Runtime.InteropServices;
|
||||
using Internal.Runtime.CompilerServices;
|
||||
#endif
|
||||
|
||||
namespace System.Buffers
|
||||
{
|
||||
@ -26,9 +24,9 @@ namespace System.Buffers
|
||||
}
|
||||
|
||||
SequenceType type = GetSequenceType();
|
||||
object endObject = _sequenceEnd.GetObject();
|
||||
object endObject = _endObject;
|
||||
int startIndex = GetIndex(position);
|
||||
int endIndex = GetIndex(_sequenceEnd);
|
||||
int endIndex = GetIndex(_endInteger);
|
||||
|
||||
if (type == SequenceType.MultiSegment)
|
||||
{
|
||||
@ -83,15 +81,15 @@ namespace System.Buffers
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private ReadOnlyMemory<T> GetFirstBuffer()
|
||||
{
|
||||
object startObject = _sequenceStart.GetObject();
|
||||
object startObject = _startObject;
|
||||
|
||||
if (startObject == null)
|
||||
return default;
|
||||
|
||||
int startIndex = _sequenceStart.GetInteger();
|
||||
int endIndex = _sequenceEnd.GetInteger();
|
||||
int startIndex = _startInteger;
|
||||
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 code below is structured this way for performance reasons and is equivalent to the following:
|
||||
@ -104,12 +102,9 @@ namespace System.Buffers
|
||||
// Highest bit of startIndex: A = startIndex >> 31
|
||||
// Highest bit of endIndex: B = endIndex >> 31
|
||||
|
||||
if (startIndex >= 0)
|
||||
{
|
||||
// A == 0 && B == 0 means SequenceType.MultiSegment
|
||||
// A == 0 && B == 1 means SequenceType.Array
|
||||
|
||||
if (endIndex >= 0) // SequenceType.MultiSegment
|
||||
// Equivalent to startIndex >= 0 && endIndex >= 0
|
||||
if ((startIndex | endIndex) >= 0)
|
||||
{
|
||||
ReadOnlyMemory<T> memory = ((ReadOnlySequenceSegment<T>)startObject).Memory;
|
||||
if (isMultiSegment)
|
||||
@ -118,30 +113,40 @@ namespace System.Buffers
|
||||
}
|
||||
return memory.Slice(startIndex, endIndex - startIndex);
|
||||
}
|
||||
else // endIndex < 0, SequenceType.Array
|
||||
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)
|
||||
{
|
||||
Debug.Assert(endIndex < 0);
|
||||
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 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)
|
||||
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;
|
||||
return ((MemoryManager<T>)startObject).Memory.Slice(startIndex, endIndex - startIndex);
|
||||
@ -150,13 +155,90 @@ namespace System.Buffers
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private SequencePosition Seek(in SequencePosition start, in SequencePosition end, long offset, ExceptionArgument argument)
|
||||
private ReadOnlySpan<T> GetFirstSpan()
|
||||
{
|
||||
int startIndex = GetIndex(start);
|
||||
int endIndex = GetIndex(end);
|
||||
object startObject = _startObject;
|
||||
|
||||
object startObject = start.GetObject();
|
||||
object endObject = end.GetObject();
|
||||
if (startObject == null)
|
||||
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)
|
||||
{
|
||||
@ -173,13 +255,49 @@ namespace System.Buffers
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange();
|
||||
|
||||
// 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);
|
||||
|
||||
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
|
||||
IsSingleSegment:
|
||||
@ -189,7 +307,7 @@ namespace System.Buffers
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
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);
|
||||
|
||||
while (currentSegment != null && currentSegment != endObject)
|
||||
@ -213,14 +331,15 @@ namespace System.Buffers
|
||||
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 startIndex = (uint)GetIndex(_sequenceStart);
|
||||
uint endIndex = (uint)GetIndex(_sequenceEnd);
|
||||
|
||||
object startObject = _sequenceStart.GetObject();
|
||||
object endObject = _sequenceEnd.GetObject();
|
||||
object startObject = _startObject;
|
||||
object endObject = _endObject;
|
||||
|
||||
uint startIndex = (uint)GetIndex(_startInteger);
|
||||
uint endIndex = (uint)GetIndex(_endInteger);
|
||||
|
||||
// Single-Segment Sequence
|
||||
if (startObject == endObject)
|
||||
@ -235,8 +354,15 @@ namespace System.Buffers
|
||||
// Multi-Segment Sequence
|
||||
// Storing this in a local since it is used twice within InRange()
|
||||
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(
|
||||
(ulong)(((ReadOnlySequenceSegment<T>)position.GetObject()).RunningIndex + sliceStartIndex),
|
||||
(ulong)(runningIndex + sliceStartIndex),
|
||||
startRange,
|
||||
(ulong)(((ReadOnlySequenceSegment<T>)endObject).RunningIndex + endIndex)))
|
||||
{
|
||||
@ -247,11 +373,11 @@ namespace System.Buffers
|
||||
|
||||
private void BoundsCheck(uint sliceStartIndex, object sliceStartObject, uint sliceEndIndex, object sliceEndObject)
|
||||
{
|
||||
uint startIndex = (uint)GetIndex(_sequenceStart);
|
||||
uint endIndex = (uint)GetIndex(_sequenceEnd);
|
||||
object startObject = _startObject;
|
||||
object endObject = _endObject;
|
||||
|
||||
object startObject = _sequenceStart.GetObject();
|
||||
object endObject = _sequenceEnd.GetObject();
|
||||
uint startIndex = (uint)GetIndex(_startInteger);
|
||||
uint endIndex = (uint)GetIndex(_endInteger);
|
||||
|
||||
// Single-Segment Sequence
|
||||
if (startObject == endObject)
|
||||
@ -271,8 +397,18 @@ namespace System.Buffers
|
||||
// This optimization works because we know sliceStartIndex, sliceEndIndex, startIndex, and endIndex are all >= 0
|
||||
Debug.Assert(sliceStartIndex >= 0 && startIndex >= 0 && endIndex >= 0);
|
||||
|
||||
ulong sliceStartRange = (ulong)(((ReadOnlySequenceSegment<T>)sliceStartObject).RunningIndex + sliceStartIndex);
|
||||
ulong sliceEndRange = (ulong)(((ReadOnlySequenceSegment<T>)sliceEndObject).RunningIndex + sliceEndIndex);
|
||||
ulong sliceStartRange = sliceStartIndex;
|
||||
ulong sliceEndRange = sliceEndIndex;
|
||||
|
||||
if (sliceStartObject != null)
|
||||
{
|
||||
sliceStartRange += (ulong)((ReadOnlySequenceSegment<T>)sliceStartObject).RunningIndex;
|
||||
}
|
||||
|
||||
if (sliceEndObject != null)
|
||||
{
|
||||
sliceEndRange += (ulong)((ReadOnlySequenceSegment<T>)sliceEndObject).RunningIndex;
|
||||
}
|
||||
|
||||
if (sliceStartRange > sliceEndRange)
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange();
|
||||
@ -322,12 +458,15 @@ namespace System.Buffers
|
||||
// start >> 31 = 0, end >> 31 = -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)]
|
||||
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)]
|
||||
private ReadOnlySequence<T> SliceImpl(in SequencePosition start, in SequencePosition end)
|
||||
{
|
||||
@ -337,19 +476,34 @@ namespace System.Buffers
|
||||
|
||||
return new ReadOnlySequence<T>(
|
||||
start.GetObject(),
|
||||
GetIndex(start) | (_sequenceStart.GetInteger() & ReadOnlySequence.FlagBitMask),
|
||||
GetIndex(start) | (_startInteger & ReadOnlySequence.FlagBitMask),
|
||||
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)]
|
||||
private long GetLength()
|
||||
{
|
||||
int startIndex = GetIndex(_sequenceStart);
|
||||
int endIndex = GetIndex(_sequenceEnd);
|
||||
object startObject = _sequenceStart.GetObject();
|
||||
object endObject = _sequenceEnd.GetObject();
|
||||
object startObject = _startObject;
|
||||
object endObject = _endObject;
|
||||
int startIndex = GetIndex(_startInteger);
|
||||
int endIndex = GetIndex(_endInteger);
|
||||
|
||||
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)
|
||||
{
|
||||
object startObject = _sequenceStart.GetObject();
|
||||
object startObject = _startObject;
|
||||
|
||||
// Default or not MultiSegment
|
||||
if (startObject == null || GetSequenceType() != SequenceType.MultiSegment)
|
||||
@ -377,12 +531,12 @@ namespace System.Buffers
|
||||
return false;
|
||||
}
|
||||
|
||||
Debug.Assert(_sequenceEnd.GetObject() != null);
|
||||
Debug.Assert(_endObject != null);
|
||||
|
||||
startSegment = (ReadOnlySequenceSegment<T>)startObject;
|
||||
startIndex = GetIndex(_sequenceStart);
|
||||
endSegment = (ReadOnlySequenceSegment<T>)_sequenceEnd.GetObject();
|
||||
endIndex = GetIndex(_sequenceEnd);
|
||||
startIndex = GetIndex(_startInteger);
|
||||
endSegment = (ReadOnlySequenceSegment<T>)_endObject;
|
||||
endIndex = GetIndex(_endInteger);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -394,10 +548,10 @@ namespace System.Buffers
|
||||
return false;
|
||||
}
|
||||
|
||||
Debug.Assert(_sequenceStart.GetObject() != null);
|
||||
Debug.Assert(_startObject != null);
|
||||
|
||||
int startIndex = GetIndex(_sequenceStart);
|
||||
segment = new ArraySegment<T>((T[])_sequenceStart.GetObject(), startIndex, GetIndex(_sequenceEnd) - startIndex);
|
||||
int startIndex = GetIndex(_startInteger);
|
||||
segment = new ArraySegment<T>((T[])_startObject, startIndex, GetIndex(_endInteger) - startIndex);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -411,11 +565,11 @@ namespace System.Buffers
|
||||
return false;
|
||||
}
|
||||
|
||||
Debug.Assert(_sequenceStart.GetObject() != null);
|
||||
Debug.Assert(_startObject != null);
|
||||
|
||||
start = GetIndex(_sequenceStart);
|
||||
length = GetIndex(_sequenceEnd) - start;
|
||||
text = (string)_sequenceStart.GetObject();
|
||||
start = GetIndex(_startInteger);
|
||||
length = GetIndex(_endInteger) - start;
|
||||
text = (string)_startObject;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -441,7 +595,7 @@ namespace System.Buffers
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
@ -470,5 +624,79 @@ namespace System.Buffers
|
||||
// Equivalent to: return (start <= value && value <= 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -67,12 +67,34 @@ namespace System.Buffers
|
||||
public static implicit operator StandardFormat(char symbol) => new StandardFormat(symbol);
|
||||
|
||||
/// <summary>
|
||||
/// Converts a classic .NET format string into a StandardFormat
|
||||
/// Converts a <see cref="ReadOnlySpan{Char}"/> into a StandardFormat
|
||||
/// </summary>
|
||||
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)
|
||||
return default;
|
||||
return true;
|
||||
|
||||
char symbol = format[0];
|
||||
byte precision;
|
||||
@ -87,24 +109,23 @@ namespace System.Buffers
|
||||
{
|
||||
uint digit = format[srcIndex] - 48u; // '0'
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
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>
|
||||
/// Returns true if both the Symbol and Precision are equal.
|
||||
/// </summary>
|
||||
@ -125,40 +146,54 @@ namespace System.Buffers
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
const int MaxLength = 4;
|
||||
char* pBuffer = stackalloc char[MaxLength];
|
||||
Span<char> buffer = stackalloc char[FormatStringLength];
|
||||
int charsWritten = Format(buffer);
|
||||
return new string(buffer.Slice(0, charsWritten));
|
||||
}
|
||||
|
||||
int dstIndex = 0;
|
||||
/// <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)
|
||||
{
|
||||
pBuffer[dstIndex++] = symbol;
|
||||
|
||||
byte precision = Precision;
|
||||
if (symbol != default &&
|
||||
(uint)destination.Length == FormatStringLength) // to eliminate bounds checks
|
||||
{
|
||||
destination[0] = symbol;
|
||||
count = 1;
|
||||
|
||||
uint precision = Precision;
|
||||
if (precision != NoPrecision)
|
||||
{
|
||||
if (precision >= 100)
|
||||
{
|
||||
pBuffer[dstIndex++] = (char)('0' + (precision / 100) % 10);
|
||||
precision = (byte)(precision % 100);
|
||||
}
|
||||
// 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.
|
||||
|
||||
if (precision >= 10)
|
||||
{
|
||||
pBuffer[dstIndex++] = (char)('0' + (precision / 10) % 10);
|
||||
precision = (byte)(precision % 10);
|
||||
uint div = Math.DivRem(precision, 10, out precision);
|
||||
destination[1] = (char)('0' + div % 10);
|
||||
count = 2;
|
||||
}
|
||||
|
||||
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>
|
||||
|
@ -57,5 +57,29 @@ namespace System.Runtime.InteropServices
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ static partial class Consts
|
||||
// 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 MonoProduct = "Mono Common Language Infrastructure";
|
||||
public const string MonoCopyright = "(c) Various Mono authors";
|
||||
|
@ -38,7 +38,7 @@ doc-update-recursive:
|
||||
@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.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 \
|
||||
Facades/System.Drawing.Primitives Facades/System.Drawing.Common System.Drawing System.Web.Services:
|
||||
|
||||
|
@ -22,13 +22,13 @@ ifeq ($(PROFILE),build)
|
||||
LIB_MCS_FLAGS += -d:SYSTEM_WEB_IMPLEMENTATION
|
||||
else ifeq ($(PROFILE),wasm)
|
||||
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)
|
||||
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))
|
||||
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
|
||||
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
|
||||
|
||||
ifneq (,$(filter build net_4_x, $(PROFILE)))
|
||||
|
@ -1 +1 @@
|
||||
319613988894e958c40cdcd218190a7ad2d6b27d
|
||||
fb4d2c7be36bfbed1a1cb06fa9f7d9e3243ddfed
|
@ -77,6 +77,7 @@ mobile_common_dirs_parallel := \
|
||||
System.Numerics \
|
||||
System.Numerics.Vectors \
|
||||
System.Data \
|
||||
System.Data.DataSetExtensions \
|
||||
Mono.Data.Sqlite \
|
||||
System.Data.Services.Client \
|
||||
System.IO.Compression \
|
||||
@ -179,6 +180,7 @@ wasm_dirs_parallel := \
|
||||
System.ServiceModel.Internals \
|
||||
System.Runtime.Serialization \
|
||||
System.Data \
|
||||
System.Data.DataSetExtensions \
|
||||
System.Xml.Linq \
|
||||
System.Numerics \
|
||||
System.Numerics.Vectors \
|
||||
@ -213,6 +215,7 @@ xammac_4_5_dirs_parallel := \
|
||||
System.Transactions \
|
||||
System.EnterpriseServices \
|
||||
System.Data \
|
||||
System.Data.DataSetExtensions \
|
||||
System.Runtime.Serialization \
|
||||
System.Xml.Linq \
|
||||
Mono.Data.Sqlite \
|
||||
|
185
mcs/class/corlib/corefx/ArrayBufferWriter.cs
Normal file
185
mcs/class/corlib/corefx/ArrayBufferWriter.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
128
mcs/class/corlib/corefx/NullableAttributes.cs
Normal file
128
mcs/class/corlib/corefx/NullableAttributes.cs
Normal 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; }
|
||||
}
|
||||
}
|
@ -26,4 +26,5 @@ partial class SR
|
||||
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 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}.";
|
||||
}
|
778
mcs/class/corlib/corefx/SequenceReader.Search.cs
Normal file
778
mcs/class/corlib/corefx/SequenceReader.Search.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
449
mcs/class/corlib/corefx/SequenceReader.cs
Normal file
449
mcs/class/corlib/corefx/SequenceReader.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
187
mcs/class/corlib/corefx/SequenceReaderExtensions.Binary.cs
Normal file
187
mcs/class/corlib/corefx/SequenceReaderExtensions.Binary.cs
Normal 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
|
||||
}
|
@ -1 +1 @@
|
||||
1bfb37576d4b00841ddf9fd40c66d4e0ecdda8b2
|
||||
d3b87d5ca787d43652ead46e2ed22cd62e293e8f
|
@ -1 +1 @@
|
||||
105fd43c2eec436dcc253a39312c91086c6842f0
|
||||
e42d54426a1e1d3f1060ba459bf0d7df12630269
|
@ -1 +1 @@
|
||||
51372251532be100f5a10fbf3bbc3ddd77ddaa14
|
||||
cfcf4af8929d3bc8e81a03420da6247493229048
|
@ -1 +1 @@
|
||||
2793ab92b134507d7d8a85615bc63a23b2750359
|
||||
954a63d9fe84b3433462ac32843883482f105840
|
@ -1 +1 @@
|
||||
cab1d0a4f39f9199d221a3825546f9e0bb4cb2de
|
||||
cf1cd597492462c59672f2550d25cb1bf1ae63e5
|
@ -1 +1 @@
|
||||
a6694cc82436c21501c424b4c279164ce30d2147
|
||||
4c4d81e0fb06844904ef14d21102e50067085a36
|
@ -1 +1 @@
|
||||
3371ccf43d2cb10c02ba09d1de5edacb61d6565e
|
||||
5ffcec35a847d1faa4aba05efb9a9bdd2b70c1b6
|
@ -1 +1 @@
|
||||
54644b539cc9675291076c315786c5954c2f5368
|
||||
5e1d3ea9834fefadd99b1af3b286bad69f927ee0
|
@ -1 +1 @@
|
||||
5dc82bce4a906fc8fb135be826d8b98ece1f68e6
|
||||
e3b29c54067694c176ab5a6ca5072b8258392587
|
@ -1 +1 @@
|
||||
105fd43c2eec436dcc253a39312c91086c6842f0
|
||||
e42d54426a1e1d3f1060ba459bf0d7df12630269
|
@ -1 +1 @@
|
||||
51372251532be100f5a10fbf3bbc3ddd77ddaa14
|
||||
cfcf4af8929d3bc8e81a03420da6247493229048
|
@ -1 +1 @@
|
||||
2793ab92b134507d7d8a85615bc63a23b2750359
|
||||
954a63d9fe84b3433462ac32843883482f105840
|
@ -1 +1 @@
|
||||
cab1d0a4f39f9199d221a3825546f9e0bb4cb2de
|
||||
cf1cd597492462c59672f2550d25cb1bf1ae63e5
|
@ -1 +1 @@
|
||||
a6694cc82436c21501c424b4c279164ce30d2147
|
||||
4c4d81e0fb06844904ef14d21102e50067085a36
|
@ -1 +1 @@
|
||||
3371ccf43d2cb10c02ba09d1de5edacb61d6565e
|
||||
5ffcec35a847d1faa4aba05efb9a9bdd2b70c1b6
|
@ -1 +1 @@
|
||||
54644b539cc9675291076c315786c5954c2f5368
|
||||
5e1d3ea9834fefadd99b1af3b286bad69f927ee0
|
@ -1 +1 @@
|
||||
d91e9f2ba309685046e8c0278b5f520245ec8ba4
|
||||
b06e35d757ace14193649bdf4f5b152bc571d141
|
@ -1 +1 @@
|
||||
5dc82bce4a906fc8fb135be826d8b98ece1f68e6
|
||||
e3b29c54067694c176ab5a6ca5072b8258392587
|
@ -1 +1 @@
|
||||
105fd43c2eec436dcc253a39312c91086c6842f0
|
||||
e42d54426a1e1d3f1060ba459bf0d7df12630269
|
@ -1 +1 @@
|
||||
51372251532be100f5a10fbf3bbc3ddd77ddaa14
|
||||
cfcf4af8929d3bc8e81a03420da6247493229048
|
@ -1 +1 @@
|
||||
2793ab92b134507d7d8a85615bc63a23b2750359
|
||||
954a63d9fe84b3433462ac32843883482f105840
|
@ -1 +1 @@
|
||||
cab1d0a4f39f9199d221a3825546f9e0bb4cb2de
|
||||
cf1cd597492462c59672f2550d25cb1bf1ae63e5
|
@ -1 +1 @@
|
||||
a6694cc82436c21501c424b4c279164ce30d2147
|
||||
4c4d81e0fb06844904ef14d21102e50067085a36
|
@ -1 +1 @@
|
||||
3371ccf43d2cb10c02ba09d1de5edacb61d6565e
|
||||
5ffcec35a847d1faa4aba05efb9a9bdd2b70c1b6
|
@ -1 +1 @@
|
||||
54644b539cc9675291076c315786c5954c2f5368
|
||||
5e1d3ea9834fefadd99b1af3b286bad69f927ee0
|
@ -1 +1 @@
|
||||
d91e9f2ba309685046e8c0278b5f520245ec8ba4
|
||||
b06e35d757ace14193649bdf4f5b152bc571d141
|
@ -1 +1 @@
|
||||
5dc82bce4a906fc8fb135be826d8b98ece1f68e6
|
||||
e3b29c54067694c176ab5a6ca5072b8258392587
|
@ -1 +1 @@
|
||||
105fd43c2eec436dcc253a39312c91086c6842f0
|
||||
e42d54426a1e1d3f1060ba459bf0d7df12630269
|
@ -1 +1 @@
|
||||
51372251532be100f5a10fbf3bbc3ddd77ddaa14
|
||||
cfcf4af8929d3bc8e81a03420da6247493229048
|
@ -1 +1 @@
|
||||
2793ab92b134507d7d8a85615bc63a23b2750359
|
||||
954a63d9fe84b3433462ac32843883482f105840
|
@ -1 +1 @@
|
||||
ed3d7b2f62629386d2f075b759c4338f9b9a0bb6
|
||||
cfd49d3591a858bb8db85758014dede8ba686b02
|
@ -1 +1 @@
|
||||
a6694cc82436c21501c424b4c279164ce30d2147
|
||||
4c4d81e0fb06844904ef14d21102e50067085a36
|
@ -1 +1 @@
|
||||
3371ccf43d2cb10c02ba09d1de5edacb61d6565e
|
||||
5ffcec35a847d1faa4aba05efb9a9bdd2b70c1b6
|
@ -1 +1 @@
|
||||
54644b539cc9675291076c315786c5954c2f5368
|
||||
5e1d3ea9834fefadd99b1af3b286bad69f927ee0
|
@ -1 +1 @@
|
||||
d91e9f2ba309685046e8c0278b5f520245ec8ba4
|
||||
b06e35d757ace14193649bdf4f5b152bc571d141
|
@ -1 +1 @@
|
||||
7eda1257bb7379dc71d06dce3c1201ed81cd3f0b
|
||||
5babb952b153b1e6415a6258886e26f26f65fbe4
|
@ -1 +1 @@
|
||||
#define FULL_VERSION "explicit/d8441de"
|
||||
#define FULL_VERSION "explicit/5281037"
|
||||
|
@ -1496,10 +1496,10 @@ distclean-generic:
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@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:
|
||||
@HOST_WIN32_TRUE@test-local:
|
||||
@CROSS_COMPILE_TRUE@clean-local:
|
||||
@HOST_WIN32_TRUE@clean-local:
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-checkPROGRAMS clean-generic clean-libtool clean-local \
|
||||
|
@ -525,8 +525,8 @@ distclean-generic:
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@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@install-exec-local:
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-generic clean-libtool clean-local mostlyclean-am
|
||||
|
BIN
po/mcs/de.gmo
BIN
po/mcs/de.gmo
Binary file not shown.
@ -1 +1 @@
|
||||
22836cf4aaad797479c8ce1812d597180405f3e4
|
||||
3903db99821777febb3c3b60bc05f2c1f4b2f971
|
BIN
po/mcs/es.gmo
BIN
po/mcs/es.gmo
Binary file not shown.
@ -1 +1 @@
|
||||
4ca83106df207b50c5e5310bcbdde9fd72e77295
|
||||
d50e4a46f861fe0c7905f64676ce12f431ed2997
|
BIN
po/mcs/ja.gmo
BIN
po/mcs/ja.gmo
Binary file not shown.
@ -1 +1 @@
|
||||
588b607c4e4812dcf7c9fda74bf270b251289401
|
||||
2304597c43edfde4984443151e1a69a88ac01036
|
@ -6,9 +6,9 @@
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
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"
|
||||
"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"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
BIN
po/mcs/pt_BR.gmo
BIN
po/mcs/pt_BR.gmo
Binary file not shown.
@ -1 +1 @@
|
||||
0b3067267bd1ad9cbbeaf0bbef9a27dcc27b5c40
|
||||
913bf0f69f37b176ccc2c874b93a2ceac857015a
|
Loading…
x
Reference in New Issue
Block a user