Imported Upstream version 5.2.0.175

Former-commit-id: bb0468d0f257ff100aa895eb5fe583fb5dfbf900
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2017-06-07 13:16:24 +00:00
parent 4bdbaf4a88
commit 966bba02bb
8776 changed files with 346420 additions and 149650 deletions

View File

@@ -9,35 +9,30 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Collections.Immutabl
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Collections.Immutable", "src\System.Collections.Immutable.csproj", "{1DD0FF15-6234-4BD6-850A-317F05479554}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{1CA59CB2-FE88-4510-92AC-3561026C3B13}"
ProjectSection(SolutionItems) = preProject
..\.nuget\packages.Windows_NT.config = ..\.nuget\packages.Windows_NT.config
EndProjectSection
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{1A2F9F4A-A032-433E-B914-ADD5992BB178}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{D7979177-679D-4E56-919B-479871FA1BDF}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{E181070D-D93C-4B03-B1EB-133CEA43503E}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E107E9C1-E893-4E87-987E-04EF0DCEAEFD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
DebugNETCoreAppnetstandard1.0netstandard1.3|AnyCPU = DebugNETCoreAppnetstandard1.0netstandard1.3|AnyCPU
ReleaseNETCoreAppnetstandard1.0netstandard1.3|AnyCPU = ReleaseNETCoreAppnetstandard1.0netstandard1.3|AnyCPU
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{95DFC527-4DC1-495E-97D7-E94EE1F7140D}.DebugNETCoreAppnetstandard1.0netstandard1.3|AnyCPU.ActiveCfg = netstandard1.3-Debug|Any CPU
{95DFC527-4DC1-495E-97D7-E94EE1F7140D}.DebugNETCoreAppnetstandard1.0netstandard1.3|AnyCPU.Build.0 = netstandard1.3-Debug|Any CPU
{95DFC527-4DC1-495E-97D7-E94EE1F7140D}.ReleaseNETCoreAppnetstandard1.0netstandard1.3|AnyCPU.ActiveCfg = netstandard1.3-Release|Any CPU
{95DFC527-4DC1-495E-97D7-E94EE1F7140D}.ReleaseNETCoreAppnetstandard1.0netstandard1.3|AnyCPU.Build.0 = netstandard1.3-Release|Any CPU
{1DD0FF15-6234-4BD6-850A-317F05479554}.DebugNETCoreAppnetstandard1.0netstandard1.3|AnyCPU.ActiveCfg = netstandard1.0-Debug|Any CPU
{1DD0FF15-6234-4BD6-850A-317F05479554}.DebugNETCoreAppnetstandard1.0netstandard1.3|AnyCPU.Build.0 = netstandard1.0-Debug|Any CPU
{1DD0FF15-6234-4BD6-850A-317F05479554}.ReleaseNETCoreAppnetstandard1.0netstandard1.3|AnyCPU.ActiveCfg = netstandard1.0-Release|Any CPU
{1DD0FF15-6234-4BD6-850A-317F05479554}.ReleaseNETCoreAppnetstandard1.0netstandard1.3|AnyCPU.Build.0 = netstandard1.0-Release|Any CPU
{95DFC527-4DC1-495E-97D7-E94EE1F7140D}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
{95DFC527-4DC1-495E-97D7-E94EE1F7140D}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
{95DFC527-4DC1-495E-97D7-E94EE1F7140D}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
{95DFC527-4DC1-495E-97D7-E94EE1F7140D}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
{1DD0FF15-6234-4BD6-850A-317F05479554}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
{1DD0FF15-6234-4BD6-850A-317F05479554}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
{1DD0FF15-6234-4BD6-850A-317F05479554}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
{1DD0FF15-6234-4BD6-850A-317F05479554}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{95DFC527-4DC1-495E-97D7-E94EE1F7140D} = {95DFC527-4DC1-495E-97D7-E94EE1F7140D}
{1DD0FF15-6234-4BD6-850A-317F05479554} = {1DD0FF15-6234-4BD6-850A-317F05479554}
{95DFC527-4DC1-495E-97D7-E94EE1F7140D} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
{1DD0FF15-6234-4BD6-850A-317F05479554} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD}
EndGlobalSection
EndGlobal

View File

@@ -5,5 +5,6 @@
<PackageVersion>1.4.0</PackageVersion>
<AssemblyVersion>1.2.2</AssemblyVersion>
<IsNETCoreApp>true</IsNETCoreApp>
<IsUAP>true</IsUAP>
</PropertyGroup>
</Project>

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<Project Include="System.Collections.Immutable.pkgproj" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.traversal.targets))\dir.traversal.targets" />
</Project>

View File

@@ -6,7 +6,7 @@
<MinClientVersion>2.8.6</MinClientVersion>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\src\System.Collections.Immutable.builds">
<ProjectReference Include="..\src\System.Collections.Immutable.csproj">
<SupportedFramework>net45;netcore45;netcoreapp1.0;wp8;wpa81;$(AllXamarinFrameworks)</SupportedFramework>
</ProjectReference>
</ItemGroup>

View File

@@ -3,7 +3,9 @@
<PropertyGroup>
<BuildConfigurations>
netstandard1.0;
netstandard;
netcoreapp;
uap-Windows_NT;
</BuildConfigurations>
</PropertyGroup>
</Project>
</Project>

View File

@@ -1,64 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">

View File

