You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
@@ -0,0 +1,128 @@
|
||||
// ==++==
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// ==--==
|
||||
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
//
|
||||
// CDSCollectionETWBCLProvider.cs
|
||||
//
|
||||
// <OWNER>[....]</OWNER>
|
||||
//
|
||||
// A helper class for firing ETW events related to the Coordination Data Structure
|
||||
// collection types. This provider is used by CDS collections in both mscorlib.dll
|
||||
// and System.dll. The purpose of sharing the provider class is to be able to enable
|
||||
// ETW tracing on all CDS collection with a single ETW provider GUID, and to minimize
|
||||
// the number of providers in use.
|
||||
//
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace System.Collections.Concurrent
|
||||
{
|
||||
#if !FEATURE_PAL // PAL doesn't support eventing
|
||||
using System.Diagnostics.Tracing;
|
||||
|
||||
/// <summary>Provides an event source for tracing CDS collection information.</summary>
|
||||
[System.Runtime.CompilerServices.FriendAccessAllowed]
|
||||
[EventSource(
|
||||
Name = "System.Collections.Concurrent.ConcurrentCollectionsEventSource",
|
||||
Guid = "35167F8E-49B2-4b96-AB86-435B59336B5E",
|
||||
LocalizationResources = "mscorlib")]
|
||||
internal sealed class CDSCollectionETWBCLProvider : EventSource
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the singleton instance for the collection ETW provider.
|
||||
/// The collection provider GUID is {35167F8E-49B2-4b96-AB86-435B59336B5E}.
|
||||
/// </summary>
|
||||
public static CDSCollectionETWBCLProvider Log = new CDSCollectionETWBCLProvider();
|
||||
/// <summary>Prevent external instantiation. All logging should go through the Log instance.</summary>
|
||||
private CDSCollectionETWBCLProvider() { }
|
||||
|
||||
/// <summary>Enabled for all keywords.</summary>
|
||||
private const EventKeywords ALL_KEYWORDS = (EventKeywords)(-1);
|
||||
|
||||
//-----------------------------------------------------------------------------------
|
||||
//
|
||||
// CDS Collection Event IDs (must be unique)
|
||||
//
|
||||
|
||||
private const int CONCURRENTSTACK_FASTPUSHFAILED_ID = 1;
|
||||
private const int CONCURRENTSTACK_FASTPOPFAILED_ID = 2;
|
||||
private const int CONCURRENTDICTIONARY_ACQUIRINGALLLOCKS_ID = 3;
|
||||
private const int CONCURRENTBAG_TRYTAKESTEALS_ID = 4;
|
||||
private const int CONCURRENTBAG_TRYPEEKSTEALS_ID = 5;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ConcurrentStack Events
|
||||
//
|
||||
|
||||
[Event(CONCURRENTSTACK_FASTPUSHFAILED_ID, Level = EventLevel.Warning)]
|
||||
public void ConcurrentStack_FastPushFailed(int spinCount)
|
||||
{
|
||||
if (IsEnabled(EventLevel.Warning, ALL_KEYWORDS))
|
||||
{
|
||||
WriteEvent(CONCURRENTSTACK_FASTPUSHFAILED_ID, spinCount);
|
||||
}
|
||||
}
|
||||
|
||||
[Event(CONCURRENTSTACK_FASTPOPFAILED_ID, Level = EventLevel.Warning)]
|
||||
public void ConcurrentStack_FastPopFailed(int spinCount)
|
||||
{
|
||||
if (IsEnabled(EventLevel.Warning, ALL_KEYWORDS))
|
||||
{
|
||||
WriteEvent(CONCURRENTSTACK_FASTPOPFAILED_ID, spinCount);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ConcurrentDictionary Events
|
||||
//
|
||||
|
||||
[Event(CONCURRENTDICTIONARY_ACQUIRINGALLLOCKS_ID, Level = EventLevel.Warning)]
|
||||
public void ConcurrentDictionary_AcquiringAllLocks(int numOfBuckets)
|
||||
{
|
||||
if (IsEnabled(EventLevel.Warning, ALL_KEYWORDS))
|
||||
{
|
||||
WriteEvent(CONCURRENTDICTIONARY_ACQUIRINGALLLOCKS_ID, numOfBuckets);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Events below this point are used by the CDS types in System.DLL
|
||||
//
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ConcurrentBag Events
|
||||
//
|
||||
|
||||
[Event(CONCURRENTBAG_TRYTAKESTEALS_ID, Level = EventLevel.Verbose)]
|
||||
public void ConcurrentBag_TryTakeSteals()
|
||||
{
|
||||
if (IsEnabled(EventLevel.Verbose, ALL_KEYWORDS))
|
||||
{
|
||||
WriteEvent(CONCURRENTBAG_TRYTAKESTEALS_ID);
|
||||
}
|
||||
}
|
||||
|
||||
[Event(CONCURRENTBAG_TRYPEEKSTEALS_ID, Level = EventLevel.Verbose)]
|
||||
public void ConcurrentBag_TryPeekSteals()
|
||||
{
|
||||
if (IsEnabled(EventLevel.Verbose, ALL_KEYWORDS))
|
||||
{
|
||||
WriteEvent(CONCURRENTBAG_TRYPEEKSTEALS_ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !FEATURE_PAL
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,119 @@
|
||||
// ==++==
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// ==--==
|
||||
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
//
|
||||
// IProducerConsumerCollection.cs
|
||||
//
|
||||
// <OWNER>[....]</OWNER>
|
||||
//
|
||||
// A common interface for all concurrent collections.
|
||||
//
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace System.Collections.Concurrent
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Defines methods to manipulate thread-safe collections intended for producer/consumer usage.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Specifies the type of elements in the collection.</typeparam>
|
||||
/// <remarks>
|
||||
/// All implementations of this interface must enable all members of this interface
|
||||
/// to be used concurrently from multiple threads.
|
||||
/// </remarks>
|
||||
public interface IProducerConsumerCollection<T> : IEnumerable<T>, ICollection
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Copies the elements of the <see cref="IProducerConsumerCollection{T}"/> to
|
||||
/// an
|
||||
/// <see cref="T:System.Array"/>, starting at a specified index.
|
||||
/// </summary>
|
||||
/// <param name="array">The one-dimensional <see cref="T:System.Array"/> that is the destination of
|
||||
/// the elements copied from the <see cref="IProducerConsumerCollection{T}"/>.
|
||||
/// The array must have zero-based indexing.</param>
|
||||
/// <param name="index">The zero-based index in <paramref name="array"/> at which copying
|
||||
/// begins.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="array"/> is a null reference (Nothing in
|
||||
/// Visual Basic).</exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException"><paramref name="index"/> is less than
|
||||
/// zero.</exception>
|
||||
/// <exception cref="ArgumentException"><paramref name="index"/> is equal to or greater than the
|
||||
/// length of the <paramref name="array"/>
|
||||
/// -or- The number of elements in the source <see cref="ConcurrentQueue{T}"/> is greater than the
|
||||
/// available space from <paramref name="index"/> to the end of the destination <paramref
|
||||
/// name="array"/>.
|
||||
/// </exception>
|
||||
void CopyTo(T[] array, int index);
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to add an object to the <see
|
||||
/// cref="IProducerConsumerCollection{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="item">The object to add to the <see
|
||||
/// cref="IProducerConsumerCollection{T}"/>.</param>
|
||||
/// <returns>true if the object was added successfully; otherwise, false.</returns>
|
||||
/// <exception cref="T:System.ArgumentException">The <paramref name="item"/> was invalid for this collection.</exception>
|
||||
bool TryAdd(T item);
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to remove and return an object from the <see cref="IProducerConsumerCollection{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="item">
|
||||
/// When this method returns, if the object was removed and returned successfully, <paramref
|
||||
/// name="item"/> contains the removed object. If no object was available to be removed, the value is
|
||||
/// unspecified.
|
||||
/// </param>
|
||||
/// <returns>true if an object was removed and returned successfully; otherwise, false.</returns>
|
||||
bool TryTake(out T item);
|
||||
|
||||
/// <summary>
|
||||
/// Copies the elements contained in the <see cref="IProducerConsumerCollection{T}"/> to a new array.
|
||||
/// </summary>
|
||||
/// <returns>A new array containing the elements copied from the <see cref="IProducerConsumerCollection{T}"/>.</returns>
|
||||
T[] ToArray();
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A debugger view of the IProducerConsumerCollection that makes it simple to browse the
|
||||
/// collection's contents at a point in time.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of elements stored within.</typeparam>
|
||||
internal sealed class SystemCollectionsConcurrent_ProducerConsumerCollectionDebugView<T>
|
||||
{
|
||||
private IProducerConsumerCollection<T> m_collection; // The collection being viewed.
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new debugger view object for the provided collection object.
|
||||
/// </summary>
|
||||
/// <param name="collection">A collection to browse in the debugger.</param>
|
||||
public SystemCollectionsConcurrent_ProducerConsumerCollectionDebugView(IProducerConsumerCollection<T> collection)
|
||||
{
|
||||
if (collection == null)
|
||||
{
|
||||
throw new ArgumentNullException("collection");
|
||||
}
|
||||
|
||||
m_collection = collection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a snapshot of the underlying collection's elements.
|
||||
/// </summary>
|
||||
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
|
||||
public T[] Items
|
||||
{
|
||||
get { return m_collection.ToArray(); }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
// ==++==
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// ==--==
|
||||
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
//
|
||||
// OrderablePartitioner.cs
|
||||
//
|
||||
// <OWNER>[....]</OWNER>
|
||||
//
|
||||
//
|
||||
//
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Permissions;
|
||||
using System.Threading;
|
||||
|
||||
namespace System.Collections.Concurrent
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Represents a particular manner of splitting an orderable data source into multiple partitions.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">Type of the elements in the collection.</typeparam>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Each element in each partition has an integer index associated with it, which determines the relative
|
||||
/// order of that element against elements in other partitions.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Inheritors of <see cref="OrderablePartitioner{TSource}"/> must adhere to the following rules:
|
||||
/// <ol>
|
||||
/// <li>All indices must be unique, such that there may not be duplicate indices. If all indices are not
|
||||
/// unique, the output ordering may be scrambled.</li>
|
||||
/// <li>All indices must be non-negative. If any indices are negative, consumers of the implementation
|
||||
/// may throw exceptions.</li>
|
||||
/// <li><see cref="GetPartitions"/> and <see cref="GetOrderablePartitions"/> should throw a
|
||||
/// <see cref="T:System.ArgumentOutOfRangeException"/> if the requested partition count is less than or
|
||||
/// equal to zero.</li>
|
||||
/// <li><see cref="GetPartitions"/> and <see cref="GetOrderablePartitions"/> should always return a number
|
||||
/// of enumerables equal to the requested partition count. If the partitioner runs out of data and cannot
|
||||
/// create as many partitions as requested, an empty enumerator should be returned for each of the
|
||||
/// remaining partitions. If this rule is not followed, consumers of the implementation may throw a <see
|
||||
/// cref="T:System.InvalidOperationException"/>.</li>
|
||||
/// <li><see cref="GetPartitions"/>, <see cref="GetOrderablePartitions"/>,
|
||||
/// <see cref="GetDynamicPartitions"/>, and <see cref="GetOrderableDynamicPartitions"/>
|
||||
/// should never return null. If null is returned, a consumer of the implementation may throw a
|
||||
/// <see cref="T:System.InvalidOperationException"/>.</li>
|
||||
/// <li><see cref="GetPartitions"/>, <see cref="GetOrderablePartitions"/>,
|
||||
/// <see cref="GetDynamicPartitions"/>, and <see cref="GetOrderableDynamicPartitions"/>
|
||||
/// should always return partitions that can fully and uniquely enumerate the input data source. All of
|
||||
/// the data and only the data contained in the input source should be enumerated, with no duplication
|
||||
/// that was not already in the input, unless specifically required by the particular partitioner's
|
||||
/// design. If this is not followed, the output ordering may be scrambled.</li>
|
||||
/// <li>If <see cref="KeysOrderedInEachPartition"/> returns true, each partition must return elements
|
||||
/// with increasing key indices.</li>
|
||||
/// <li>If <see cref="KeysOrderedAcrossPartitions"/> returns true, all the keys in partition numbered N
|
||||
/// must be larger than all the keys in partition numbered N-1.</li>
|
||||
/// <li>If <see cref="KeysNormalized"/> returns true, all indices must be monotonically increasing from
|
||||
/// 0, though not necessarily within a single partition.</li>
|
||||
/// </ol>
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[HostProtection(Synchronization = true, ExternalThreading = true)]
|
||||
public abstract class OrderablePartitioner<TSource> : Partitioner<TSource>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="OrderablePartitioner{TSource}"/> class with the
|
||||
/// specified constraints on the index keys.
|
||||
/// </summary>
|
||||
/// <param name="keysOrderedInEachPartition">
|
||||
/// Indicates whether the elements in each partition are yielded in the order of
|
||||
/// increasing keys.
|
||||
/// </param>
|
||||
/// <param name="keysOrderedAcrossPartitions">
|
||||
/// Indicates whether elements in an earlier partition always come before
|
||||
/// elements in a later partition. If true, each element in partition 0 has a smaller order key than
|
||||
/// any element in partition 1, each element in partition 1 has a smaller order key than any element
|
||||
/// in partition 2, and so on.
|
||||
/// </param>
|
||||
/// <param name="keysNormalized">
|
||||
/// Indicates whether keys are normalized. If true, all order keys are distinct
|
||||
/// integers in the range [0 .. numberOfElements-1]. If false, order keys must still be dictinct, but
|
||||
/// only their relative order is considered, not their absolute values.
|
||||
/// </param>
|
||||
protected OrderablePartitioner(bool keysOrderedInEachPartition, bool keysOrderedAcrossPartitions, bool keysNormalized)
|
||||
{
|
||||
KeysOrderedInEachPartition = keysOrderedInEachPartition;
|
||||
KeysOrderedAcrossPartitions = keysOrderedAcrossPartitions;
|
||||
KeysNormalized = keysNormalized;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Partitions the underlying collection into the specified number of orderable partitions.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Each partition is represented as an enumerator over key-value pairs.
|
||||
/// The value of the pair is the element itself, and the key is an integer which determines
|
||||
/// the relative ordering of this element against other elements in the data source.
|
||||
/// </remarks>
|
||||
/// <param name="partitionCount">The number of partitions to create.</param>
|
||||
/// <returns>A list containing <paramref name="partitionCount"/> enumerators.</returns>
|
||||
public abstract IList<IEnumerator<KeyValuePair<long, TSource>>> GetOrderablePartitions(int partitionCount);
|
||||
|
||||
/// <summary>
|
||||
/// Creates an object that can partition the underlying collection into a variable number of
|
||||
/// partitions.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The returned object implements the <see
|
||||
/// cref="T:System.Collections.Generic.IEnumerable{TSource}"/> interface. Calling <see
|
||||
/// cref="System.Collections.Generic.IEnumerable{TSource}.GetEnumerator">GetEnumerator</see> on the
|
||||
/// object creates another partition over the sequence.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Each partition is represented as an enumerator over key-value pairs. The value in the pair is the element
|
||||
/// itself, and the key is an integer which determines the relative ordering of this element against
|
||||
/// other elements.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The <see cref="GetOrderableDynamicPartitions"/> method is only supported if the <see
|
||||
/// cref="System.Collections.Concurrent.Partitioner{TSource}.SupportsDynamicPartitions">SupportsDynamicPartitions</see>
|
||||
/// property returns true.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <returns>An object that can create partitions over the underlying data source.</returns>
|
||||
/// <exception cref="NotSupportedException">Dynamic partitioning is not supported by this
|
||||
/// partitioner.</exception>
|
||||
public virtual IEnumerable<KeyValuePair<long, TSource>> GetOrderableDynamicPartitions()
|
||||
{
|
||||
throw new NotSupportedException(Environment.GetResourceString("Partitioner_DynamicPartitionsNotSupported"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether elements in each partition are yielded in the order of increasing keys.
|
||||
/// </summary>
|
||||
public bool KeysOrderedInEachPartition { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether elements in an earlier partition always come before elements in a later partition.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If <see cref="KeysOrderedAcrossPartitions"/> returns true, each element in partition 0 has a
|
||||
/// smaller order key than any element in partition 1, each element in partition 1 has a smaller
|
||||
/// order key than any element in partition 2, and so on.
|
||||
/// </remarks>
|
||||
public bool KeysOrderedAcrossPartitions { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether order keys are normalized.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If <see cref="KeysNormalized"/> returns true, all order keys are distinct integers in the range
|
||||
/// [0 .. numberOfElements-1]. If the property returns false, order keys must still be dictinct, but
|
||||
/// only their relative order is considered, not their absolute values.
|
||||
/// </remarks>
|
||||
public bool KeysNormalized { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Partitions the underlying collection into the given number of ordered partitions.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default implementation provides the same behavior as <see cref="GetOrderablePartitions"/> except
|
||||
/// that the returned set of partitions does not provide the keys for the elements.
|
||||
/// </remarks>
|
||||
/// <param name="partitionCount">The number of partitions to create.</param>
|
||||
/// <returns>A list containing <paramref name="partitionCount"/> enumerators.</returns>
|
||||
public override IList<IEnumerator<TSource>> GetPartitions(int partitionCount)
|
||||
{
|
||||
IList<IEnumerator<KeyValuePair<long, TSource>>> orderablePartitions = GetOrderablePartitions(partitionCount);
|
||||
|
||||
if (orderablePartitions.Count != partitionCount)
|
||||
{
|
||||
throw new InvalidOperationException("OrderablePartitioner_GetPartitions_WrongNumberOfPartitions");
|
||||
}
|
||||
|
||||
IEnumerator<TSource>[] partitions = new IEnumerator<TSource>[partitionCount];
|
||||
for (int i = 0; i < partitionCount; i++)
|
||||
{
|
||||
partitions[i] = new EnumeratorDropIndices(orderablePartitions[i]);
|
||||
}
|
||||
return partitions;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an object that can partition the underlying collection into a variable number of
|
||||
/// partitions.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The returned object implements the <see
|
||||
/// cref="T:System.Collections.Generic.IEnumerable{TSource}"/> interface. Calling <see
|
||||
/// cref="System.Collections.Generic.IEnumerable{TSource}.GetEnumerator">GetEnumerator</see> on the
|
||||
/// object creates another partition over the sequence.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The default implementation provides the same behavior as <see cref="GetOrderableDynamicPartitions"/> except
|
||||
/// that the returned set of partitions does not provide the keys for the elements.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The <see cref="GetDynamicPartitions"/> method is only supported if the <see
|
||||
/// cref="System.Collections.Concurrent.Partitioner{TSource}.SupportsDynamicPartitions"/>
|
||||
/// property returns true.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <returns>An object that can create partitions over the underlying data source.</returns>
|
||||
/// <exception cref="NotSupportedException">Dynamic partitioning is not supported by this
|
||||
/// partitioner.</exception>
|
||||
public override IEnumerable<TSource> GetDynamicPartitions()
|
||||
{
|
||||
IEnumerable<KeyValuePair<long, TSource>> orderablePartitions = GetOrderableDynamicPartitions();
|
||||
return new EnumerableDropIndices(orderablePartitions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts an enumerable over key-value pairs to an enumerable over values.
|
||||
/// </summary>
|
||||
private class EnumerableDropIndices : IEnumerable<TSource>, IDisposable
|
||||
{
|
||||
private readonly IEnumerable<KeyValuePair<long, TSource>> m_source;
|
||||
public EnumerableDropIndices(IEnumerable<KeyValuePair<long, TSource>> source)
|
||||
{
|
||||
m_source = source;
|
||||
}
|
||||
public IEnumerator<TSource> GetEnumerator()
|
||||
{
|
||||
return new EnumeratorDropIndices(m_source.GetEnumerator());
|
||||
}
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return ((EnumerableDropIndices)this).GetEnumerator();
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
IDisposable d = m_source as IDisposable;
|
||||
if (d != null)
|
||||
{
|
||||
d.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class EnumeratorDropIndices : IEnumerator<TSource>
|
||||
{
|
||||
private readonly IEnumerator<KeyValuePair<long, TSource>> m_source;
|
||||
public EnumeratorDropIndices(IEnumerator<KeyValuePair<long, TSource>> source)
|
||||
{
|
||||
m_source = source;
|
||||
}
|
||||
public bool MoveNext()
|
||||
{
|
||||
return m_source.MoveNext();
|
||||
}
|
||||
public TSource Current
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_source.Current.Value;
|
||||
}
|
||||
}
|
||||
Object IEnumerator.Current
|
||||
{
|
||||
get
|
||||
{
|
||||
return ((EnumeratorDropIndices)this).Current;
|
||||
}
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
m_source.Dispose();
|
||||
}
|
||||
public void Reset()
|
||||
{
|
||||
m_source.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
// ==++==
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// ==--==
|
||||
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
//
|
||||
// Partitioner.cs
|
||||
//
|
||||
// <OWNER>[....]</OWNER>
|
||||
//
|
||||
// Represents a particular way of splitting a collection into multiple partitions.
|
||||
//
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Permissions;
|
||||
using System.Threading;
|
||||
|
||||
namespace System.Collections.Concurrent
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a particular manner of splitting a data source into multiple partitions.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">Type of the elements in the collection.</typeparam>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Inheritors of <see cref="Partitioner{TSource}"/> must adhere to the following rules:
|
||||
/// <ol>
|
||||
/// <li><see cref="GetPartitions"/> should throw a
|
||||
/// <see cref="T:System.ArgumentOutOfRangeException"/> if the requested partition count is less than or
|
||||
/// equal to zero.</li>
|
||||
/// <li><see cref="GetPartitions"/> should always return a number of enumerables equal to the requested
|
||||
/// partition count. If the partitioner runs out of data and cannot create as many partitions as
|
||||
/// requested, an empty enumerator should be returned for each of the remaining partitions. If this rule
|
||||
/// is not followed, consumers of the implementation may throw a <see
|
||||
/// cref="T:System.InvalidOperationException"/>.</li>
|
||||
/// <li><see cref="GetPartitions"/> and <see cref="GetDynamicPartitions"/>
|
||||
/// should never return null. If null is returned, a consumer of the implementation may throw a
|
||||
/// <see cref="T:System.InvalidOperationException"/>.</li>
|
||||
/// <li><see cref="GetPartitions"/> and <see cref="GetDynamicPartitions"/> should always return
|
||||
/// partitions that can fully and uniquely enumerate the input data source. All of the data and only the
|
||||
/// data contained in the input source should be enumerated, with no duplication that was not already in
|
||||
/// the input, unless specifically required by the particular partitioner's design. If this is not
|
||||
/// followed, the output ordering may be scrambled.</li>
|
||||
/// </ol>
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[HostProtection(Synchronization = true, ExternalThreading = true)]
|
||||
public abstract class Partitioner<TSource>
|
||||
{
|
||||
/// <summary>
|
||||
/// Partitions the underlying collection into the given number of partitions.
|
||||
/// </summary>
|
||||
/// <param name="partitionCount">The number of partitions to create.</param>
|
||||
/// <returns>A list containing <paramref name="partitionCount"/> enumerators.</returns>
|
||||
public abstract IList<IEnumerator<TSource>> GetPartitions(int partitionCount);
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether additional partitions can be created dynamically.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true if the <see cref="Partitioner{TSource}"/> can create partitions dynamically as they are
|
||||
/// requested; false if the <see cref="Partitioner{TSource}"/> can only allocate
|
||||
/// partitions statically.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// If a derived class does not override and implement <see cref="GetDynamicPartitions"/>,
|
||||
/// <see cref="SupportsDynamicPartitions"/> should return false. The value of <see
|
||||
/// cref="SupportsDynamicPartitions"/> should not vary over the lifetime of this instance.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public virtual bool SupportsDynamicPartitions
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an object that can partition the underlying collection into a variable number of
|
||||
/// partitions.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The returned object implements the <see
|
||||
/// cref="T:System.Collections.Generic.IEnumerable{TSource}"/> interface. Calling <see
|
||||
/// cref="System.Collections.Generic.IEnumerable{TSource}.GetEnumerator">GetEnumerator</see> on the
|
||||
/// object creates another partition over the sequence.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The <see cref="GetDynamicPartitions"/> method is only supported if the <see
|
||||
/// cref="SupportsDynamicPartitions"/>
|
||||
/// property returns true.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <returns>An object that can create partitions over the underlying data source.</returns>
|
||||
/// <exception cref="NotSupportedException">Dynamic partitioning is not supported by this
|
||||
/// partitioner.</exception>
|
||||
public virtual IEnumerable<TSource> GetDynamicPartitions()
|
||||
{
|
||||
throw new NotSupportedException(Environment.GetResourceString("Partitioner_DynamicPartitionsNotSupported"));
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
||||
0e7b25c8eec5ef2270f833d3acd6e2faa65156b0
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,80 @@
|
||||
// ==++==
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// ==--==
|
||||
/*============================================================
|
||||
**
|
||||
** Class: CaseInsensitiveComparer
|
||||
**
|
||||
** <OWNER>[....]</OWNER>
|
||||
**
|
||||
**
|
||||
**
|
||||
============================================================*/
|
||||
namespace System.Collections {
|
||||
//This class does not contain members and does not need to be serializable
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Globalization;
|
||||
using System.Diagnostics.Contracts;
|
||||
|
||||
[Serializable]
|
||||
[System.Runtime.InteropServices.ComVisible(true)]
|
||||
public class CaseInsensitiveComparer : IComparer {
|
||||
private CompareInfo m_compareInfo;
|
||||
private static volatile CaseInsensitiveComparer m_InvariantCaseInsensitiveComparer;
|
||||
|
||||
public CaseInsensitiveComparer() {
|
||||
m_compareInfo = CultureInfo.CurrentCulture.CompareInfo;
|
||||
}
|
||||
|
||||
public CaseInsensitiveComparer(CultureInfo culture) {
|
||||
if (culture==null) {
|
||||
throw new ArgumentNullException("culture");
|
||||
}
|
||||
Contract.EndContractBlock();
|
||||
m_compareInfo = culture.CompareInfo;
|
||||
}
|
||||
|
||||
public static CaseInsensitiveComparer Default
|
||||
{
|
||||
get
|
||||
{
|
||||
Contract.Ensures(Contract.Result<CaseInsensitiveComparer>() != null);
|
||||
|
||||
return new CaseInsensitiveComparer(CultureInfo.CurrentCulture);
|
||||
}
|
||||
}
|
||||
|
||||
public static CaseInsensitiveComparer DefaultInvariant
|
||||
{
|
||||
get
|
||||
{
|
||||
Contract.Ensures(Contract.Result<CaseInsensitiveComparer>() != null);
|
||||
|
||||
if (m_InvariantCaseInsensitiveComparer == null) {
|
||||
m_InvariantCaseInsensitiveComparer = new CaseInsensitiveComparer(CultureInfo.InvariantCulture);
|
||||
}
|
||||
return m_InvariantCaseInsensitiveComparer;
|
||||
}
|
||||
}
|
||||
|
||||
// Behaves exactly like Comparer.Default.Compare except that the comparison is case insensitive
|
||||
// Compares two Objects by calling CompareTo. If a ==
|
||||
// b,0 is returned. If a implements
|
||||
// IComparable, a.CompareTo(b) is returned. If a
|
||||
// doesn't implement IComparable and b does,
|
||||
// -(b.CompareTo(a)) is returned, otherwise an
|
||||
// exception is thrown.
|
||||
//
|
||||
public int Compare(Object a, Object b) {
|
||||
String sa = a as String;
|
||||
String sb = b as String;
|
||||
if (sa != null && sb != null)
|
||||
return m_compareInfo.Compare(sa, sb, CompareOptions.IgnoreCase);
|
||||
else
|
||||
return Comparer.Default.Compare(a,b);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
// ==++==
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// ==--==
|
||||
/*============================================================
|
||||
**
|
||||
** Class: CaseInsensitiveHashCodeProvider
|
||||
**
|
||||
** <OWNER>[....]</OWNER>
|
||||
**
|
||||
**
|
||||
** Purpose: Designed to support hashtables which require
|
||||
** case-insensitive behavior while still maintaining case,
|
||||
** this provides an efficient mechanism for getting the
|
||||
** hashcode of the string ignoring case.
|
||||
**
|
||||
**
|
||||
============================================================*/
|
||||
namespace System.Collections {
|
||||
//This class does not contain members and does not need to be serializable
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Globalization;
|
||||
using System.Diagnostics.Contracts;
|
||||
|
||||
[Serializable]
|
||||
[Obsolete("Please use StringComparer instead.")]
|
||||
[System.Runtime.InteropServices.ComVisible(true)]
|
||||
public class CaseInsensitiveHashCodeProvider : IHashCodeProvider {
|
||||
private TextInfo m_text;
|
||||
private static volatile CaseInsensitiveHashCodeProvider m_InvariantCaseInsensitiveHashCodeProvider = null;
|
||||
|
||||
public CaseInsensitiveHashCodeProvider() {
|
||||
m_text = CultureInfo.CurrentCulture.TextInfo;
|
||||
}
|
||||
|
||||
public CaseInsensitiveHashCodeProvider(CultureInfo culture) {
|
||||
if (culture==null) {
|
||||
throw new ArgumentNullException("culture");
|
||||
}
|
||||
Contract.EndContractBlock();
|
||||
m_text = culture.TextInfo;
|
||||
}
|
||||
|
||||
public static CaseInsensitiveHashCodeProvider Default
|
||||
{
|
||||
get
|
||||
{
|
||||
Contract.Ensures(Contract.Result<CaseInsensitiveHashCodeProvider>() != null);
|
||||
|
||||
return new CaseInsensitiveHashCodeProvider(CultureInfo.CurrentCulture);
|
||||
}
|
||||
}
|
||||
|
||||
public static CaseInsensitiveHashCodeProvider DefaultInvariant
|
||||
{
|
||||
get
|
||||
{
|
||||
Contract.Ensures(Contract.Result<CaseInsensitiveHashCodeProvider>() != null);
|
||||
|
||||
if (m_InvariantCaseInsensitiveHashCodeProvider == null) {
|
||||
m_InvariantCaseInsensitiveHashCodeProvider = new CaseInsensitiveHashCodeProvider(CultureInfo.InvariantCulture);
|
||||
}
|
||||
return m_InvariantCaseInsensitiveHashCodeProvider;
|
||||
}
|
||||
}
|
||||
|
||||
public int GetHashCode(Object obj) {
|
||||
if (obj==null) {
|
||||
throw new ArgumentNullException("obj");
|
||||
}
|
||||
Contract.EndContractBlock();
|
||||
|
||||
String s = obj as String;
|
||||
if (s==null) {
|
||||
return obj.GetHashCode();
|
||||
}
|
||||
|
||||
return m_text.GetCaseInsensitiveHashCode(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
// ==++==
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// ==--==
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
// <OWNER>[....]</OWNER>
|
||||
//
|
||||
|
||||
namespace System.Collections {
|
||||
using System;
|
||||
using System.Diagnostics.Contracts;
|
||||
|
||||
// Useful base class for typed read/write collections where items derive from object
|
||||
[Serializable]
|
||||
[System.Runtime.InteropServices.ComVisible(true)]
|
||||
public abstract class CollectionBase : IList {
|
||||
ArrayList list;
|
||||
|
||||
protected CollectionBase() {
|
||||
list = new ArrayList();
|
||||
}
|
||||
|
||||
protected CollectionBase(int capacity) {
|
||||
list = new ArrayList(capacity);
|
||||
}
|
||||
|
||||
|
||||
protected ArrayList InnerList {
|
||||
get {
|
||||
if (list == null)
|
||||
list = new ArrayList();
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
protected IList List {
|
||||
get { return (IList)this; }
|
||||
}
|
||||
|
||||
[System.Runtime.InteropServices.ComVisible(false)]
|
||||
public int Capacity {
|
||||
get {
|
||||
return InnerList.Capacity;
|
||||
}
|
||||
set {
|
||||
InnerList.Capacity = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public int Count {
|
||||
get {
|
||||
return list == null ? 0 : list.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear() {
|
||||
OnClear();
|
||||
InnerList.Clear();
|
||||
OnClearComplete();
|
||||
}
|
||||
|
||||
public void RemoveAt(int index) {
|
||||
if (index < 0 || index >= Count)
|
||||
throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_Index"));
|
||||
Contract.EndContractBlock();
|
||||
Object temp = InnerList[index];
|
||||
OnValidate(temp);
|
||||
OnRemove(index, temp);
|
||||
InnerList.RemoveAt(index);
|
||||
try {
|
||||
OnRemoveComplete(index, temp);
|
||||
}
|
||||
catch {
|
||||
InnerList.Insert(index, temp);
|
||||
throw;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool IList.IsReadOnly {
|
||||
get { return InnerList.IsReadOnly; }
|
||||
}
|
||||
|
||||
bool IList.IsFixedSize {
|
||||
get { return InnerList.IsFixedSize; }
|
||||
}
|
||||
|
||||
bool ICollection.IsSynchronized {
|
||||
get { return InnerList.IsSynchronized; }
|
||||
}
|
||||
|
||||
Object ICollection.SyncRoot {
|
||||
get { return InnerList.SyncRoot; }
|
||||
}
|
||||
|
||||
void ICollection.CopyTo(Array array, int index) {
|
||||
InnerList.CopyTo(array, index);
|
||||
}
|
||||
|
||||
Object IList.this[int index] {
|
||||
get {
|
||||
if (index < 0 || index >= Count)
|
||||
throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_Index"));
|
||||
Contract.EndContractBlock();
|
||||
return InnerList[index];
|
||||
}
|
||||
set {
|
||||
if (index < 0 || index >= Count)
|
||||
throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_Index"));
|
||||
Contract.EndContractBlock();
|
||||
OnValidate(value);
|
||||
Object temp = InnerList[index];
|
||||
OnSet(index, temp, value);
|
||||
InnerList[index] = value;
|
||||
try {
|
||||
OnSetComplete(index, temp, value);
|
||||
}
|
||||
catch {
|
||||
InnerList[index] = temp;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IList.Contains(Object value) {
|
||||
return InnerList.Contains(value);
|
||||
}
|
||||
|
||||
int IList.Add(Object value) {
|
||||
OnValidate(value);
|
||||
OnInsert(InnerList.Count, value);
|
||||
int index = InnerList.Add(value);
|
||||
try {
|
||||
OnInsertComplete(index, value);
|
||||
}
|
||||
catch {
|
||||
InnerList.RemoveAt(index);
|
||||
throw;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
void IList.Remove(Object value) {
|
||||
OnValidate(value);
|
||||
int index = InnerList.IndexOf(value);
|
||||
if (index < 0) throw new ArgumentException(Environment.GetResourceString("Arg_RemoveArgNotFound"));
|
||||
OnRemove(index, value);
|
||||
InnerList.RemoveAt(index);
|
||||
try{
|
||||
OnRemoveComplete(index, value);
|
||||
}
|
||||
catch {
|
||||
InnerList.Insert(index, value);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
int IList.IndexOf(Object value) {
|
||||
return InnerList.IndexOf(value);
|
||||
}
|
||||
|
||||
void IList.Insert(int index, Object value) {
|
||||
if (index < 0 || index > Count)
|
||||
throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_Index"));
|
||||
Contract.EndContractBlock();
|
||||
OnValidate(value);
|
||||
OnInsert(index, value);
|
||||
InnerList.Insert(index, value);
|
||||
try {
|
||||
OnInsertComplete(index, value);
|
||||
}
|
||||
catch {
|
||||
InnerList.RemoveAt(index);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator GetEnumerator() {
|
||||
return InnerList.GetEnumerator();
|
||||
}
|
||||
|
||||
protected virtual void OnSet(int index, Object oldValue, Object newValue) {
|
||||
}
|
||||
|
||||
protected virtual void OnInsert(int index, Object value) {
|
||||
}
|
||||
|
||||
protected virtual void OnClear() {
|
||||
}
|
||||
|
||||
protected virtual void OnRemove(int index, Object value) {
|
||||
}
|
||||
|
||||
protected virtual void OnValidate(Object value) {
|
||||
if (value == null) throw new ArgumentNullException("value");
|
||||
Contract.EndContractBlock();
|
||||
}
|
||||
|
||||
protected virtual void OnSetComplete(int index, Object oldValue, Object newValue) {
|
||||
}
|
||||
|
||||
protected virtual void OnInsertComplete(int index, Object value) {
|
||||
}
|
||||
|
||||
protected virtual void OnClearComplete() {
|
||||
}
|
||||
|
||||
protected virtual void OnRemoveComplete(int index, Object value) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
// ==++==
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// ==--==
|
||||
/*============================================================
|
||||
**
|
||||
** Class: Comparer
|
||||
**
|
||||
** <OWNER>[....]</OWNER>
|
||||
**
|
||||
**
|
||||
** Purpose: Default IComparer implementation.
|
||||
**
|
||||
**
|
||||
===========================================================*/
|
||||
namespace System.Collections {
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Security.Permissions;
|
||||
using System.Diagnostics.Contracts;
|
||||
|
||||
[Serializable]
|
||||
[System.Runtime.InteropServices.ComVisible(true)]
|
||||
public sealed class Comparer : IComparer , ISerializable
|
||||
{
|
||||
private CompareInfo m_compareInfo;
|
||||
public static readonly Comparer Default = new Comparer(CultureInfo.CurrentCulture);
|
||||
public static readonly Comparer DefaultInvariant = new Comparer(CultureInfo.InvariantCulture);
|
||||
|
||||
private const String CompareInfoName = "CompareInfo";
|
||||
|
||||
private Comparer() {
|
||||
m_compareInfo = null;
|
||||
}
|
||||
|
||||
public Comparer(CultureInfo culture) {
|
||||
if (culture==null) {
|
||||
throw new ArgumentNullException("culture");
|
||||
}
|
||||
Contract.EndContractBlock();
|
||||
m_compareInfo = culture.CompareInfo;
|
||||
}
|
||||
|
||||
private Comparer(SerializationInfo info, StreamingContext context) {
|
||||
m_compareInfo = null;
|
||||
SerializationInfoEnumerator enumerator = info.GetEnumerator();
|
||||
while( enumerator.MoveNext()) {
|
||||
switch( enumerator.Name) {
|
||||
case CompareInfoName:
|
||||
m_compareInfo = (CompareInfo) info.GetValue(CompareInfoName, typeof(CompareInfo));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compares two Objects by calling CompareTo. If a ==
|
||||
// b,0 is returned. If a implements
|
||||
// IComparable, a.CompareTo(b) is returned. If a
|
||||
// doesn't implement IComparable and b does,
|
||||
// -(b.CompareTo(a)) is returned, otherwise an
|
||||
// exception is thrown.
|
||||
//
|
||||
public int Compare(Object a, Object b) {
|
||||
if (a == b) return 0;
|
||||
if (a == null) return -1;
|
||||
if (b == null) return 1;
|
||||
if (m_compareInfo != null) {
|
||||
String sa = a as String;
|
||||
String sb = b as String;
|
||||
if (sa != null && sb != null)
|
||||
return m_compareInfo.Compare(sa, sb);
|
||||
}
|
||||
|
||||
IComparable ia = a as IComparable;
|
||||
if (ia != null)
|
||||
return ia.CompareTo(b);
|
||||
|
||||
IComparable ib = b as IComparable;
|
||||
if (ib != null)
|
||||
return -ib.CompareTo(a);
|
||||
|
||||
throw new ArgumentException(Environment.GetResourceString("Argument_ImplementIComparable"));
|
||||
}
|
||||
|
||||
[System.Security.SecurityCritical] // auto-generated_required
|
||||
public void GetObjectData(SerializationInfo info, StreamingContext context) {
|
||||
if (info==null) {
|
||||
throw new ArgumentNullException("info");
|
||||
}
|
||||
Contract.EndContractBlock();
|
||||
|
||||
if( m_compareInfo != null) {
|
||||
info.AddValue(CompareInfoName, m_compareInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// ==++==
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// ==--==
|
||||
// <OWNER>[....]</OWNER>
|
||||
//
|
||||
|
||||
using System.Diagnostics.Contracts;
|
||||
|
||||
namespace System.Collections {
|
||||
|
||||
[Serializable]
|
||||
internal class CompatibleComparer: IEqualityComparer {
|
||||
IComparer _comparer;
|
||||
#pragma warning disable 618
|
||||
IHashCodeProvider _hcp;
|
||||
|
||||
internal CompatibleComparer(IComparer comparer, IHashCodeProvider hashCodeProvider) {
|
||||
_comparer = comparer;
|
||||
_hcp = hashCodeProvider;
|
||||
}
|
||||
#pragma warning restore 618
|
||||
|
||||
public int Compare(Object a, Object b) {
|
||||
if (a == b) return 0;
|
||||
if (a == null) return -1;
|
||||
if (b == null) return 1;
|
||||
if (_comparer != null)
|
||||
return _comparer.Compare(a,b);
|
||||
IComparable ia = a as IComparable;
|
||||
if (ia != null)
|
||||
return ia.CompareTo(b);
|
||||
|
||||
throw new ArgumentException(Environment.GetResourceString("Argument_ImplementIComparable"));
|
||||
}
|
||||
|
||||
public new bool Equals(Object a, Object b) {
|
||||
return Compare(a, b) == 0;
|
||||
}
|
||||
|
||||
public int GetHashCode(Object obj) {
|
||||
if( obj == null) {
|
||||
throw new ArgumentNullException("obj");
|
||||
}
|
||||
Contract.EndContractBlock();
|
||||
|
||||
if (_hcp != null)
|
||||
return _hcp.GetHashCode(obj);
|
||||
return obj.GetHashCode();
|
||||
}
|
||||
|
||||
// These are helpers for the Hashtable to query the IKeyComparer infrastructure.
|
||||
internal IComparer Comparer {
|
||||
get {
|
||||
return _comparer;
|
||||
}
|
||||
}
|
||||
|
||||
// These are helpers for the Hashtable to query the IKeyComparer infrastructure.
|
||||
#pragma warning disable 618
|
||||
internal IHashCodeProvider HashCodeProvider {
|
||||
get {
|
||||
return _hcp;
|
||||
}
|
||||
}
|
||||
#pragma warning restore 618
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
// ==++==
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// ==--==
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
// <OWNER>[....]</OWNER>
|
||||
//
|
||||
|
||||
namespace System.Collections {
|
||||
|
||||
using System;
|
||||
using System.Security.Permissions;
|
||||
|
||||
// Useful base class for typed read/write collections where items derive from object
|
||||
[Serializable]
|
||||
[System.Runtime.InteropServices.ComVisible(true)]
|
||||
public abstract class DictionaryBase : IDictionary {
|
||||
Hashtable hashtable;
|
||||
|
||||
protected Hashtable InnerHashtable {
|
||||
get {
|
||||
if (hashtable == null)
|
||||
hashtable = new Hashtable();
|
||||
return hashtable;
|
||||
}
|
||||
}
|
||||
|
||||
protected IDictionary Dictionary {
|
||||
get { return (IDictionary) this; }
|
||||
}
|
||||
|
||||
public int Count {
|
||||
// to avoid newing inner list if no items are ever added
|
||||
get { return hashtable == null ? 0 : hashtable.Count; }
|
||||
}
|
||||
|
||||
bool IDictionary.IsReadOnly {
|
||||
get { return InnerHashtable.IsReadOnly; }
|
||||
}
|
||||
|
||||
bool IDictionary.IsFixedSize {
|
||||
get { return InnerHashtable.IsFixedSize; }
|
||||
}
|
||||
|
||||
bool ICollection.IsSynchronized {
|
||||
get { return InnerHashtable.IsSynchronized; }
|
||||
}
|
||||
|
||||
ICollection IDictionary.Keys {
|
||||
get {
|
||||
return InnerHashtable.Keys;
|
||||
}
|
||||
}
|
||||
|
||||
Object ICollection.SyncRoot {
|
||||
get { return InnerHashtable.SyncRoot; }
|
||||
}
|
||||
|
||||
ICollection IDictionary.Values {
|
||||
get {
|
||||
return InnerHashtable.Values;
|
||||
}
|
||||
}
|
||||
|
||||
public void CopyTo(Array array, int index) {
|
||||
InnerHashtable.CopyTo(array, index);
|
||||
}
|
||||
|
||||
object IDictionary.this[object key] {
|
||||
get {
|
||||
object currentValue = InnerHashtable[key];
|
||||
OnGet(key, currentValue);
|
||||
return currentValue;
|
||||
}
|
||||
set {
|
||||
OnValidate(key, value);
|
||||
bool keyExists = true;
|
||||
Object temp = InnerHashtable[key];
|
||||
if( temp == null) {
|
||||
keyExists = InnerHashtable.Contains(key);
|
||||
}
|
||||
|
||||
OnSet(key, temp, value);
|
||||
InnerHashtable[key] = value;
|
||||
try {
|
||||
OnSetComplete(key, temp, value);
|
||||
}
|
||||
catch {
|
||||
if( keyExists) {
|
||||
InnerHashtable[key] = temp;
|
||||
}
|
||||
else {
|
||||
InnerHashtable.Remove(key);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IDictionary.Contains(object key) {
|
||||
return InnerHashtable.Contains(key);
|
||||
}
|
||||
|
||||
void IDictionary.Add(object key, object value) {
|
||||
OnValidate(key, value);
|
||||
OnInsert(key, value);
|
||||
InnerHashtable.Add(key, value);
|
||||
try {
|
||||
OnInsertComplete(key, value);
|
||||
}
|
||||
catch {
|
||||
InnerHashtable.Remove(key);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear() {
|
||||
OnClear();
|
||||
InnerHashtable.Clear();
|
||||
OnClearComplete();
|
||||
}
|
||||
|
||||
void IDictionary.Remove(object key) {
|
||||
if(InnerHashtable.Contains(key)) {
|
||||
Object temp = InnerHashtable[key];
|
||||
OnValidate(key, temp);
|
||||
OnRemove(key, temp);
|
||||
|
||||
InnerHashtable.Remove(key);
|
||||
try {
|
||||
OnRemoveComplete(key, temp);
|
||||
}
|
||||
catch {
|
||||
InnerHashtable.Add(key, temp);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IDictionaryEnumerator GetEnumerator() {
|
||||
return InnerHashtable.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() {
|
||||
return InnerHashtable.GetEnumerator();
|
||||
}
|
||||
|
||||
protected virtual object OnGet(object key, object currentValue) {
|
||||
return currentValue;
|
||||
}
|
||||
|
||||
protected virtual void OnSet(object key, object oldValue, object newValue) {
|
||||
}
|
||||
|
||||
protected virtual void OnInsert(object key, object value) {
|
||||
}
|
||||
|
||||
protected virtual void OnClear() {
|
||||
}
|
||||
|
||||
protected virtual void OnRemove(object key, object value) {
|
||||
}
|
||||
|
||||
protected virtual void OnValidate(object key, object value) {
|
||||
}
|
||||
|
||||
protected virtual void OnSetComplete(object key, object oldValue, object newValue) {
|
||||
}
|
||||
|
||||
protected virtual void OnInsertComplete(object key, object value) {
|
||||
}
|
||||
|
||||
protected virtual void OnClearComplete() {
|
||||
}
|
||||
|
||||
protected virtual void OnRemoveComplete(object key, object value) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// ==++==
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// ==--==
|
||||
/*============================================================
|
||||
**
|
||||
** Interface: DictionaryEntry
|
||||
**
|
||||
** <OWNER>[....]</OWNER>
|
||||
**
|
||||
**
|
||||
** Purpose: Return Value for IDictionaryEnumerator::GetEntry
|
||||
**
|
||||
**
|
||||
===========================================================*/
|
||||
namespace System.Collections {
|
||||
|
||||
using System;
|
||||
// A DictionaryEntry holds a key and a value from a dictionary.
|
||||
// It is returned by IDictionaryEnumerator::GetEntry().
|
||||
[System.Runtime.InteropServices.ComVisible(true)]
|
||||
[Serializable]
|
||||
public struct DictionaryEntry
|
||||
{
|
||||
private Object _key;
|
||||
private Object _value;
|
||||
|
||||
// Constructs a new DictionaryEnumerator by setting the Key
|
||||
// and Value fields appropriately.
|
||||
public DictionaryEntry(Object key, Object value) {
|
||||
_key = key;
|
||||
_value = value;
|
||||
}
|
||||
|
||||
public Object Key {
|
||||
get {
|
||||
return _key;
|
||||
}
|
||||
|
||||
set {
|
||||
_key = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Object Value {
|
||||
get {
|
||||
return _value;
|
||||
}
|
||||
|
||||
set {
|
||||
_value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
// ==++==
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// ==--==
|
||||
/*============================================================
|
||||
**
|
||||
** Class: EmptyReadOnlyDictionaryInternal
|
||||
**
|
||||
** <OWNER>[....]</OWNER>
|
||||
**
|
||||
**
|
||||
** Purpose: List for exceptions.
|
||||
**
|
||||
**
|
||||
===========================================================*/
|
||||
|
||||
using System.Diagnostics.Contracts;
|
||||
|
||||
namespace System.Collections {
|
||||
/// This is a simple implementation of IDictionary that is empty and readonly.
|
||||
[Serializable]
|
||||
internal sealed class EmptyReadOnlyDictionaryInternal: IDictionary {
|
||||
|
||||
// Note that this class must be agile with respect to AppDomains. See its usage in
|
||||
// System.Exception to understand why this is the case.
|
||||
|
||||
public EmptyReadOnlyDictionaryInternal() {
|
||||
}
|
||||
|
||||
// IEnumerable members
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() {
|
||||
return new NodeEnumerator();
|
||||
}
|
||||
|
||||
// ICollection members
|
||||
|
||||
public void CopyTo(Array array, int index) {
|
||||
if (array==null)
|
||||
throw new ArgumentNullException("array");
|
||||
|
||||
if (array.Rank != 1)
|
||||
throw new ArgumentException(Environment.GetResourceString("Arg_RankMultiDimNotSupported"));
|
||||
|
||||
if (index < 0)
|
||||
throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
|
||||
|
||||
if ( array.Length - index < this.Count )
|
||||
throw new ArgumentException( Environment.GetResourceString("ArgumentOutOfRange_Index"), "index");
|
||||
Contract.EndContractBlock();
|
||||
|
||||
// the actual copy is a NOP
|
||||
}
|
||||
|
||||
public int Count {
|
||||
get {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public Object SyncRoot {
|
||||
get {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSynchronized {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// IDictionary members
|
||||
|
||||
public Object this[Object key] {
|
||||
get {
|
||||
if (key == null) {
|
||||
throw new ArgumentNullException("key", Environment.GetResourceString("ArgumentNull_Key"));
|
||||
}
|
||||
Contract.EndContractBlock();
|
||||
return null;
|
||||
}
|
||||
set {
|
||||
if (key == null) {
|
||||
throw new ArgumentNullException("key", Environment.GetResourceString("ArgumentNull_Key"));
|
||||
}
|
||||
|
||||
if (!key.GetType().IsSerializable)
|
||||
throw new ArgumentException(Environment.GetResourceString("Argument_NotSerializable"), "key");
|
||||
|
||||
if( (value != null) && (!value.GetType().IsSerializable ) )
|
||||
throw new ArgumentException(Environment.GetResourceString("Argument_NotSerializable"), "value");
|
||||
Contract.EndContractBlock();
|
||||
|
||||
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ReadOnly"));
|
||||
}
|
||||
}
|
||||
|
||||
public ICollection Keys {
|
||||
get {
|
||||
return EmptyArray<Object>.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public ICollection Values {
|
||||
get {
|
||||
return EmptyArray<Object>.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Contains(Object key) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Add(Object key, Object value) {
|
||||
if (key == null) {
|
||||
throw new ArgumentNullException("key", Environment.GetResourceString("ArgumentNull_Key"));
|
||||
}
|
||||
|
||||
if (!key.GetType().IsSerializable)
|
||||
throw new ArgumentException(Environment.GetResourceString("Argument_NotSerializable"), "key" );
|
||||
|
||||
if( (value != null) && (!value.GetType().IsSerializable) )
|
||||
throw new ArgumentException(Environment.GetResourceString("Argument_NotSerializable"), "value");
|
||||
Contract.EndContractBlock();
|
||||
|
||||
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ReadOnly"));
|
||||
}
|
||||
|
||||
public void Clear() {
|
||||
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ReadOnly"));
|
||||
}
|
||||
|
||||
public bool IsReadOnly {
|
||||
get {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsFixedSize {
|
||||
get {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public IDictionaryEnumerator GetEnumerator() {
|
||||
return new NodeEnumerator();
|
||||
}
|
||||
|
||||
public void Remove(Object key) {
|
||||
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ReadOnly"));
|
||||
}
|
||||
|
||||
private sealed class NodeEnumerator : IDictionaryEnumerator {
|
||||
|
||||
public NodeEnumerator() {
|
||||
}
|
||||
|
||||
// IEnumerator members
|
||||
|
||||
public bool MoveNext() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Object Current {
|
||||
get {
|
||||
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumOpCantHappen"));
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset() {
|
||||
}
|
||||
|
||||
// IDictionaryEnumerator members
|
||||
|
||||
public Object Key {
|
||||
get {
|
||||
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumOpCantHappen"));
|
||||
}
|
||||
}
|
||||
|
||||
public Object Value {
|
||||
get {
|
||||
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumOpCantHappen"));
|
||||
}
|
||||
}
|
||||
|
||||
public DictionaryEntry Entry {
|
||||
get {
|
||||
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumOpCantHappen"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,177 @@
|
||||
// ==++==
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// ==--==
|
||||
// <OWNER>[....]</OWNER>
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Contracts;
|
||||
//using System.Globalization;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
[Serializable]
|
||||
[TypeDependencyAttribute("System.Collections.Generic.ObjectComparer`1")]
|
||||
public abstract class Comparer<T> : IComparer, IComparer<T>
|
||||
{
|
||||
static volatile Comparer<T> defaultComparer;
|
||||
|
||||
public static Comparer<T> Default {
|
||||
get {
|
||||
Contract.Ensures(Contract.Result<Comparer<T>>() != null);
|
||||
|
||||
Comparer<T> comparer = defaultComparer;
|
||||
if (comparer == null) {
|
||||
comparer = CreateComparer();
|
||||
defaultComparer = comparer;
|
||||
}
|
||||
return comparer;
|
||||
}
|
||||
}
|
||||
|
||||
public static Comparer<T> Create(Comparison<T> comparison)
|
||||
{
|
||||
Contract.Ensures(Contract.Result<Comparer<T>>() != null);
|
||||
|
||||
if (comparison == null)
|
||||
throw new ArgumentNullException("comparison");
|
||||
|
||||
return new ComparisonComparer<T>(comparison);
|
||||
}
|
||||
|
||||
//
|
||||
// Note that logic in this method is replicated in vm\compile.cpp to ensure that NGen
|
||||
// saves the right instantiations
|
||||
//
|
||||
[System.Security.SecuritySafeCritical] // auto-generated
|
||||
private static Comparer<T> CreateComparer() {
|
||||
RuntimeType t = (RuntimeType)typeof(T);
|
||||
|
||||
// If T implements IComparable<T> return a GenericComparer<T>
|
||||
#if FEATURE_LEGACYNETCF
|
||||
// Pre-Apollo Windows Phone call the overload that sorts the keys, not values this achieves the same result
|
||||
if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) {
|
||||
if (t.ImplementInterface(typeof(IComparable<T>))) {
|
||||
return (Comparer<T>)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(GenericComparer<int>), t);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (typeof(IComparable<T>).IsAssignableFrom(t)) {
|
||||
#if MONO
|
||||
return (Comparer<T>)RuntimeType.CreateInstanceForAnotherGenericParameter (typeof(GenericComparer<>), t);
|
||||
#else
|
||||
return (Comparer<T>)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(GenericComparer<int>), t);
|
||||
#endif
|
||||
}
|
||||
|
||||
// If T is a Nullable<U> where U implements IComparable<U> return a NullableComparer<U>
|
||||
if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>)) {
|
||||
RuntimeType u = (RuntimeType)t.GetGenericArguments()[0];
|
||||
if (typeof(IComparable<>).MakeGenericType(u).IsAssignableFrom(u)) {
|
||||
#if MONO
|
||||
return (Comparer<T>)RuntimeType.CreateInstanceForAnotherGenericParameter (typeof(NullableComparer<>), u);
|
||||
#else
|
||||
return (Comparer<T>)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(NullableComparer<int>), u);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
// Otherwise return an ObjectComparer<T>
|
||||
return new ObjectComparer<T>();
|
||||
}
|
||||
|
||||
public abstract int Compare(T x, T y);
|
||||
|
||||
int IComparer.Compare(object x, object y) {
|
||||
if (x == null) return y == null ? 0 : -1;
|
||||
if (y == null) return 1;
|
||||
if (x is T && y is T) return Compare((T)x, (T)y);
|
||||
ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArgumentForComparison);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal class GenericComparer<T> : Comparer<T> where T: IComparable<T>
|
||||
{
|
||||
public override int Compare(T x, T y) {
|
||||
if (x != null) {
|
||||
if (y != null) return x.CompareTo(y);
|
||||
return 1;
|
||||
}
|
||||
if (y != null) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Equals method for the comparer itself.
|
||||
public override bool Equals(Object obj){
|
||||
GenericComparer<T> comparer = obj as GenericComparer<T>;
|
||||
return comparer != null;
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
return this.GetType().Name.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal class NullableComparer<T> : Comparer<Nullable<T>> where T : struct, IComparable<T>
|
||||
{
|
||||
public override int Compare(Nullable<T> x, Nullable<T> y) {
|
||||
if (x.HasValue) {
|
||||
if (y.HasValue) return x.value.CompareTo(y.value);
|
||||
return 1;
|
||||
}
|
||||
if (y.HasValue) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Equals method for the comparer itself.
|
||||
public override bool Equals(Object obj){
|
||||
NullableComparer<T> comparer = obj as NullableComparer<T>;
|
||||
return comparer != null;
|
||||
}
|
||||
|
||||
|
||||
public override int GetHashCode() {
|
||||
return this.GetType().Name.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal class ObjectComparer<T> : Comparer<T>
|
||||
{
|
||||
public override int Compare(T x, T y) {
|
||||
return System.Collections.Comparer.Default.Compare(x, y);
|
||||
}
|
||||
|
||||
// Equals method for the comparer itself.
|
||||
public override bool Equals(Object obj){
|
||||
ObjectComparer<T> comparer = obj as ObjectComparer<T>;
|
||||
return comparer != null;
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
return this.GetType().Name.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal class ComparisonComparer<T> : Comparer<T>
|
||||
{
|
||||
private readonly Comparison<T> _comparison;
|
||||
|
||||
public ComparisonComparer(Comparison<T> comparison) {
|
||||
_comparison = comparison;
|
||||
}
|
||||
|
||||
public override int Compare(T x, T y) {
|
||||
return _comparison(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user