You've already forked linux-packaging-mono
Imported Upstream version 5.2.0.175
Former-commit-id: bb0468d0f257ff100aa895eb5fe583fb5dfbf900
This commit is contained in:
parent
4bdbaf4a88
commit
966bba02bb
@@ -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
|
||||
|
||||
@@ -5,5 +5,6 @@
|
||||
<PackageVersion>1.4.0</PackageVersion>
|
||||
<AssemblyVersion>1.2.2</AssemblyVersion>
|
||||
<IsNETCoreApp>true</IsNETCoreApp>
|
||||
<IsUAP>true</IsUAP>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
<PropertyGroup>
|
||||
<BuildConfigurations>
|
||||
netstandard1.0;
|
||||
netstandard;
|
||||
netcoreapp;
|
||||
uap-Windows_NT;
|
||||
</BuildConfigurations>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1 +1 @@
|
||||
4c0868d47412dea5b94ed1c36f48ef11c1ba2538
|
||||
f47e2be8fb4b862e1a9cae6fe9ddf551dcc207bb
|
||||
@@ -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
Reference in New Issue
Block a user