@@ -6,16 +6,19 @@
<ProjectGuid>{1DD0FF15-6234-4BD6-850A-317F05479554}</ProjectGuid>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>System.Collections.Immutable</RootNamespace>
<AssemblyName>System.Collections.Immutable</AssemblyName>
<FileAlignment>512</FileAlignment>
<DocumentationFile>$(OutputPath)System.Collections.Immutable.xml</DocumentationFile>
<DocumentationFile>$(OutputPath)$(MSBuildProjectName).xml</DocumentationFile>
<GenerateAppxPackageOnBuild>False</GenerateAppxPackageOnBuild>
<PackageTargetFramework Condition="'$(TargetGroup)' == 'netstandard1.0'">netstandard1.0;portable-net45+win8+wp8+wpa81</PackageTargetFramework>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.0-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.0-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Release|AnyCPU'" />
<ItemGroup>
<Compile Include="Properties\InternalsVisibleTo.cs" />
<Compile Include="GlobalSuppressions.cs" />
@@ -36,25 +39,26 @@
<Compile Include="System\Collections\Immutable\IImmutableStack.cs" />
<Compile Include="System\Collections\Immutable\IStrongEnumerable_2.cs" />
<Compile Include="System\Collections\Immutable\IStrongEnumerator_1.cs" />
<Compile Include="System\Collections\Immutable\SortedInt32KeyNode.cs" />
<Compile Include="System\Collections\Immutable\IOrderedCollection.cs" />
<Compile Include="System\Collections\Immutable\ImmutableArray.cs" />
<Compile Include="System\Collections\Immutable\ImmutableArray_1.Builder.cs" />
<Compile Include="System\Collections\Immutable\ImmutableArray_1.Builder.DebuggerProxy.cs" />
<Compile Include="System\Collections\Immutable\ImmutableArray_1.Enumerator.cs" />
<Compile Include="System\Collections\Immutable\ImmutableArray_1.cs" />
<Compile Include="System\Collections\Immutable\ImmutableArray_1.Minimal.cs" />
<Compile Include="System\Collections\Immutable\ImmutableDictionary.cs" />
<Compile Include="System\Collections\Immutable\ImmutableDictionary_2.Builder.cs" />
<Compile Include="System\Collections\Immutable\ImmutableDictionary_2.Comparers.cs" />
<Compile Include="System\Collections\Immutable\ImmutableDictionary_2.DebuggerProxy.cs" />
<Compile Include="System\Collections\Immutable\ImmutableDictionary_2.Enumerator.cs" />
<Compile Include="System\Collections\Immutable\ImmutableDictionary_2.HashBucket.cs" />
<Compile Include="System\Collections\Immutable\ImmutableDictionary_2.MutationInput.cs" />
<Compile Include="System\Collections\Immutable\ImmutableDictionary_2.MutationResult.cs" />
<Compile Include="System\Collections\Immutable\ImmutableDictionary_2.cs" />
<Compile Include="System\Collections\Immutable\ImmutableEnumerableDebuggerProxy.cs" />
<Compile Include="System\Collections\Immutable\ImmutableExtensions.cs" />
<Compile Include="System\Collections\Immutable\ImmutableExtensions.Minimal.cs" />
<Compile Include="System\Collections\Immutable\ImmutableHashSet.cs" />
<Compile Include="System\Collections\Immutable\ImmutableHashSet_1.Builder.cs" />
<Compile Include="System\Collections\Immutable\ImmutableHashSet_1.DebuggerProxy.cs" />
<Compile Include="System\Collections\Immutable\ImmutableHashSet_1.Enumerator.cs" />
<Compile Include="System\Collections\Immutable\ImmutableHashSet_1.HashBucket.cs" />
<Compile Include="System\Collections\Immutable\ImmutableHashSet_1.MutationInput.cs" />
@@ -67,17 +71,26 @@
<Compile Include="System\Collections\Immutable\ImmutableList_1.cs" />
<Compile Include="System\Collections\Immutable\ImmutableQueue.cs" />
<Compile Include="System\Collections\Immutable\ImmutableQueue_1.cs" />
<Compile Include="System\Collections\Immutable\ImmutableQueue_1.Enumerator.cs" />
<Compile Include="System\Collections\Immutable\ImmutableSortedDictionary.cs" />
<Compile Include="System\Collections\Immutable\ImmutableSortedDictionary_2.Builder.cs" />
<Compile Include="System\Collections\Immutable\ImmutableSortedDictionary_2.cs" />
<Compile Include="System\Collections\Immutable\ImmutableSortedDictionary_2.Enumerator.cs" />
<Compile Include="System\Collections\Immutable\ImmutableSortedDictionary_2.Node.cs" />
<Compile Include="System\Collections\Immutable\ImmutableSortedSet.cs" />
<Compile Include="System\Collections\Immutable\ImmutableSortedSet_1.Builder.cs" />
<Compile Include="System\Collections\Immutable\ImmutableSortedSet_1.Builder.DebuggerProxy.cs" />
<Compile Include="System\Collections\Immutable\ImmutableSortedSet_1.cs" />
<Compile Include="System\Collections\Immutable\ImmutableSortedSet_1.Enumerator.cs" />
<Compile Include="System\Collections\Immutable\ImmutableSortedSet_1.Node.cs" />
<Compile Include="System\Collections\Immutable\ImmutableStack.cs" />
<Compile Include="System\Collections\Immutable\ImmutableStack_1.cs" />
<Compile Include="System\Collections\Immutable\ImmutableStack_1.Enumerator.cs" />
<Compile Include="System\Collections\Immutable\KeysOrValuesCollectionAccessor.cs" />
<Compile Include="System\Collections\Immutable\RefAsValueType.cs" />
<Compile Include="System\Collections\Immutable\SecureObjectPool.cs" />
<Compile Include="System\Collections\Immutable\SortedInt32KeyNode.cs" />
<Compile Include="System\Collections\Immutable\SortedInt32KeyNode.Enumerator.cs" />
<Compile Include="System\Linq\ImmutableArrayExtensions.cs" />
<Compile Include="Validation\Requires.cs" />
<Compile Include="Validation\ValidatedNotNullAttribute.cs" />
@@ -85,6 +98,11 @@
<Link>Common\System\Runtime\Versioning\NonVersionableAttribute.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)' == 'netstandard1.0'">
<Compile Include="$(CommonPath)\System\Diagnostics\CodeAnalysis\ExcludeFromCodeCoverageAttribute.cs">
<Link>Common\System\Diagnostics\CodeAnalysis\ExcludeFromCodeCoverageAttribute.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="Interfaces.cd" />
<Reference Include="System.Collections" />

View File

@@ -137,7 +137,7 @@ namespace System.Collections.Immutable
}
/// <summary>
/// Creates an empty <see cref="ImmutableArray{T}"/>.
/// Creates an <see cref="ImmutableArray{T}"/> with the specified elements.
/// </summary>
/// <typeparam name="T">The type of element stored in the array.</typeparam>
/// <param name="items">The elements to store in the array.</param>

View File

@@ -0,0 +1,39 @@
// 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.Collections.Immutable
{
/// <summary>
/// A simple view of the immutable collection that the debugger can show to the developer.
/// </summary>
internal sealed class ImmutableArrayBuilderDebuggerProxy<T>
{
/// <summary>
/// The collection to be enumerated.
/// </summary>
private readonly ImmutableArray<T>.Builder _builder;
/// <summary>
/// Initializes a new instance of the <see cref="ImmutableArrayBuilderDebuggerProxy{T}"/> class.
/// </summary>
/// <param name="builder">The collection to display in the debugger</param>
public ImmutableArrayBuilderDebuggerProxy(ImmutableArray<T>.Builder builder)
{
_builder = builder;
}
/// <summary>
/// Gets a simple debugger-viewable collection.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public T[] A
{
get
{
return _builder.ToArray();
}
}
}
}

View File

@@ -4,7 +4,6 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
namespace System.Collections.Immutable
@@ -747,35 +746,4 @@ namespace System.Collections.Immutable
}
}
}
/// <summary>
/// A simple view of the immutable collection that the debugger can show to the developer.
/// </summary>
internal sealed class ImmutableArrayBuilderDebuggerProxy<T>
{
/// <summary>
/// The collection to be enumerated.
/// </summary>
private readonly ImmutableArray<T>.Builder _builder;
/// <summary>
/// Initializes a new instance of the <see cref="ImmutableArrayBuilderDebuggerProxy{T}"/> class.
/// </summary>
/// <param name="builder">The collection to display in the debugger</param>
public ImmutableArrayBuilderDebuggerProxy(ImmutableArray<T>.Builder builder)
{
_builder = builder;
}
/// <summary>
/// Gets a simple debugger-viewable collection.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public T[] A
{
get
{
return _builder.ToArray();
}
}
}
}

View File

@@ -109,7 +109,7 @@ namespace System.Collections.Immutable
{
// this.index >= 0 && this.index < this.array.Length
// unsigned compare performs the range check above in one compare
if ((uint)_index < (uint)_array.Length)
if (unchecked((uint)_index) < (uint)_array.Length)
{
return _array[_index];
}

View File

@@ -0,0 +1,426 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Linq;
using System.Runtime.Versioning;
namespace System.Collections.Immutable
{
/// <summary>
/// A readonly array with O(1) indexable lookup time.
/// </summary>
/// <typeparam name="T">The type of element stored by the array.</typeparam>
/// <devremarks>
/// This type has a documented contract of being exactly one reference-type field in size.
/// Our own <see cref="ImmutableInterlocked"/> class depends on it, as well as others externally.
/// IMPORTANT NOTICE FOR MAINTAINERS AND REVIEWERS:
/// This type should be thread-safe. As a struct, it cannot protect its own fields
/// from being changed from one thread while its members are executing on other threads
/// because structs can change *in place* simply by reassigning the field containing
/// this struct. Therefore it is extremely important that
/// ** Every member should only dereference <c>this</c> ONCE. **
/// If a member needs to reference the array field, that counts as a dereference of <c>this</c>.
/// Calling other instance members (properties or methods) also counts as dereferencing <c>this</c>.
/// Any member that needs to use <c>this</c> more than once must instead
/// assign <c>this</c> to a local variable and use that for the rest of the code instead.
/// This effectively copies the one field in the struct to a local variable so that
/// it is insulated from other threads.
/// </devremarks>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
[NonVersionable] // Applies to field layout
public partial struct ImmutableArray<T> : IEnumerable<T>, IEquatable<ImmutableArray<T>>, IImmutableArray
{
/// <summary>
/// An empty (initialized) instance of <see cref="ImmutableArray{T}"/>.
/// </summary>
public static readonly ImmutableArray<T> Empty = new ImmutableArray<T>(new T[0]);
/// <summary>
/// The backing field for this instance. References to this value should never be shared with outside code.
/// </summary>
/// <remarks>
/// This would be private, but we make it internal so that our own extension methods can access it.
/// </remarks>
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
internal T[] array;
/// <summary>
/// Initializes a new instance of the <see cref="ImmutableArray{T}"/> struct
/// *without making a defensive copy*.
/// </summary>
/// <param name="items">The array to use. May be null for "default" arrays.</param>
internal ImmutableArray(T[] items)
{
this.array = items;
}
#region Operators
/// <summary>
/// Checks equality between two instances.
/// </summary>
/// <param name="left">The instance to the left of the operator.</param>
/// <param name="right">The instance to the right of the operator.</param>
/// <returns><c>true</c> if the values' underlying arrays are reference equal; <c>false</c> otherwise.</returns>
[NonVersionable]
public static bool operator ==(ImmutableArray<T> left, ImmutableArray<T> right)
{
return left.Equals(right);
}
/// <summary>
/// Checks inequality between two instances.
/// </summary>
/// <param name="left">The instance to the left of the operator.</param>
/// <param name="right">The instance to the right of the operator.</param>
/// <returns><c>true</c> if the values' underlying arrays are reference not equal; <c>false</c> otherwise.</returns>
[NonVersionable]
public static bool operator !=(ImmutableArray<T> left, ImmutableArray<T> right)
{
return !left.Equals(right);
}
/// <summary>
/// Checks equality between two instances.
/// </summary>
/// <param name="left">The instance to the left of the operator.</param>
/// <param name="right">The instance to the right of the operator.</param>
/// <returns><c>true</c> if the values' underlying arrays are reference equal; <c>false</c> otherwise.</returns>
public static bool operator ==(ImmutableArray<T>? left, ImmutableArray<T>? right)
{
return left.GetValueOrDefault().Equals(right.GetValueOrDefault());
}
/// <summary>
/// Checks inequality between two instances.
/// </summary>
/// <param name="left">The instance to the left of the operator.</param>
/// <param name="right">The instance to the right of the operator.</param>
/// <returns><c>true</c> if the values' underlying arrays are reference not equal; <c>false</c> otherwise.</returns>
public static bool operator !=(ImmutableArray<T>? left, ImmutableArray<T>? right)
{
return !left.GetValueOrDefault().Equals(right.GetValueOrDefault());
}
#endregion
/// <summary>
/// Gets the element at the specified index in the read-only list.
/// </summary>
/// <param name="index">The zero-based index of the element to get.</param>
/// <returns>The element at the specified index in the read-only list.</returns>
public T this[int index]
{
[NonVersionable]
get
{
// We intentionally do not check this.array != null, and throw NullReferenceException
// if this is called while uninitialized.
// The reason for this is perf.
// Length and the indexer must be absolutely trivially implemented for the JIT optimization
// of removing array bounds checking to work.
return this.array[index];
}
}
/// <summary>
/// Gets a value indicating whether this collection is empty.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public bool IsEmpty
{
[NonVersionable]
get { return this.Length == 0; }
}
/// <summary>
/// Gets the number of elements in the array.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public int Length
{
[NonVersionable]
get
{
// We intentionally do not check this.array != null, and throw NullReferenceException
// if this is called while uninitialized.
// The reason for this is perf.
// Length and the indexer must be absolutely trivially implemented for the JIT optimization
// of removing array bounds checking to work.
return this.array.Length;
}
}
/// <summary>
/// Gets a value indicating whether this struct was initialized without an actual array instance.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public bool IsDefault
{
get { return this.array == null; }
}
/// <summary>
/// Gets a value indicating whether this struct is empty or uninitialized.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public bool IsDefaultOrEmpty
{
get
{
var self = this;
return self.array == null || self.array.Length == 0;
}
}
/// <summary>
/// Gets an untyped reference to the array.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
Array IImmutableArray.Array
{
get { return this.array; }
}
/// <summary>
/// Gets the string to display in the debugger watches window for this instance.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string DebuggerDisplay
{
get
{
var self = this;
return self.IsDefault ? "Uninitialized" : String.Format(CultureInfo.CurrentCulture, "Length = {0}", self.Length);
}
}
/// <summary>
/// Copies the contents of this array to the specified array.
/// </summary>
/// <param name="destination">The array to copy to.</param>
[Pure]
public void CopyTo(T[] destination)
{
var self = this;
self.ThrowNullRefIfNotInitialized();
Array.Copy(self.array, 0, destination, 0, self.Length);
}
/// <summary>
/// Copies the contents of this array to the specified array.
/// </summary>
/// <param name="destination">The array to copy to.</param>
/// <param name="destinationIndex">The index into the destination array to which the first copied element is written.</param>
[Pure]
public void CopyTo(T[] destination, int destinationIndex)
{
var self = this;
self.ThrowNullRefIfNotInitialized();
Array.Copy(self.array, 0, destination, destinationIndex, self.Length);
}
/// <summary>
/// Copies the contents of this array to the specified array.
/// </summary>
/// <param name="sourceIndex">The index into this collection of the first element to copy.</param>
/// <param name="destination">The array to copy to.</param>
/// <param name="destinationIndex">The index into the destination array to which the first copied element is written.</param>
/// <param name="length">The number of elements to copy.</param>
[Pure]
public void CopyTo(int sourceIndex, T[] destination, int destinationIndex, int length)
{
var self = this;
self.ThrowNullRefIfNotInitialized();
Array.Copy(self.array, sourceIndex, destination, destinationIndex, length);
}
/// <summary>
/// Returns a builder that is populated with the same contents as this array.
/// </summary>
/// <returns>The new builder.</returns>
[Pure]
public ImmutableArray<T>.Builder ToBuilder()
{
var self = this;
if (self.Length == 0)
{
return new Builder(); // allow the builder to create itself with a reasonable default capacity
}
var builder = new Builder(self.Length);
builder.AddRange(self);
return builder;
}
/// <summary>
/// Returns an enumerator for the contents of the array.
/// </summary>
/// <returns>An enumerator.</returns>
[Pure]
public Enumerator GetEnumerator()
{
var self = this;
self.ThrowNullRefIfNotInitialized();
return new Enumerator(self.array);
}
/// <summary>
/// Returns a hash code for this instance.
/// </summary>
/// <returns>
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
/// </returns>
[Pure]
public override int GetHashCode()
{
var self = this;
return self.array == null ? 0 : self.array.GetHashCode();
}
/// <summary>
/// Determines whether the specified <see cref="Object"/> is equal to this instance.
/// </summary>
/// <param name="obj">The <see cref="Object"/> to compare with this instance.</param>
/// <returns>
/// <c>true</c> if the specified <see cref="Object"/> is equal to this instance; otherwise, <c>false</c>.
/// </returns>
[Pure]
public override bool Equals(object obj)
{
IImmutableArray other = obj as IImmutableArray;
if (other != null)
{
return this.array == other.Array;
}
return false;
}
/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
/// <param name="other">An object to compare with this object.</param>
/// <returns>
/// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
/// </returns>
[Pure]
[NonVersionable]
public bool Equals(ImmutableArray<T> other)
{
return this.array == other.array;
}
/// <summary>
/// Initializes a new instance of the <see cref="ImmutableArray{T}"/> struct based on the contents
/// of an existing instance, allowing a covariant static cast to efficiently reuse the existing array.
/// </summary>
/// <param name="items">The array to initialize the array with. No copy is made.</param>
/// <remarks>
/// Covariant upcasts from this method may be reversed by calling the
/// <see cref="ImmutableArray{T}.As{TOther}"/> or <see cref="ImmutableArray{T}.CastArray{TOther}"/>method.
/// </remarks>
[Pure]
public static ImmutableArray<T> CastUp<TDerived>(ImmutableArray<TDerived> items)
where TDerived : class, T
{
return new ImmutableArray<T>(items.array);
}
/// <summary>
/// Initializes a new instance of the <see cref="ImmutableArray{T}"/> struct by casting the underlying
/// array to an array of type <typeparam name="TOther"/>.
/// </summary>
/// <exception cref="InvalidCastException">Thrown if the cast is illegal.</exception>
[Pure]
public ImmutableArray<TOther> CastArray<TOther>() where TOther : class
{
return new ImmutableArray<TOther>((TOther[])(object)array);
}
/// <summary>
/// Creates an immutable array for this array, cast to a different element type.
/// </summary>
/// <typeparam name="TOther">The type of array element to return.</typeparam>
/// <returns>
/// A struct typed for the base element type. If the cast fails, an instance
/// is returned whose <see cref="IsDefault"/> property returns <c>true</c>.
/// </returns>
/// <remarks>
/// Arrays of derived elements types can be cast to arrays of base element types
/// without reallocating the array.
/// These upcasts can be reversed via this same method, casting an array of base
/// element types to their derived types. However, downcasting is only successful
/// when it reverses a prior upcasting operation.
/// </remarks>
[Pure]
public ImmutableArray<TOther> As<TOther>() where TOther : class
{
return new ImmutableArray<TOther>(this.array as TOther[]);
}
/// <summary>
/// Returns an enumerator for the contents of the array.
/// </summary>
/// <returns>An enumerator.</returns>
/// <exception cref="InvalidOperationException">Thrown if the <see cref="IsDefault"/> property returns true.</exception>
[Pure]
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
var self = this;
self.ThrowInvalidOperationIfNotInitialized();
return EnumeratorObject.Create(self.array);
}
/// <summary>
/// Returns an enumerator for the contents of the array.
/// </summary>
/// <returns>An enumerator.</returns>
/// <exception cref="InvalidOperationException">Thrown if the <see cref="IsDefault"/> property returns true.</exception>
[Pure]
IEnumerator IEnumerable.GetEnumerator()
{
var self = this;
self.ThrowInvalidOperationIfNotInitialized();
return EnumeratorObject.Create(self.array);
}
/// <summary>
/// Throws a null reference exception if the array field is null.
/// </summary>
internal void ThrowNullRefIfNotInitialized()
{
// Force NullReferenceException if array is null by touching its Length.
// This way of checking has a nice property of requiring very little code
// and not having any conditions/branches.
// In a faulting scenario we are relying on hardware to generate the fault.
// And in the non-faulting scenario (most common) the check is virtually free since
// if we are going to do anything with the array, we will need Length anyways
// so touching it, and potentially causing a cache miss, is not going to be an
// extra expense.
var unused = this.array.Length;
}
/// <summary>
/// Throws an <see cref="InvalidOperationException"/> if the <see cref="array"/> field is null, i.e. the
/// <see cref="IsDefault"/> property returns true. The
/// <see cref="InvalidOperationException"/> message specifies that the operation cannot be performed
/// on a default instance of <see cref="ImmutableArray{T}"/>.
///
/// This is intended for explicitly implemented interface method and property implementations.
/// </summary>
private void ThrowInvalidOperationIfNotInitialized()
{
if (this.IsDefault)
{
throw new InvalidOperationException(SR.InvalidOperationOnDefaultArray);
}
}
}
}

View File

@@ -12,123 +12,8 @@ using System.Runtime.Versioning;
namespace System.Collections.Immutable
{
/// <summary>
/// A readonly array with O(1) indexable lookup time.
/// </summary>
/// <typeparam name="T">The type of element stored by the array.</typeparam>
/// <devremarks>
/// This type has a documented contract of being exactly one reference-type field in size.
/// Our own <see cref="ImmutableInterlocked"/> class depends on it, as well as others externally.
/// IMPORTANT NOTICE FOR MAINTAINERS AND REVIEWERS:
/// This type should be thread-safe. As a struct, it cannot protect its own fields
/// from being changed from one thread while its members are executing on other threads
/// because structs can change *in place* simply by reassigning the field containing
/// this struct. Therefore it is extremely important that
/// ** Every member should only dereference <c>this</c> ONCE. **
/// If a member needs to reference the array field, that counts as a dereference of <c>this</c>.
/// Calling other instance members (properties or methods) also counts as dereferencing <c>this</c>.
/// Any member that needs to use <c>this</c> more than once must instead
/// assign <c>this</c> to a local variable and use that for the rest of the code instead.
/// This effectively copies the one field in the struct to a local variable so that
/// it is insulated from other threads.
/// </devremarks>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
[NonVersionable] // Applies to field layout
public partial struct ImmutableArray<T> : IReadOnlyList<T>, IList<T>, IEquatable<ImmutableArray<T>>, IImmutableList<T>, IList, IImmutableArray, IStructuralComparable, IStructuralEquatable
public partial struct ImmutableArray<T> : IReadOnlyList<T>, IList<T>, IEquatable<ImmutableArray<T>>, IList, IImmutableArray, IStructuralComparable, IStructuralEquatable, IImmutableList<T>
{
/// <summary>
/// An empty (initialized) instance of <see cref="ImmutableArray{T}"/>.
/// </summary>
public static readonly ImmutableArray<T> Empty = new ImmutableArray<T>(new T[0]);
/// <summary>
/// The backing field for this instance. References to this value should never be shared with outside code.
/// </summary>
/// <remarks>
/// This would be private, but we make it internal so that our own extension methods can access it.
/// </remarks>
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
internal T[] array;
/// <summary>
/// Initializes a new instance of the <see cref="ImmutableArray{T}"/> struct
/// *without making a defensive copy*.
/// </summary>
/// <param name="items">The array to use. May be null for "default" arrays.</param>
internal ImmutableArray(T[] items)
{
this.array = items;
}
#region Operators
/// <summary>
/// Checks equality between two instances.
/// </summary>
/// <param name="left">The instance to the left of the operator.</param>
/// <param name="right">The instance to the right of the operator.</param>
/// <returns><c>true</c> if the values' underlying arrays are reference equal; <c>false</c> otherwise.</returns>
[NonVersionable]
public static bool operator ==(ImmutableArray<T> left, ImmutableArray<T> right)
{
return left.Equals(right);
}
/// <summary>
/// Checks inequality between two instances.
/// </summary>
/// <param name="left">The instance to the left of the operator.</param>
/// <param name="right">The instance to the right of the operator.</param>
/// <returns><c>true</c> if the values' underlying arrays are reference not equal; <c>false</c> otherwise.</returns>
[NonVersionable]
public static bool operator !=(ImmutableArray<T> left, ImmutableArray<T> right)
{
return !left.Equals(right);
}
/// <summary>
/// Checks equality between two instances.
/// </summary>
/// <param name="left">The instance to the left of the operator.</param>
/// <param name="right">The instance to the right of the operator.</param>
/// <returns><c>true</c> if the values' underlying arrays are reference equal; <c>false</c> otherwise.</returns>
public static bool operator ==(ImmutableArray<T>? left, ImmutableArray<T>? right)
{
return left.GetValueOrDefault().Equals(right.GetValueOrDefault());
}
/// <summary>
/// Checks inequality between two instances.
/// </summary>
/// <param name="left">The instance to the left of the operator.</param>
/// <param name="right">The instance to the right of the operator.</param>
/// <returns><c>true</c> if the values' underlying arrays are reference not equal; <c>false</c> otherwise.</returns>
public static bool operator !=(ImmutableArray<T>? left, ImmutableArray<T>? right)
{
return !left.GetValueOrDefault().Equals(right.GetValueOrDefault());
}
#endregion
/// <summary>
/// Gets the element at the specified index in the read-only list.
/// </summary>
/// <param name="index">The zero-based index of the element to get.</param>
/// <returns>The element at the specified index in the read-only list.</returns>
public T this[int index]
{
[NonVersionable]
get
{
// We intentionally do not check this.array != null, and throw NullReferenceException
// if this is called while uninitialized.
// The reason for this is perf.
// Length and the indexer must be absolutely trivially implemented for the JIT optimization
// of removing array bounds checking to work.
return this.array[index];
}
}
/// <summary>
/// Gets or sets the element at the specified index in the read-only list.
/// </summary>
@@ -159,34 +44,6 @@ namespace System.Collections.Immutable
get { return true; }
}
/// <summary>
/// Gets a value indicating whether this collection is empty.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public bool IsEmpty
{
[NonVersionable]
get { return this.Length == 0; }
}
/// <summary>
/// Gets the number of elements in the array.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public int Length
{
[NonVersionable]
get
{
// We intentionally do not check this.array != null, and throw NullReferenceException
// if this is called while uninitialized.
// The reason for this is perf.
// Length and the indexer must be absolutely trivially implemented for the JIT optimization
// of removing array bounds checking to work.
return this.array.Length;
}
}
/// <summary>
/// Gets the number of array in the collection.
/// </summary>
@@ -235,50 +92,6 @@ namespace System.Collections.Immutable
}
}
/// <summary>
/// Gets a value indicating whether this struct was initialized without an actual array instance.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public bool IsDefault
{
get { return this.array == null; }
}
/// <summary>
/// Gets a value indicating whether this struct is empty or uninitialized.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public bool IsDefaultOrEmpty
{
get
{
var self = this;
return self.array == null || self.array.Length == 0;
}
}
/// <summary>
/// Gets an untyped reference to the array.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
Array IImmutableArray.Array
{
get { return this.array; }
}
/// <summary>
/// Gets the string to display in the debugger watches window for this instance.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string DebuggerDisplay
{
get
{
var self = this;
return self.IsDefault ? "Uninitialized" : String.Format(CultureInfo.CurrentCulture, "Length = {0}", self.Length);
}
}
/// <summary>
/// Searches the array for the specified item.
/// </summary>
@@ -475,46 +288,6 @@ namespace System.Collections.Immutable
return this.IndexOf(item) >= 0;
}
/// <summary>
/// Copies the contents of this array to the specified array.
/// </summary>
/// <param name="destination">The array to copy to.</param>
[Pure]
public void CopyTo(T[] destination)
{
var self = this;
self.ThrowNullRefIfNotInitialized();
Array.Copy(self.array, 0, destination, 0, self.Length);
}
/// <summary>
/// Copies the contents of this array to the specified array.
/// </summary>
/// <param name="destination">The array to copy to.</param>
/// <param name="destinationIndex">The index into the destination array to which the first copied element is written.</param>
[Pure]
public void CopyTo(T[] destination, int destinationIndex)
{
var self = this;
self.ThrowNullRefIfNotInitialized();
Array.Copy(self.array, 0, destination, destinationIndex, self.Length);
}
/// <summary>
/// Copies the contents of this array to the specified array.
/// </summary>
/// <param name="sourceIndex">The index into this collection of the first element to copy.</param>
/// <param name="destination">The array to copy to.</param>
/// <param name="destinationIndex">The index into the destination array to which the first copied element is written.</param>
/// <param name="length">The number of elements to copy.</param>
[Pure]
public void CopyTo(int sourceIndex, T[] destination, int destinationIndex, int length)
{
var self = this;
self.ThrowNullRefIfNotInitialized();
Array.Copy(self.array, sourceIndex, destination, destinationIndex, length);
}
/// <summary>
/// Returns a new array with the specified value inserted at the specified position.
/// </summary>
@@ -1030,131 +803,6 @@ namespace System.Collections.Immutable
return self;
}
/// <summary>
/// Returns a builder that is populated with the same contents as this array.
/// </summary>
/// <returns>The new builder.</returns>
[Pure]
public ImmutableArray<T>.Builder ToBuilder()
{
var self = this;
if (self.Length == 0)
{
return new Builder(); // allow the builder to create itself with a reasonable default capacity
}
var builder = new Builder(self.Length);
builder.AddRange(self);
return builder;
}
/// <summary>
/// Returns an enumerator for the contents of the array.
/// </summary>
/// <returns>An enumerator.</returns>
[Pure]
public Enumerator GetEnumerator()
{
var self = this;
self.ThrowNullRefIfNotInitialized();
return new Enumerator(self.array);
}
/// <summary>
/// Returns a hash code for this instance.
/// </summary>
/// <returns>
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
/// </returns>
[Pure]
public override int GetHashCode()
{
var self = this;
return self.array == null ? 0 : self.array.GetHashCode();
}
/// <summary>
/// Determines whether the specified <see cref="Object"/> is equal to this instance.
/// </summary>
/// <param name="obj">The <see cref="Object"/> to compare with this instance.</param>
/// <returns>
/// <c>true</c> if the specified <see cref="Object"/> is equal to this instance; otherwise, <c>false</c>.
/// </returns>
[Pure]
public override bool Equals(object obj)
{
IImmutableArray other = obj as IImmutableArray;
if (other != null)
{
return this.array == other.Array;
}
return false;
}
/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
/// <param name="other">An object to compare with this object.</param>
/// <returns>
/// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
/// </returns>
[Pure]
[NonVersionable]
public bool Equals(ImmutableArray<T> other)
{
return this.array == other.array;
}
/// <summary>
/// Initializes a new instance of the <see cref="ImmutableArray{T}"/> struct based on the contents
/// of an existing instance, allowing a covariant static cast to efficiently reuse the existing array.
/// </summary>
/// <param name="items">The array to initialize the array with. No copy is made.</param>
/// <remarks>
/// Covariant upcasts from this method may be reversed by calling the
/// <see cref="ImmutableArray{T}.As{TOther}"/> or <see cref="ImmutableArray{T}.CastArray{TOther}"/>method.
/// </remarks>
[Pure]
public static ImmutableArray<T> CastUp<TDerived>(ImmutableArray<TDerived> items)
where TDerived : class, T
{
return new ImmutableArray<T>(items.array);
}
/// <summary>
/// Initializes a new instance of the <see cref="ImmutableArray{T}"/> struct by casting the underlying
/// array to an array of type <typeparam name="TOther"/>.
/// </summary>
/// <exception cref="InvalidCastException">Thrown if the cast is illegal.</exception>
[Pure]
public ImmutableArray<TOther> CastArray<TOther>() where TOther : class
{
return new ImmutableArray<TOther>((TOther[])(object)array);
}
/// <summary>
/// Creates an immutable array for this array, cast to a different element type.
/// </summary>
/// <typeparam name="TOther">The type of array element to return.</typeparam>
/// <returns>
/// A struct typed for the base element type. If the cast fails, an instance
/// is returned whose <see cref="IsDefault"/> property returns <c>true</c>.
/// </returns>
/// <remarks>
/// Arrays of derived elements types can be cast to arrays of base element types
/// without reallocating the array.
/// These upcasts can be reversed via this same method, casting an array of base
/// element types to their derived types. However, downcasting is only successful
/// when it reverses a prior upcasting operation.
/// </remarks>
[Pure]
public ImmutableArray<TOther> As<TOther>() where TOther : class
{
return new ImmutableArray<TOther>(this.array as TOther[]);
}
/// <summary>
/// Filters the elements of this array to those assignable to the specified type.
/// </summary>
@@ -1207,32 +855,6 @@ namespace System.Collections.Immutable
throw new NotSupportedException();
}
/// <summary>
/// Returns an enumerator for the contents of the array.
/// </summary>
/// <returns>An enumerator.</returns>
/// <exception cref="InvalidOperationException">Thrown if the <see cref="IsDefault"/> property returns true.</exception>
[Pure]
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
var self = this;
self.ThrowInvalidOperationIfNotInitialized();
return EnumeratorObject.Create(self.array);
}
/// <summary>
/// Returns an enumerator for the contents of the array.
/// </summary>
/// <returns>An enumerator.</returns>
/// <exception cref="InvalidOperationException">Thrown if the <see cref="IsDefault"/> property returns true.</exception>
[Pure]
IEnumerator IEnumerable.GetEnumerator()
{
var self = this;
self.ThrowInvalidOperationIfNotInitialized();
return EnumeratorObject.Create(self.array);
}
/// <summary>
/// See <see cref="IImmutableList{T}"/>
/// </summary>
@@ -1643,37 +1265,6 @@ namespace System.Collections.Immutable
#endregion
/// <summary>
/// Throws a null reference exception if the array field is null.
/// </summary>
internal void ThrowNullRefIfNotInitialized()
{
// Force NullReferenceException if array is null by touching its Length.
// This way of checking has a nice property of requiring very little code
// and not having any conditions/branches.
// In a faulting scenario we are relying on hardware to generate the fault.
// And in the non-faulting scenario (most common) the check is virtually free since
// if we are going to do anything with the array, we will need Length anyways
// so touching it, and potentially causing a cache miss, is not going to be an
// extra expense.
var unused = this.array.Length;
}
/// <summary>
/// Throws an <see cref="InvalidOperationException"/> if the <see cref="array"/> field is null, i.e. the
/// <see cref="IsDefault"/> property returns true. The
/// <see cref="InvalidOperationException"/> message specifies that the operation cannot be performed
/// on a default instance of <see cref="ImmutableArray{T}"/>.
///
/// This is intended for explicitly implemented interface method and property implementations.
/// </summary>
private void ThrowInvalidOperationIfNotInitialized()
{
if (this.IsDefault)
{
throw new InvalidOperationException(SR.InvalidOperationOnDefaultArray);
}
}
/// <summary>
/// Returns an array with items at the specified indices removed.

View File

@@ -1,54 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
namespace System.Collections.Immutable
{
/// <summary>
/// A simple view of the immutable collection that the debugger can show to the developer.
/// </summary>
internal class ImmutableDictionaryDebuggerProxy<TKey, TValue>
{
/// <summary>
/// The collection to be enumerated.
/// </summary>
private readonly ImmutableDictionary<TKey, TValue> _map;
/// <summary>
/// The simple view of the collection.
/// </summary>
private KeyValuePair<TKey, TValue>[] _contents;
/// <summary>
/// Initializes a new instance of the <see cref="ImmutableDictionaryDebuggerProxy{TKey, TValue}"/> class.
/// </summary>
/// <param name="map">The collection to display in the debugger</param>
public ImmutableDictionaryDebuggerProxy(ImmutableDictionary<TKey, TValue> map)
{
Requires.NotNull(map, nameof(map));
_map = map;
}
/// <summary>
/// Gets a simple debugger-viewable collection.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public KeyValuePair<TKey, TValue>[] Contents
{
get
{
if (_contents == null)
{
_contents = _map.ToArray(_map.Count);
}
return _contents;
}
}
}
}

View File

@@ -0,0 +1,64 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace System.Collections.Immutable
{
/// <summary>
/// Displays immutable dictionaries in the debugger.
/// </summary>
/// <typeparam name="TKey">The type of the dictionary's keys.</typeparam>
/// <typeparam name="TValue">The type of the dictionary's values.</typeparam>
internal class ImmutableDictionaryDebuggerProxy<TKey, TValue> : ImmutableEnumerableDebuggerProxy<KeyValuePair<TKey, TValue>>
{
/// <summary>
/// Initializes a new instance of the <see cref="ImmutableDictionaryDebuggerProxy{TKey, TValue}"/> class.
/// </summary>
/// <param name="dictionary">The enumerable to show in the debugger.</param>
public ImmutableDictionaryDebuggerProxy(IImmutableDictionary<TKey, TValue> dictionary)
: base(enumerable: dictionary)
{
}
}
/// <summary>
/// Displays immutable enumerables in the debugger.
/// </summary>
/// <typeparam name="T">The element type of the enumerable.</typeparam>
/// <remarks>
/// This class should only be used with immutable enumerables, since it
/// caches the enumerable into an array for display in the debugger.
/// </remarks>
internal class ImmutableEnumerableDebuggerProxy<T>
{
/// <summary>
/// The enumerable to show to the debugger.
/// </summary>
private readonly IEnumerable<T> _enumerable;
/// <summary>
/// The contents of the enumerable, cached into an array.
/// </summary>
private T[] _cachedContents;
/// <summary>
/// Initializes a new instance of the <see cref="ImmutableEnumerableDebuggerProxy{T}"/> class.
/// </summary>
/// <param name="enumerable">The enumerable to show in the debugger.</param>
public ImmutableEnumerableDebuggerProxy(IEnumerable<T> enumerable)
{
Requires.NotNull(enumerable, nameof(enumerable));
_enumerable = enumerable;
}
/// <summary>
/// Gets the contents of the enumerable for display in the debugger.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public T[] Contents => _cachedContents ?? (_cachedContents = _enumerable.ToArray());
}
}

View File

@@ -0,0 +1,181 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Reflection;
namespace System.Collections.Immutable
{
internal static partial class ImmutableExtensions
{
/// <summary>
/// Tries to divine the number of elements in a sequence without actually enumerating each element.
/// </summary>
/// <typeparam name="T">The type of elements in the sequence.</typeparam>
/// <param name="sequence">The enumerable source.</param>
/// <param name="count">Receives the number of elements in the enumeration, if it could be determined.</param>
/// <returns><c>true</c> if the count could be determined; <c>false</c> otherwise.</returns>
internal static bool TryGetCount<T>(this IEnumerable<T> sequence, out int count)
{
return TryGetCount<T>((IEnumerable)sequence, out count);
}
/// <summary>
/// Tries to divine the number of elements in a sequence without actually enumerating each element.
/// </summary>
/// <typeparam name="T">The type of elements in the sequence.</typeparam>
/// <param name="sequence">The enumerable source.</param>
/// <param name="count">Receives the number of elements in the enumeration, if it could be determined.</param>
/// <returns><c>true</c> if the count could be determined; <c>false</c> otherwise.</returns>
internal static bool TryGetCount<T>(this IEnumerable sequence, out int count)
{
var collection = sequence as ICollection;
if (collection != null)
{
count = collection.Count;
return true;
}
var collectionOfT = sequence as ICollection<T>;
if (collectionOfT != null)
{
count = collectionOfT.Count;
return true;
}
var readOnlyCollection = sequence as IReadOnlyCollection<T>;
if (readOnlyCollection != null)
{
count = readOnlyCollection.Count;
return true;
}
count = 0;
return false;
}
/// <summary>
/// Gets the number of elements in the specified sequence,
/// while guaranteeing that the sequence is only enumerated once
/// in total by this method and the caller.
/// </summary>
/// <typeparam name="T">The type of element in the collection.</typeparam>
/// <param name="sequence">The sequence.</param>
/// <returns>The number of elements in the sequence.</returns>
internal static int GetCount<T>(ref IEnumerable<T> sequence)
{
int count;
if (!sequence.TryGetCount(out count))
{
// We cannot predict the length of the sequence. We must walk the entire sequence
// to find the count. But avoid our caller also having to enumerate by capturing
// the enumeration in a snapshot and passing that back to the caller.
var list = sequence.ToList();
count = list.Count;
sequence = list;
}
return count;
}
/// <summary>
/// Tries to copy the elements in the sequence to the specified array,
/// if the sequence is a well-known collection type. Otherwise, does
/// nothing and returns <c>false</c>.
/// </summary>
/// <typeparam name="T">The type of element in the sequence.</typeparam>
/// <param name="sequence">The sequence to copy.</param>
/// <param name="array">The array to copy the elements to.</param>
/// <param name="arrayIndex">The index in the array to start copying.</param>
/// <returns><c>true</c> if the elements were successfully copied; <c>false</c> otherwise.</returns>
/// <remarks>
/// <para>
/// The reason we don't copy anything other than for well-known types is that a malicious interface
/// implementation of <see cref="ICollection{T}"/> could hold on to the array when its <see cref="ICollection{T}.CopyTo"/>
/// method is called. If the array it holds onto underlies an <see cref="ImmutableArray{T}"/>, it could violate
/// immutability by modifying the array.
/// </para>
/// </remarks>
internal static bool TryCopyTo<T>(this IEnumerable<T> sequence, T[] array, int arrayIndex)
{
Debug.Assert(sequence != null);
Debug.Assert(array != null);
Debug.Assert(arrayIndex >= 0 && arrayIndex <= array.Length);
// IList is the GCD of what the following types implement.
var listInterface = sequence as IList<T>;
if (listInterface != null)
{
var list = sequence as List<T>;
if (list != null)
{
list.CopyTo(array, arrayIndex);
return true;
}
// Array.Copy can throw an ArrayTypeMismatchException if the underlying type of
// the destination array is not typeof(T[]), but is assignment-compatible with T[].
// See https://github.com/dotnet/corefx/issues/2241 for more info.
if (sequence.GetType() == typeof(T[]))
{
var sourceArray = (T[])sequence;
Array.Copy(sourceArray, 0, array, arrayIndex, sourceArray.Length);
return true;
}
if (sequence is ImmutableArray<T>)
{
var immutable = (ImmutableArray<T>)sequence;
Array.Copy(immutable.array, 0, array, arrayIndex, immutable.Length);
return true;
}
}
return false;
}
/// <summary>
/// Gets a copy of a sequence as an array.
/// </summary>
/// <typeparam name="T">The type of element.</typeparam>
/// <param name="sequence">The sequence to be copied.</param>
/// <param name="count">The number of elements in the sequence.</param>
/// <returns>The array.</returns>
/// <remarks>
/// This is more efficient than the <see cref="Enumerable.ToArray{TSource}"/> extension method
/// because that only tries to cast the sequence to <see cref="ICollection{T}"/> to determine
/// the count before it falls back to reallocating arrays as it enumerates.
/// </remarks>
internal static T[] ToArray<T>(this IEnumerable<T> sequence, int count)
{
Requires.NotNull(sequence, nameof(sequence));
Requires.Range(count >= 0, nameof(count));
if (count == 0)
{
return ImmutableArray<T>.Empty.array;
}
T[] array = new T[count];
if (!sequence.TryCopyTo(array, 0))
{
int i = 0;
foreach (var item in sequence)
{
Requires.Argument(i < count);
array[i++] = item;
}
Requires.Argument(i == count);
}
return array;
}
}
}

View File

@@ -14,172 +14,8 @@ namespace System.Collections.Immutable
/// <summary>
/// Extension methods for immutable types.
/// </summary>
internal static class ImmutableExtensions
internal static partial class ImmutableExtensions
{
/// <summary>
/// Tries to divine the number of elements in a sequence without actually enumerating each element.
/// </summary>
/// <typeparam name="T">The type of elements in the sequence.</typeparam>
/// <param name="sequence">The enumerable source.</param>
/// <param name="count">Receives the number of elements in the enumeration, if it could be determined.</param>
/// <returns><c>true</c> if the count could be determined; <c>false</c> otherwise.</returns>
internal static bool TryGetCount<T>(this IEnumerable<T> sequence, out int count)
{
return TryGetCount<T>((IEnumerable)sequence, out count);
}
/// <summary>
/// Tries to divine the number of elements in a sequence without actually enumerating each element.
/// </summary>
/// <typeparam name="T">The type of elements in the sequence.</typeparam>
/// <param name="sequence">The enumerable source.</param>
/// <param name="count">Receives the number of elements in the enumeration, if it could be determined.</param>
/// <returns><c>true</c> if the count could be determined; <c>false</c> otherwise.</returns>
internal static bool TryGetCount<T>(this IEnumerable sequence, out int count)
{
var collection = sequence as ICollection;
if (collection != null)
{
count = collection.Count;
return true;
}
var collectionOfT = sequence as ICollection<T>;
if (collectionOfT != null)
{
count = collectionOfT.Count;
return true;
}
var readOnlyCollection = sequence as IReadOnlyCollection<T>;
if (readOnlyCollection != null)
{
count = readOnlyCollection.Count;
return true;
}
count = 0;
return false;
}
/// <summary>
/// Gets the number of elements in the specified sequence,
/// while guaranteeing that the sequence is only enumerated once
/// in total by this method and the caller.
/// </summary>
/// <typeparam name="T">The type of element in the collection.</typeparam>
/// <param name="sequence">The sequence.</param>
/// <returns>The number of elements in the sequence.</returns>
internal static int GetCount<T>(ref IEnumerable<T> sequence)
{
int count;
if (!sequence.TryGetCount(out count))
{
// We cannot predict the length of the sequence. We must walk the entire sequence
// to find the count. But avoid our caller also having to enumerate by capturing
// the enumeration in a snapshot and passing that back to the caller.
var list = sequence.ToList();
count = list.Count;
sequence = list;
}
return count;
}
/// <summary>
/// Tries to copy the elements in the sequence to the specified array,
/// if the sequence is a well-known collection type. Otherwise, does
/// nothing and returns <c>false</c>.
/// </summary>
/// <typeparam name="T">The type of element in the sequence.</typeparam>
/// <param name="sequence">The sequence to copy.</param>
/// <param name="array">The array to copy the elements to.</param>
/// <param name="arrayIndex">The index in the array to start copying.</param>
/// <returns><c>true</c> if the elements were successfully copied; <c>false</c> otherwise.</returns>
/// <remarks>
/// <para>
/// The reason we don't copy anything other than for well-known types is that a malicious interface
/// implementation of <see cref="ICollection{T}"/> could hold on to the array when its <see cref="ICollection{T}.CopyTo"/>
/// method is called. If the array it holds onto underlies an <see cref="ImmutableArray{T}"/>, it could violate
/// immutability by modifying the array.
/// </para>
/// </remarks>
internal static bool TryCopyTo<T>(this IEnumerable<T> sequence, T[] array, int arrayIndex)
{
Debug.Assert(sequence != null);
Debug.Assert(array != null);
Debug.Assert(arrayIndex >= 0 && arrayIndex <= array.Length);
// IList is the GCD of what the following types implement.
var listInterface = sequence as IList<T>;
if (listInterface != null)
{
var list = sequence as List<T>;
if (list != null)
{
list.CopyTo(array, arrayIndex);
return true;
}
// Array.Copy can throw an ArrayTypeMismatchException if the underlying type of
// the destination array is not typeof(T[]), but is assignment-compatible with T[].
// See https://github.com/dotnet/corefx/issues/2241 for more info.
if (sequence.GetType() == typeof(T[]))
{
var sourceArray = (T[])sequence;
Array.Copy(sourceArray, 0, array, arrayIndex, sourceArray.Length);
return true;
}
if (sequence is ImmutableArray<T>)
{
var immutable = (ImmutableArray<T>)sequence;
Array.Copy(immutable.array, 0, array, arrayIndex, immutable.Length);
return true;
}
}
return false;
}
/// <summary>
/// Gets a copy of a sequence as an array.
/// </summary>
/// <typeparam name="T">The type of element.</typeparam>
/// <param name="sequence">The sequence to be copied.</param>
/// <param name="count">The number of elements in the sequence.</param>
/// <returns>The array.</returns>
/// <remarks>
/// This is more efficient than the <see cref="Enumerable.ToArray{TSource}"/> extension method
/// because that only tries to cast the sequence to <see cref="ICollection{T}"/> to determine
/// the count before it falls back to reallocating arrays as it enumerates.
/// </remarks>
internal static T[] ToArray<T>(this IEnumerable<T> sequence, int count)
{
Requires.NotNull(sequence, nameof(sequence));
Requires.Range(count >= 0, nameof(count));
if (count == 0)
{
return ImmutableArray<T>.Empty.array;
}
T[] array = new T[count];
if (!sequence.TryCopyTo(array, 0))
{
int i = 0;
foreach (var item in sequence)
{
Requires.Argument(i < count);
array[i++] = item;
}
Requires.Argument(i == count);
}
return array;
}
#if EqualsStructurally

View File

@@ -15,7 +15,7 @@ namespace System.Collections.Immutable
/// </summary>
/// <typeparam name="T">The type of elements in the set.</typeparam>
[DebuggerDisplay("Count = {Count}")]
[DebuggerTypeProxy(typeof(ImmutableHashSetDebuggerProxy<>))]
[DebuggerTypeProxy(typeof(ImmutableEnumerableDebuggerProxy<>))]
public sealed partial class ImmutableHashSet<T> : IImmutableSet<T>, IHashKeyCollection<T>, IReadOnlyCollection<T>, ICollection<T>, ISet<T>, ICollection, IStrongEnumerable<T, ImmutableHashSet<T>.Enumerator>
{
/// <summary>

View File

@@ -1 +1 @@
4c0868d47412dea5b94ed1c36f48ef11c1ba2538
f47e2be8fb4b862e1a9cae6fe9ddf551dcc207bb

View File

@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
@@ -32,49 +33,68 @@ namespace System.Collections.Immutable
/// <param name="item">The item to prepopulate.</param>
/// <returns>The new immutable collection.</returns>
[Pure]
public static ImmutableQueue<T> Create<T>(T item)
{
return ImmutableQueue<T>.Empty.Enqueue(item);
}
public static ImmutableQueue<T> Create<T>(T item) => ImmutableQueue<T>.Empty.Enqueue(item);
/// <summary>
/// Creates a new immutable collection prefilled with the specified items.
/// Creates a new immutable queue from the specified items.
/// </summary>
/// <typeparam name="T">The type of items stored by the collection.</typeparam>
/// <param name="items">The items to prepopulate.</param>
/// <returns>The new immutable collection.</returns>
/// <typeparam name="T">The type of items to store in the queue.</typeparam>
/// <param name="items">The enumerable to copy items from.</param>
/// <returns>The new immutable queue.</returns>
[Pure]
public static ImmutableQueue<T> CreateRange<T>(IEnumerable<T> items)
{
Requires.NotNull(items, nameof(items));
var queue = ImmutableQueue<T>.Empty;
foreach (var item in items)
var array = items as T[];
if (array != null)
{
queue = queue.Enqueue(item);
return Create(items: array);
}
return queue;
using (IEnumerator<T> e = items.GetEnumerator())
{
if (!e.MoveNext())
{
return ImmutableQueue<T>.Empty;
}
var forwards = ImmutableStack.Create(e.Current);
var backwards = ImmutableStack<T>.Empty;
while (e.MoveNext())
{
backwards = backwards.Push(e.Current);
}
return new ImmutableQueue<T>(forwards: forwards, backwards: backwards);
}
}
/// <summary>
/// Creates a new immutable collection prefilled with the specified items.
/// Creates a new immutable queue from the specified items.
/// </summary>
/// <typeparam name="T">The type of items stored by the collection.</typeparam>
/// <param name="items">The items to prepopulate.</param>
/// <returns>The new immutable collection.</returns>
/// <typeparam name="T">The type of items to store in the queue.</typeparam>
/// <param name="items">The array to copy items from.</param>
/// <returns>The new immutable queue.</returns>
[Pure]
public static ImmutableQueue<T> Create<T>(params T[] items)
{
Requires.NotNull(items, nameof(items));
var queue = ImmutableQueue<T>.Empty;
foreach (var item in items)
if (items.Length == 0)
{
queue = queue.Enqueue(item);
return ImmutableQueue<T>.Empty;
}
return queue;
var forwards = ImmutableStack<T>.Empty;
for (int i = items.Length - 1; i >= 0; i--)
{
forwards = forwards.Push(items[i]);
}
return new ImmutableQueue<T>(forwards: forwards, backwards: ImmutableStack<T>.Empty);
}
/// <summary>

Some files were not shown because too many files have changed in this diff Show More