Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Baulig <martin@novell.com>2006-02-16 17:00:18 +0300
committerMartin Baulig <martin@novell.com>2006-02-16 17:00:18 +0300
commit5236d7998dc0a814bf81402c22707da2dadc4781 (patch)
tree6b26bfd96322db808ffe57b2a58f043179624b4f /mcs/class/Mono.C5
parenta4e2db9bc89d8d69859b174e83b707af8fa13d86 (diff)
Bringing C5 1.0 into the main branch.
svn path=/trunk/mcs/; revision=56931
Diffstat (limited to 'mcs/class/Mono.C5')
-rw-r--r--mcs/class/Mono.C5/C5/AssemblyInfo.cs79
-rw-r--r--mcs/class/Mono.C5/C5/Attributes.cs48
-rw-r--r--mcs/class/Mono.C5/C5/Builtin.cs186
-rw-r--r--mcs/class/Mono.C5/C5/C5.csproj128
-rw-r--r--mcs/class/Mono.C5/C5/ClsdiagWork.pngbin0 -> 17212 bytes
-rw-r--r--mcs/class/Mono.C5/C5/Collections.cs1520
-rw-r--r--mcs/class/Mono.C5/C5/Comparer.cs152
-rw-r--r--mcs/class/Mono.C5/C5/Delegates.cs131
-rw-r--r--mcs/class/Mono.C5/C5/Dictionaries.cs1295
-rw-r--r--mcs/class/Mono.C5/C5/Enums.cs98
-rw-r--r--mcs/class/Mono.C5/C5/Events.cs532
-rw-r--r--mcs/class/Mono.C5/C5/Exceptions.cs244
-rw-r--r--mcs/class/Mono.C5/C5/Formatting.cs247
-rw-r--r--mcs/class/Mono.C5/C5/Hashers.cs489
-rw-r--r--mcs/class/Mono.C5/C5/Interfaces.cs1884
-rw-r--r--mcs/class/Mono.C5/C5/MappedEnumerators.cs145
-rw-r--r--mcs/class/Mono.C5/C5/Random.cs172
-rw-r--r--mcs/class/Mono.C5/C5/Records.cs510
-rw-r--r--mcs/class/Mono.C5/C5/Sorting.cs239
-rw-r--r--mcs/class/Mono.C5/C5/ViewSupport.cs101
-rw-r--r--mcs/class/Mono.C5/C5/WrappedArray.cs871
-rw-r--r--mcs/class/Mono.C5/C5/Wrappers.cs2233
-rw-r--r--mcs/class/Mono.C5/C5/arrays/ArrayList.cs2536
-rw-r--r--mcs/class/Mono.C5/C5/arrays/CircularQueue.cs334
-rw-r--r--mcs/class/Mono.C5/C5/arrays/SortedArray.cs1266
-rw-r--r--mcs/class/Mono.C5/C5/hashing/HashBag.cs678
-rw-r--r--mcs/class/Mono.C5/C5/hashing/HashDictionary.cs77
-rw-r--r--mcs/class/Mono.C5/C5/hashing/HashTable.cs1600
-rw-r--r--mcs/class/Mono.C5/C5/heaps/IntervalHeap.cs1100
-rw-r--r--mcs/class/Mono.C5/C5/linkedlists/LinkedList.cs3782
-rw-r--r--mcs/class/Mono.C5/C5/trees/.cvsignore1
-rw-r--r--mcs/class/Mono.C5/C5/trees/RedBlackTreeDictionary.cs80
-rw-r--r--mcs/class/Mono.C5/C5/trees/RedBlackTreeSet.cs4490
33 files changed, 27248 insertions, 0 deletions
diff --git a/mcs/class/Mono.C5/C5/AssemblyInfo.cs b/mcs/class/Mono.C5/C5/AssemblyInfo.cs
new file mode 100644
index 00000000000..a649742b511
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/AssemblyInfo.cs
@@ -0,0 +1,79 @@
+/*
+ Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+//
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+//
+[assembly: AssemblyTitle("C5: Copenhagen Comprehensive Collection Classes for CLI")]
+[assembly: AssemblyDescription("This is a debug build of release 1.0.0")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("(c) 2003-2006 Niels Kokholm and Peter Sestoft")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+//
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+
+[assembly: AssemblyVersion("1.0.0")]
+
+//
+// In order to sign your assembly you must specify a key to use. Refer to the
+// Microsoft .NET Framework documentation for more information on assembly signing.
+//
+// Use the attributes below to control which key is used for signing.
+//
+// Notes:
+// (*) If no key is specified, the assembly is not signed.
+// (*) KeyName refers to a key that has been installed in the Crypto Service
+// Provider (CSP) on your machine. KeyFile refers to a file which contains
+// a key.
+// (*) If the KeyFile and the KeyName values are both specified, the
+// following processing occurs:
+// (1) If the KeyName can be found in the CSP, that key is used.
+// (2) If the KeyName does not exist and the KeyFile does exist, the key
+// in the KeyFile is installed into the CSP and used.
+// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
+// When specifying the KeyFile, the location of the KeyFile should be
+// relative to the project output directory which is
+// %Project Directory%\obj\<configuration>. For example, if your KeyFile is
+// located in the project directory, you would specify the AssemblyKeyFile
+// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
+// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
+// documentation for more information on this.
+//
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("..\\..\\..\\c5.snk")]
+//[assembly: AssemblyKeyName("")]
diff --git a/mcs/class/Mono.C5/C5/Attributes.cs b/mcs/class/Mono.C5/C5/Attributes.cs
new file mode 100644
index 00000000000..9302996aa0d
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/Attributes.cs
@@ -0,0 +1,48 @@
+/*
+ Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+using System;
+using System.Diagnostics;
+using SCG = System.Collections.Generic;
+namespace C5
+{
+ /// <summary>
+ /// A custom attribute to mark methods and properties as being tested
+ /// sufficiently in the regression test suite.
+ /// </summary>
+ [AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
+ public class TestedAttribute : Attribute
+ {
+
+ /// <summary>
+ /// Optional reference to test case
+ /// </summary>
+ [Tested]
+ public string via;
+
+
+ /// <summary>
+ /// Pretty print attribute value
+ /// </summary>
+ /// <returns>"Tested via " + via</returns>
+ [Tested]
+ public override string ToString() { return "Tested via " + via; }
+ }
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/C5/Builtin.cs b/mcs/class/Mono.C5/C5/Builtin.cs
new file mode 100644
index 00000000000..3b6a4b017f4
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/Builtin.cs
@@ -0,0 +1,186 @@
+/*
+ Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+using System;
+using System.Diagnostics;
+using SCG = System.Collections.Generic;
+namespace C5
+{
+ #region int stuff
+ [Serializable]
+ class IntComparer : SCG.IComparer<int>
+ {
+ [Tested]
+ public int Compare(int a, int b) { return a > b ? 1 : a < b ? -1 : 0; }
+ }
+
+ /// <summary>
+ /// An equalityComparer for System.Int32 integers.
+ /// <para>This class is a singleton and the instance can be accessed
+ /// via the static <see cref="P:C5.IntEqualityComparer.Default"/> property</para>
+ /// </summary>
+ [Serializable]
+ public class IntEqualityComparer : SCG.IEqualityComparer<int>
+ {
+ static IntEqualityComparer cached;
+ IntEqualityComparer() { }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ [Tested]
+ public static IntEqualityComparer Default { get { return cached ?? (cached = new IntEqualityComparer()); } }
+ /// <summary>
+ /// Get the hash code of this integer, that is, itself
+ /// </summary>
+ /// <param name="item">The integer</param>
+ /// <returns>The same</returns>
+ [Tested]
+ public int GetHashCode(int item) { return item; }
+
+
+ /// <summary>
+ /// Determine whether two integers are equal
+ /// </summary>
+ /// <param name="int1">first integer</param>
+ /// <param name="int2">second integer</param>
+ /// <returns>True if equal</returns>
+ [Tested]
+ public bool Equals(int int1, int int2) { return int1 == int2; }
+ }
+
+ #endregion
+
+ #region double stuff
+ class DoubleComparer : SCG.IComparer<double>
+ {
+ public int Compare(double a, double b) { return a > b ? 1 : a < b ? -1 : 0; }
+ }
+
+ /// <summary>
+ /// An equalityComparer for double.
+ /// <para>This class is a singleton and the instance can be accessed
+ /// via the static <see cref="P:C5.DoubleEqualityComparer.Default"/> property</para>
+ /// </summary>
+ public class DoubleEqualityComparer : SCG.IEqualityComparer<double>
+ {
+ static DoubleEqualityComparer cached;
+ DoubleEqualityComparer() { }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ [Tested]
+ public static DoubleEqualityComparer Default { get { return cached ?? (cached = new DoubleEqualityComparer()); } }
+ /// <summary>
+ /// Get the hash code of this double,
+ /// </summary>
+ /// <param name="item">The double</param>
+ /// <returns>The same</returns>
+ [Tested]
+ public int GetHashCode(double item) { return item.GetHashCode(); }
+
+
+ /// <summary>
+ /// Check if two doubles are equal
+ /// </summary>
+ /// <param name="item1">first double</param>
+ /// <param name="item2">second double</param>
+ /// <returns>True if equal</returns>
+ [Tested]
+ public bool Equals(double item1, double item2) { return item1 == item2; }
+ }
+ #endregion
+
+ #region byte stuff
+ class ByteComparer : SCG.IComparer<byte>
+ {
+ public int Compare(byte a, byte b) { return a > b ? 1 : a < b ? -1 : 0; }
+ }
+
+ /// <summary>
+ /// An equalityComparer for byte
+ /// <para>This class is a singleton and the instance can be accessed
+ /// via the <see cref="P:C5.ByteEqualityComparer.Default"/> property</para>
+ /// </summary>
+ public class ByteEqualityComparer : SCG.IEqualityComparer<byte>
+ {
+ static ByteEqualityComparer cached = new ByteEqualityComparer();
+ ByteEqualityComparer() { }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public static ByteEqualityComparer Default { get { return cached ?? (cached = new ByteEqualityComparer()); } }
+ /// <summary>
+ /// Get the hash code of this byte, i.e. itself
+ /// </summary>
+ /// <param name="item">The byte</param>
+ /// <returns>The same</returns>
+ public int GetHashCode(byte item) { return item; }
+
+ /// <summary>
+ /// Check if two bytes are equal
+ /// </summary>
+ /// <param name="item1">first byte</param>
+ /// <param name="item2">second byte</param>
+ /// <returns>True if equal</returns>
+ public bool Equals(byte item1, byte item2) { return item1 == item2; }
+ }
+ #endregion
+
+ #region char stuff
+ class CharComparer : SCG.IComparer<char>
+ {
+ public int Compare(char a, char b) { return a > b ? 1 : a < b ? -1 : 0; }
+ }
+
+ /// <summary>
+ /// An equalityComparer for char.
+ /// </summary>
+ public class CharEqualityComparer : SCG.IEqualityComparer<char>
+ {
+ static CharEqualityComparer cached = new CharEqualityComparer();
+ CharEqualityComparer() { }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public static CharEqualityComparer Default { get { return cached ?? (cached = new CharEqualityComparer()); } }
+
+ /// <summary>
+ /// Get the hash code of this char
+ /// </summary>
+ /// <param name="item">The char</param>
+ /// <returns>The same</returns>
+ public int GetHashCode(char item) { return item.GetHashCode(); }
+
+
+ /// <summary>
+ /// Check if two chars are equal
+ /// </summary>
+ /// <param name="item1">first char</param>
+ /// <param name="item2">second char</param>
+ /// <returns>True if equal</returns>
+ public bool Equals(char item1, char item2) { return item1 == item2; }
+ }
+ #endregion
+
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/C5/C5.csproj b/mcs/class/Mono.C5/C5/C5.csproj
new file mode 100644
index 00000000000..eb0c5b0ebdc
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/C5.csproj
@@ -0,0 +1,128 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <ProductVersion>8.0.40607</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{D70489CD-ABDA-48FF-BD1E-BE3F7495BE71}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <StartupObject>
+ </StartupObject>
+ <RootNamespace>C5</RootNamespace>
+ <NoStandardLibraries>false</NoStandardLibraries>
+ <AssemblyName>C5</AssemblyName>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
+ <DebugSymbols>true</DebugSymbols>
+ <Optimize>false</Optimize>
+ <OutputPath>.\bin\Debug\</OutputPath>
+ <EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
+ <DefineConstants>DEBUG</DefineConstants>
+ <WarningLevel>4</WarningLevel>
+ <IncrementalBuild>false</IncrementalBuild>
+ <DocumentationFile>c5.xml</DocumentationFile>
+ <FxCopRules>+ComRules.dll;+DesignRules.dll|AbstractTypesShouldNotHaveConstructors;+DesignRules.dll|AddAndSubtractOverrideShouldHaveOperatorEqualsOverride;-DesignRules.dll|AssembliesAreMarkedClsCompliant;-DesignRules.dll|AssembliesHaveStrongNames;+DesignRules.dll|AssembliesHaveVersionNumbers;-DesignRules.dll|AssembliesShouldBeComVisibleAttributed;+DesignRules.dll|AttributesAreAttributeUsageAttributed;+DesignRules.dll|AttributesShouldHaveAccessorsForAllArguments;+DesignRules.dll|AvoidNamespacesWithFewMembers;-DesignRules.dll|AvoidOutParameters;+DesignRules.dll|AvoidValueTypesPassedAsByRefParameters;+DesignRules.dll|ConsiderHavingOnlyOneDimensionForIndexer;+DesignRules.dll|ConsiderPassingBaseTypesAsParameters;+DesignRules.dll|ConsiderReplacingMethodsWithProperties;+DesignRules.dll|ConsiderReplacingRepetitiveArgsWithParameterArray;+DesignRules.dll|DefaultParametersAreNotUsed;+DesignRules.dll|EnumerationsShouldBeFlagsAttributed;+DesignRules.dll|EnumerationsShouldBeInt32;+DesignRules.dll|EnumerationsShouldBeIntegralType;+DesignRules.dll|EventFirstParametersAreTypeObject;+DesignRules.dll|EventHandlersReturnVoid;+DesignRules.dll|EventSecondParametersAreEventArgsType;+DesignRules.dll|EventsHaveTwoParameters;+DesignRules.dll|EventsShouldBeUsed;+DesignRules.dll|ExceptionAndSystemExceptionTypesAreNotCaught;+DesignRules.dll|ExceptionsRequireMultipleConstructors;-DesignRules.dll|ExplicitMethodImplementationsInUnsealedClassesHaveVisibleAlternates;+DesignRules.dll|ExternallyVisibleNestedTypesShouldNotBeUsed;+DesignRules.dll|ICollectionImplementationsHaveStronglyTypedMembers;+DesignRules.dll|IComparableImplementationsOverrideEquals;+DesignRules.dll|IComparableImplementationsOverrideOperators;+DesignRules.dll|IEnumeratorImplementationsHaveStronglyTypedMembers;+DesignRules.dll|IListImplementationsHaveStronglyTypedMembers;+DesignRules.dll|InterfacesShouldNotBeEmpty;+DesignRules.dll|ISerializableTypesAreMarkedSerializable;+DesignRules.dll|ObsoleteAttributeOnMemberShouldProvideMessage;+DesignRules.dll|ObsoleteAttributeOnTypeShouldProvideMessage;-DesignRules.dll|OnlyIntegralValuesOrStringsShouldBeUsedForIndexers;+DesignRules.dll|PropertiesShouldNotBeWriteOnly;+DesignRules.dll|ReferenceTypesAreNotPassedAsByRefParameters;+DesignRules.dll|ReferenceTypesShouldNotOverrideOperatorEquals;+DesignRules.dll|SealedTypesDoNotDeclareProtectedMembers;+DesignRules.dll|SealedTypesDoNotDeclareVirtualMembers;+DesignRules.dll|TypesAllocatingUnmanagedResourcesImplementIDisposable;+DesignRules.dll|TypesBelongToNamespaces;+DesignRules.dll|TypesDoNotHavePublicInstanceFields;+DesignRules.dll|TypesHavingOnlyStaticMembersShouldBeSealed;+DesignRules.dll|TypesHavingOnlyStaticMembersShouldNotHaveConstructors;+DesignRules.dll|UriParametersShouldNotBeStrings;+DesignRules.dll|UriPropertiesShouldNotBeStrings;+DesignRules.dll|UriReturnValuesShouldNotBeStrings;+GlobalizationRules.dll;+MaintainabilityRules.dll;+NamingRules.dll;+PerformanceRules.dll;+ReliabilityRules.dll;+SecurityRules.dll;+UsageRules.dll</FxCopRules>
+ <RunFxCop>false</RunFxCop>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
+ <DebugSymbols>false</DebugSymbols>
+ <Optimize>true</Optimize>
+ <OutputPath>.\bin\Release\</OutputPath>
+ <EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
+ <DefineConstants>TRACE</DefineConstants>
+ <WarningLevel>4</WarningLevel>
+ <IncrementalBuild>false</IncrementalBuild>
+ <DocumentationFile>
+ </DocumentationFile>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System">
+ <HintPath>..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.2.30703\System.dll</HintPath>
+ <Name>System</Name>
+ </Reference>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="arrays\CircularQueue.cs" />
+ <Compile Include="arrays\HashedArrayList.cs" />
+ <Compile Include="AssemblyInfo.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="Attributes.cs" />
+ <Compile Include="Builtin.cs" />
+ <Compile Include="Comparer.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="Delegates.cs" />
+ <Compile Include="Enums.cs" />
+ <Compile Include="Exceptions.cs" />
+ <Compile Include="Formatting.cs" />
+ <Compile Include="Hashers.cs" />
+ <Compile Include="Events.cs" />
+ <Compile Include="Collections.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="Dictionaries.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="Interfaces.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="linkedlists\HashedLinkedList.cs" />
+ <Compile Include="Random.cs" />
+ <Compile Include="Records.cs" />
+ <Compile Include="Sorting.cs" />
+ <Compile Include="ViewSupport.cs" />
+ <Compile Include="MappedEnumerators.cs" />
+ <Compile Include="WrappedArray.cs" />
+ <Compile Include="Wrappers.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="arrays\ArrayList.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="arrays\SortedArray.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="hashing\HashBag.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="hashing\HashDictionary.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="hashing\HashTable.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="heaps\IntervalHeap.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="linkedlists\LinkedList.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="trees\RedBlackTreeSet.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="trees\RedBlackTreeBag.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="trees\RedBlackTreeDictionary.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ </ItemGroup>
+ <ItemGroup>
+ <AppDesigner Include="Properties\" />
+ </ItemGroup>
+ <ItemGroup>
+ <Folder Include="Properties\" />
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSHARP.Targets" />
+ <PropertyGroup>
+ <PreBuildEvent>"$(SolutionDir)PreProcess\$(OutDir)PreProcess.exe"</PreBuildEvent>
+ <PostBuildEvent>
+ </PostBuildEvent>
+ </PropertyGroup>
+ <ProjectExtensions>
+ <VisualStudio>
+ </VisualStudio>
+ </ProjectExtensions>
+</Project> \ No newline at end of file
diff --git a/mcs/class/Mono.C5/C5/ClsdiagWork.png b/mcs/class/Mono.C5/C5/ClsdiagWork.png
new file mode 100644
index 00000000000..9a1866653a8
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/ClsdiagWork.png
Binary files differ
diff --git a/mcs/class/Mono.C5/C5/Collections.cs b/mcs/class/Mono.C5/C5/Collections.cs
new file mode 100644
index 00000000000..98acf96dd5a
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/Collections.cs
@@ -0,0 +1,1520 @@
+/*
+ Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+#define IMPROVED_COLLECTION_HASHFUNCTION
+
+using System;
+using System.Diagnostics;
+using SCG = System.Collections.Generic;
+namespace C5
+{
+ /// <summary>
+ /// A base class for implementing an IEnumerable&lt;T&gt;
+ /// </summary>
+ [Serializable]
+ public abstract class EnumerableBase<T> : SCG.IEnumerable<T>
+ {
+ /// <summary>
+ /// Create an enumerator for this collection.
+ /// </summary>
+ /// <returns>The enumerator</returns>
+ public abstract SCG.IEnumerator<T> GetEnumerator();
+
+ /// <summary>
+ /// Count the number of items in an enumerable by enumeration
+ /// </summary>
+ /// <param name="items">The enumerable to count</param>
+ /// <returns>The size of the enumerable</returns>
+ [Tested]
+ protected static int countItems(SCG.IEnumerable<T> items)
+ {
+ ICollectionValue<T> jtems = items as ICollectionValue<T>;
+
+ if (jtems != null)
+ return jtems.Count;
+
+ int count = 0;
+
+ using (SCG.IEnumerator<T> e = items.GetEnumerator())
+ while (e.MoveNext()) count++;
+
+ return count;
+ }
+
+ #region IEnumerable Members
+
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ #endregion
+ }
+
+
+ /// <summary>
+ /// Base class for classes implementing ICollectionValue[T]
+ /// </summary>
+ [Serializable]
+ public abstract class CollectionValueBase<T> : EnumerableBase<T>, ICollectionValue<T>, IShowable
+ {
+ #region Event handling
+ EventBlock<T> eventBlock;
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public virtual EventTypeEnum ListenableEvents { get { return 0; } }
+
+ /// <summary>
+ /// A flag bitmap of the events currently subscribed to by this collection.
+ /// </summary>
+ /// <value></value>
+ public virtual EventTypeEnum ActiveEvents { get { return eventBlock == null ? 0 : eventBlock.events; } }
+
+ private void checkWillListen(EventTypeEnum eventType)
+ {
+ if ((ListenableEvents & eventType) == 0)
+ throw new UnlistenableEventException();
+ }
+
+ /// <summary>
+ /// The change event. Will be raised for every change operation on the collection.
+ /// </summary>
+ public virtual event CollectionChangedHandler<T> CollectionChanged
+ {
+ add { checkWillListen(EventTypeEnum.Changed); (eventBlock ?? (eventBlock = new EventBlock<T>())).CollectionChanged += value; }
+ remove
+ {
+ checkWillListen(EventTypeEnum.Changed);
+ if (eventBlock != null)
+ {
+ eventBlock.CollectionChanged -= value;
+ if (eventBlock.events == 0) eventBlock = null;
+ }
+ }
+ }
+ /// <summary>
+ /// Fire the CollectionChanged event
+ /// </summary>
+ protected virtual void raiseCollectionChanged()
+ { if (eventBlock != null) eventBlock.raiseCollectionChanged(this); }
+
+ /// <summary>
+ /// The clear event. Will be raised for every Clear operation on the collection.
+ /// </summary>
+ public virtual event CollectionClearedHandler<T> CollectionCleared
+ {
+ add { checkWillListen(EventTypeEnum.Cleared); (eventBlock ?? (eventBlock = new EventBlock<T>())).CollectionCleared += value; }
+ remove
+ {
+ checkWillListen(EventTypeEnum.Cleared);
+ if (eventBlock != null)
+ {
+ eventBlock.CollectionCleared -= value;
+ if (eventBlock.events == 0) eventBlock = null;
+ }
+ }
+ }
+ /// <summary>
+ /// Fire the CollectionCleared event
+ /// </summary>
+ protected virtual void raiseCollectionCleared(bool full, int count)
+ { if (eventBlock != null) eventBlock.raiseCollectionCleared(this, full, count); }
+
+ /// <summary>
+ /// Fire the CollectionCleared event
+ /// </summary>
+ protected virtual void raiseCollectionCleared(bool full, int count, int? offset)
+ { if (eventBlock != null) eventBlock.raiseCollectionCleared(this, full, count, offset); }
+
+ /// <summary>
+ /// The item added event. Will be raised for every individual addition to the collection.
+ /// </summary>
+ public virtual event ItemsAddedHandler<T> ItemsAdded
+ {
+ add { checkWillListen(EventTypeEnum.Added); (eventBlock ?? (eventBlock = new EventBlock<T>())).ItemsAdded += value; }
+ remove
+ {
+ checkWillListen(EventTypeEnum.Added);
+ if (eventBlock != null)
+ {
+ eventBlock.ItemsAdded -= value;
+ if (eventBlock.events == 0) eventBlock = null;
+ }
+ }
+ }
+ /// <summary>
+ /// Fire the ItemsAdded event
+ /// </summary>
+ /// <param name="item">The item that was added</param>
+ /// <param name="count"></param>
+ protected virtual void raiseItemsAdded(T item, int count)
+ { if (eventBlock != null) eventBlock.raiseItemsAdded(this, item, count); }
+
+ /// <summary>
+ /// The item removed event. Will be raised for every individual removal from the collection.
+ /// </summary>
+ public virtual event ItemsRemovedHandler<T> ItemsRemoved
+ {
+ add { checkWillListen(EventTypeEnum.Removed); (eventBlock ?? (eventBlock = new EventBlock<T>())).ItemsRemoved += value; }
+ remove
+ {
+ checkWillListen(EventTypeEnum.Removed);
+ if (eventBlock != null)
+ {
+ eventBlock.ItemsRemoved -= value;
+ if (eventBlock.events == 0) eventBlock = null;
+ }
+ }
+ }
+ /// <summary>
+ /// Fire the ItemsRemoved event
+ /// </summary>
+ /// <param name="item">The item that was removed</param>
+ /// <param name="count"></param>
+ protected virtual void raiseItemsRemoved(T item, int count)
+ { if (eventBlock != null) eventBlock.raiseItemsRemoved(this, item, count); }
+
+ /// <summary>
+ /// The item added event. Will be raised for every individual addition to the collection.
+ /// </summary>
+ public virtual event ItemInsertedHandler<T> ItemInserted
+ {
+ add { checkWillListen(EventTypeEnum.Inserted); (eventBlock ?? (eventBlock = new EventBlock<T>())).ItemInserted += value; }
+ remove
+ {
+ checkWillListen(EventTypeEnum.Inserted);
+ if (eventBlock != null)
+ {
+ eventBlock.ItemInserted -= value;
+ if (eventBlock.events == 0) eventBlock = null;
+ }
+ }
+ }
+ /// <summary>
+ /// Fire the ItemInserted event
+ /// </summary>
+ /// <param name="item">The item that was added</param>
+ /// <param name="index"></param>
+ protected virtual void raiseItemInserted(T item, int index)
+ { if (eventBlock != null) eventBlock.raiseItemInserted(this, item, index); }
+
+ /// <summary>
+ /// The item removed event. Will be raised for every individual removal from the collection.
+ /// </summary>
+ public virtual event ItemRemovedAtHandler<T> ItemRemovedAt
+ {
+ add { checkWillListen(EventTypeEnum.RemovedAt); (eventBlock ?? (eventBlock = new EventBlock<T>())).ItemRemovedAt += value; }
+ remove
+ {
+ checkWillListen(EventTypeEnum.RemovedAt);
+ if (eventBlock != null)
+ {
+ eventBlock.ItemRemovedAt -= value;
+ if (eventBlock.events == 0) eventBlock = null;
+ }
+ }
+ }
+ /// <summary>
+ /// Fire the ItemRemovedAt event
+ /// </summary>
+ /// <param name="item">The item that was removed</param>
+ /// <param name="index"></param>
+ protected virtual void raiseItemRemovedAt(T item, int index)
+ { if (eventBlock != null) eventBlock.raiseItemRemovedAt(this, item, index); }
+
+ #region Event support for IList
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="index"></param>
+ /// <param name="value"></param>
+ /// <param name="item"></param>
+ protected virtual void raiseForSetThis(int index, T value, T item)
+ {
+ if (ActiveEvents != 0)
+ {
+ raiseItemsRemoved(item, 1);
+ raiseItemRemovedAt(item, index);
+ raiseItemsAdded(value, 1);
+ raiseItemInserted(value, index);
+ raiseCollectionChanged();
+ }
+ }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="i"></param>
+ /// <param name="item"></param>
+ protected virtual void raiseForInsert(int i, T item)
+ {
+ if (ActiveEvents != 0)
+ {
+ raiseItemInserted(item, i);
+ raiseItemsAdded(item, 1);
+ raiseCollectionChanged();
+ }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ protected void raiseForRemove(T item)
+ {
+ if (ActiveEvents != 0)
+ {
+ raiseItemsRemoved(item, 1);
+ raiseCollectionChanged();
+ }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ /// <param name="count"></param>
+ protected void raiseForRemove(T item, int count)
+ {
+ if (ActiveEvents != 0)
+ {
+ raiseItemsRemoved(item, count);
+ raiseCollectionChanged();
+ }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="index"></param>
+ /// <param name="item"></param>
+ protected void raiseForRemoveAt(int index, T item)
+ {
+ if (ActiveEvents != 0)
+ {
+ raiseItemRemovedAt(item, index);
+ raiseItemsRemoved(item, 1);
+ raiseCollectionChanged();
+ }
+ }
+
+ #endregion
+
+ #region Event Support for ICollection
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="newitem"></param>
+ /// <param name="olditem"></param>
+ protected virtual void raiseForUpdate(T newitem, T olditem)
+ {
+ if (ActiveEvents != 0)
+ {
+ raiseItemsRemoved(olditem, 1);
+ raiseItemsAdded(newitem, 1);
+ raiseCollectionChanged();
+ }
+ }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="newitem"></param>
+ /// <param name="olditem"></param>
+ /// <param name="count"></param>
+ protected virtual void raiseForUpdate(T newitem, T olditem, int count)
+ {
+ if (ActiveEvents != 0)
+ {
+ raiseItemsRemoved(olditem, count);
+ raiseItemsAdded(newitem, count);
+ raiseCollectionChanged();
+ }
+ }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ protected virtual void raiseForAdd(T item)
+ {
+ if (ActiveEvents != 0)
+ {
+ raiseItemsAdded(item, 1);
+ raiseCollectionChanged();
+ }
+ }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="wasRemoved"></param>
+ protected virtual void raiseForRemoveAll(ICollectionValue<T> wasRemoved)
+ {
+ if ((ActiveEvents & EventTypeEnum.Removed) != 0)
+ foreach (T item in wasRemoved)
+ raiseItemsRemoved(item, 1);
+ if (wasRemoved != null && wasRemoved.Count > 0)
+ raiseCollectionChanged();
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ protected class RaiseForRemoveAllHandler
+ {
+ CollectionValueBase<T> collection;
+ CircularQueue<T> wasRemoved;
+ bool wasChanged = false;
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="collection"></param>
+ public RaiseForRemoveAllHandler(CollectionValueBase<T> collection)
+ {
+ this.collection = collection;
+ mustFireRemoved = (collection.ActiveEvents & EventTypeEnum.Removed) != 0;
+ MustFire = (collection.ActiveEvents & (EventTypeEnum.Removed | EventTypeEnum.Changed)) != 0;
+ }
+
+ bool mustFireRemoved;
+ /// <summary>
+ ///
+ /// </summary>
+ public readonly bool MustFire;
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ public void Remove(T item)
+ {
+ if (mustFireRemoved)
+ {
+ if (wasRemoved == null)
+ wasRemoved = new CircularQueue<T>();
+ wasRemoved.Enqueue(item);
+ }
+ if (!wasChanged)
+ wasChanged = true;
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ public void Raise()
+ {
+ if (wasRemoved != null)
+ foreach (T item in wasRemoved)
+ collection.raiseItemsRemoved(item, 1);
+ if (wasChanged)
+ collection.raiseCollectionChanged();
+ }
+ }
+ #endregion
+
+ #endregion
+
+ /// <summary>
+ /// Check if collection is empty.
+ /// </summary>
+ /// <value>True if empty</value>
+ public abstract bool IsEmpty { get;}
+
+ /// <summary>
+ /// The number of items in this collection.
+ /// </summary>
+ /// <value></value>
+ public abstract int Count { get;}
+
+ /// <summary>
+ /// The value is symbolic indicating the type of asymptotic complexity
+ /// in terms of the size of this collection (worst-case or amortized as
+ /// relevant).
+ /// </summary>
+ /// <value>A characterization of the speed of the
+ /// <code>Count</code> property in this collection.</value>
+ public abstract Speed CountSpeed { get; }
+
+ /// <summary>
+ /// Copy the items of this collection to part of an array.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException"> if <code>index</code>
+ /// is not a valid index
+ /// into the array (i.e. negative or not less than the size of the array)
+ /// or the array does not have room for the items.</exception>
+ /// <param name="array">The array to copy to.</param>
+ /// <param name="index">The starting index.</param>
+ [Tested]
+ public virtual void CopyTo(T[] array, int index)
+ {
+#warning This code does not fit the doc comment and unit tests
+ if (index < 0 || index + Count > array.Length)
+ throw new ArgumentOutOfRangeException();
+
+ foreach (T item in this) array[index++] = item;
+ }
+
+ /// <summary>
+ /// Create an array with the items of this collection (in the same order as an
+ /// enumerator would output them).
+ /// </summary>
+ /// <returns>The array</returns>
+ //[Tested]
+ public virtual T[] ToArray()
+ {
+ T[] res = new T[Count];
+ int i = 0;
+
+ foreach (T item in this) res[i++] = item;
+
+ return res;
+ }
+
+ /// <summary>
+ /// Apply an single argument action, <see cref="T:C5.Act`1"/> to this enumerable
+ /// </summary>
+ /// <param name="action">The action delegate</param>
+ [Tested]
+ public virtual void Apply(Act<T> action)
+ {
+ foreach (T item in this)
+ action(item);
+ }
+
+
+ /// <summary>
+ /// Check if there exists an item that satisfies a
+ /// specific predicate in this collection.
+ /// </summary>
+ /// <param name="predicate">A delegate
+ /// (<see cref="T:C5.Fun`2"/> with <code>R = bool</code>)
+ /// defining the predicate</param>
+ /// <returns>True if such an item exists</returns>
+ [Tested]
+ public virtual bool Exists(Fun<T, bool> predicate)
+ {
+ foreach (T item in this)
+ if (predicate(item))
+ return true;
+
+ return false;
+ }
+
+ /// <summary>
+ /// Check if there exists an item that satisfies a
+ /// specific predicate in this collection and return the first one in enumeration order.
+ /// </summary>
+ /// <param name="predicate">A delegate
+ /// (<see cref="T:C5.Fun`2"/> with <code>R == bool</code>) defining the predicate</param>
+ /// <param name="item"></param>
+ /// <returns>True is such an item exists</returns>
+ public virtual bool Find(Fun<T, bool> predicate, out T item)
+ {
+ foreach (T jtem in this)
+ if (predicate(jtem))
+ {
+ item = jtem;
+ return true;
+ }
+ item = default(T);
+ return false;
+ }
+
+ /// <summary>
+ /// Check if all items in this collection satisfies a specific predicate.
+ /// </summary>
+ /// <param name="predicate">A delegate
+ /// (<see cref="T:C5.Fun`2"/> with <code>R = bool</code>)
+ /// defining the predicate</param>
+ /// <returns>True if all items satisfies the predicate</returns>
+ [Tested]
+ public virtual bool All(Fun<T, bool> predicate)
+ {
+ foreach (T item in this)
+ if (!predicate(item))
+ return false;
+
+ return true;
+ }
+
+ /// <summary>
+ /// Create an enumerable, enumerating the items of this collection that satisfies
+ /// a certain condition.
+ /// </summary>
+ /// <param name="predicate">A delegate
+ /// (<see cref="T:C5.Fun`2"/> with <code>R = bool</code>)
+ /// defining the predicate</param>
+ /// <returns>The filtered enumerable</returns>
+ public virtual SCG.IEnumerable<T> Filter(Fun<T, bool> predicate)
+ {
+ foreach (T item in this)
+ if (predicate(item))
+ yield return item;
+ }
+
+ /// <summary>
+ /// Choose some item of this collection.
+ /// </summary>
+ /// <exception cref="NoSuchItemException">if collection is empty.</exception>
+ /// <returns></returns>
+ public abstract T Choose();
+
+
+ /// <summary>
+ /// Create an enumerator for this collection.
+ /// </summary>
+ /// <returns>The enumerator</returns>
+ public override abstract SCG.IEnumerator<T> GetEnumerator();
+
+ #region IShowable Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="stringbuilder"></param>
+ /// <param name="rest"></param>
+ /// <param name="formatProvider"></param>
+ /// <returns></returns>
+ public virtual bool Show(System.Text.StringBuilder stringbuilder, ref int rest, IFormatProvider formatProvider)
+ {
+ return Showing.ShowCollectionValue<T>(this, stringbuilder, ref rest, formatProvider);
+ }
+ #endregion
+
+ #region IFormattable Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="format"></param>
+ /// <param name="formatProvider"></param>
+ /// <returns></returns>
+ public virtual string ToString(string format, IFormatProvider formatProvider)
+ {
+ return Showing.ShowString(this, format, formatProvider);
+ }
+
+ #endregion
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public override string ToString()
+ {
+ return ToString(null, null);
+ }
+
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ public abstract class DirectedCollectionValueBase<T> : CollectionValueBase<T>, IDirectedCollectionValue<T>
+ {
+ /// <summary>
+ /// <code>Forwards</code> if same, else <code>Backwards</code>
+ /// </summary>
+ /// <value>The enumeration direction relative to the original collection.</value>
+ public virtual EnumerationDirection Direction { [Tested]get { return EnumerationDirection.Forwards; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public abstract IDirectedCollectionValue<T> Backwards();
+
+ IDirectedEnumerable<T> IDirectedEnumerable<T>.Backwards() { return this.Backwards(); }
+
+ /// <summary>
+ /// Check if there exists an item that satisfies a
+ /// specific predicate in this collection and return the first one in enumeration order.
+ /// </summary>
+ /// <param name="predicate">A delegate
+ /// (<see cref="T:C5.Fun`2"/> with <code>R == bool</code>) defining the predicate</param>
+ /// <param name="item"></param>
+ /// <returns>True is such an item exists</returns>
+ public virtual bool FindLast(Fun<T, bool> predicate, out T item)
+ {
+ foreach (T jtem in Backwards())
+ if (predicate(jtem))
+ {
+ item = jtem;
+ return true;
+ }
+ item = default(T);
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Base class (abstract) for ICollection implementations.
+ /// </summary>
+ [Serializable]
+ public abstract class CollectionBase<T> : CollectionValueBase<T>
+ {
+ #region Fields
+
+ object syncroot = new object();
+
+ /// <summary>
+ /// The underlying field of the ReadOnly property
+ /// </summary>
+ protected bool isReadOnly = false;
+
+ /// <summary>
+ /// The current stamp value
+ /// </summary>
+ protected int stamp;
+
+ /// <summary>
+ /// The number of items in the collection
+ /// </summary>
+ protected int size;
+
+ /// <summary>
+ /// The item equalityComparer of the collection
+ /// </summary>
+ protected readonly SCG.IEqualityComparer<T> itemequalityComparer;
+
+ int iUnSequencedHashCode, iUnSequencedHashCodeStamp = -1;
+
+ #endregion
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="itemequalityComparer"></param>
+ public CollectionBase(SCG.IEqualityComparer<T> itemequalityComparer)
+ {
+ if (itemequalityComparer == null)
+ throw new NullReferenceException("Item EqualityComparer cannot be null.");
+ this.itemequalityComparer = itemequalityComparer;
+ }
+
+ #region Util
+
+ /// <summary>
+ /// Utility method for range checking.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException"> if the start or count is negative or
+ /// if the range does not fit within collection size.</exception>
+ /// <param name="start">start of range</param>
+ /// <param name="count">size of range</param>
+ [Tested]
+ protected void checkRange(int start, int count)
+ {
+ if (start < 0 || count < 0 || start + count > size)
+ throw new ArgumentOutOfRangeException();
+ }
+
+
+ /// <summary>
+ /// Compute the unsequenced hash code of a collection
+ /// </summary>
+ /// <param name="items">The collection to compute hash code for</param>
+ /// <param name="itemequalityComparer">The item equalityComparer</param>
+ /// <returns>The hash code</returns>
+ [Tested]
+ public static int ComputeHashCode(ICollectionValue<T> items, SCG.IEqualityComparer<T> itemequalityComparer)
+ {
+ int h = 0;
+
+#if IMPROVED_COLLECTION_HASHFUNCTION
+ //But still heuristic:
+ //Note: the three odd factors should really be random,
+ //but there will be a problem with serialization/deserialization!
+ //Two products is too few
+ foreach (T item in items)
+ {
+ uint h1 = (uint)itemequalityComparer.GetHashCode(item);
+
+ h += (int)((h1 * 1529784657 + 1) ^ (h1 * 2912831877) ^ (h1 * 1118771817 + 2));
+ }
+
+ return h;
+ /*
+ The pairs (-1657792980, -1570288808) and (1862883298, -272461342) gives the same
+ unsequenced hashcode with this hashfunction. The pair was found with code like
+
+ HashDictionary<int, int[]> set = new HashDictionary<int, int[]>();
+ Random rnd = new C5Random(12345);
+ while (true)
+ {
+ int[] a = new int[2];
+ a[0] = rnd.Next(); a[1] = rnd.Next();
+ int h = unsequencedhashcode(a);
+ int[] b = a;
+ if (set.FindOrAdd(h, ref b))
+ {
+ Console.WriteLine("Code {5}, Pair ({1},{2}) number {0} matched other pair ({3},{4})", set.Count, a[0], a[1], b[0], b[1], h);
+ }
+ }
+ */
+#else
+ foreach (T item in items)
+ h ^= itemequalityComparer.GetHashCode(item);
+
+ return (items.Count << 16) + h;
+#endif
+ }
+
+ static Type isortedtype = typeof(ISorted<T>);
+
+ /// <summary>
+ /// Examine if tit and tat are equal as unsequenced collections
+ /// using the specified item equalityComparer (assumed compatible with the two collections).
+ /// </summary>
+ /// <param name="collection1">The first collection</param>
+ /// <param name="collection2">The second collection</param>
+ /// <param name="itemequalityComparer">The item equalityComparer to use for comparison</param>
+ /// <returns>True if equal</returns>
+ [Tested]
+ public static bool StaticEquals(ICollection<T> collection1, ICollection<T> collection2, SCG.IEqualityComparer<T> itemequalityComparer)
+ {
+ if (object.ReferenceEquals(collection1, collection2))
+ return true;
+
+ if (collection1.Count != collection2.Count)
+ return false;
+
+ //This way we might run through both enumerations twice, but
+ //probably not (if the hash codes are good)
+ //TODO: cehck equal equalityComparers, at least here!
+ if (collection1.GetUnsequencedHashCode() != collection2.GetUnsequencedHashCode())
+ return false;
+
+ //TODO: move this to the sorted implementation classes?
+ //Really depends on speed of IntanceOfType: we could save a cast
+ {
+ ISorted<T> stit, stat;
+ if ((stit = collection1 as ISorted<T>) != null && (stat = collection2 as ISorted<T>) != null && stit.Comparer == stat.Comparer)
+ {
+ using (SCG.IEnumerator<T> dat = collection2.GetEnumerator(), dit = collection1.GetEnumerator())
+ {
+ while (dit.MoveNext())
+ {
+ dat.MoveNext();
+ if (!itemequalityComparer.Equals(dit.Current, dat.Current))
+ return false;
+ }
+ return true;
+ }
+ }
+ }
+
+ if (!collection1.AllowsDuplicates && (collection2.AllowsDuplicates || collection2.ContainsSpeed >= collection1.ContainsSpeed))
+ {
+ foreach (T x in collection1) if (!collection2.Contains(x)) return false;
+ }
+ else if (!collection2.AllowsDuplicates)
+ {
+ foreach (T x in collection2) if (!collection1.Contains(x)) return false;
+ }
+ // Now tit.AllowsDuplicates && tat.AllowsDuplicates
+ else if (collection1.DuplicatesByCounting && collection2.DuplicatesByCounting)
+ {
+ foreach (T item in collection2) if (collection1.ContainsCount(item) != collection2.ContainsCount(item)) return false;
+ }
+ else
+ {
+ //To avoid an O(n^2) algorithm, we make an aux hashtable to hold the count of items
+ HashDictionary<T, int> dict = new HashDictionary<T, int>();
+ foreach (T item in collection2)
+ {
+ int count = 1;
+ if (dict.FindOrAdd(item, ref count))
+ dict[item] = count + 1;
+ }
+ foreach (T item in collection1)
+ {
+ int count;
+ if (dict.Find(item, out count) && count > 0)
+ dict[item] = count - 1;
+ else
+ return false;
+ }
+ return true;
+ }
+
+ return true;
+ }
+
+
+ /// <summary>
+ /// Get the unsequenced collection hash code of this collection: from the cached
+ /// value if present and up to date, else (re)compute.
+ /// </summary>
+ /// <returns>The hash code</returns>
+ public virtual int GetUnsequencedHashCode()
+ {
+ if (iUnSequencedHashCodeStamp == stamp)
+ return iUnSequencedHashCode;
+
+ iUnSequencedHashCode = ComputeHashCode(this, itemequalityComparer);
+ iUnSequencedHashCodeStamp = stamp;
+ return iUnSequencedHashCode;
+ }
+
+
+ /// <summary>
+ /// Check if the contents of that is equal to the contents of this
+ /// in the unsequenced sense. Using the item equalityComparer of this collection.
+ /// Assuming that the item EqualityComparer is compatible with otherCollection!
+ /// </summary>
+ /// <param name="otherCollection">The collection to compare to.</param>
+ /// <returns>True if equal</returns>
+ public virtual bool UnsequencedEquals(ICollection<T> otherCollection)
+ {
+ return otherCollection != null && StaticEquals((ICollection<T>)this, otherCollection, itemequalityComparer);
+ }
+
+
+ /// <summary>
+ /// Check if the collection has been modified since a specified time, expressed as a stamp value.
+ /// </summary>
+ /// <exception cref="CollectionModifiedException"> if this collection has been updated
+ /// since a target time</exception>
+ /// <param name="thestamp">The stamp identifying the target time</param>
+ protected virtual void modifycheck(int thestamp)
+ {
+ if (this.stamp != thestamp)
+ throw new CollectionModifiedException();
+ }
+
+
+ /// <summary>
+ /// Check if it is valid to perform update operations, and if so increment stamp.
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException">If colection is read-only</exception>
+ protected virtual void updatecheck()
+ {
+ if (isReadOnly)
+ throw new ReadOnlyCollectionException();
+
+ stamp++;
+ }
+
+ #endregion
+
+ #region ICollection<T> members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>True if this collection is read only</value>
+ [Tested]
+ public virtual bool IsReadOnly { [Tested]get { return isReadOnly; } }
+
+ #endregion
+
+ #region ICollectionValue<T> members
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>The size of this collection</value>
+ [Tested]
+ public override int Count { [Tested]get { return size; } }
+
+ /// <summary>
+ /// The value is symbolic indicating the type of asymptotic complexity
+ /// in terms of the size of this collection (worst-case or amortized as
+ /// relevant).
+ /// </summary>
+ /// <value>A characterization of the speed of the
+ /// <code>Count</code> property in this collection.</value>
+ public override Speed CountSpeed { get { return Speed.Constant; } }
+
+
+ #endregion
+
+ #region IExtensible<T> members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public virtual SCG.IEqualityComparer<T> EqualityComparer { get { return itemequalityComparer; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>A distinguished object to use for locking to synchronize multithreaded access</value>
+ [Tested]
+ public virtual object SyncRoot { get { return syncroot; } }
+
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>True if this collection is empty</value>
+ [Tested]
+ public override bool IsEmpty { [Tested]get { return size == 0; } }
+
+ #endregion
+
+ #region IEnumerable<T> Members
+ /// <summary>
+ /// Create an enumerator for this collection.
+ /// </summary>
+ /// <returns>The enumerator</returns>
+ public override abstract SCG.IEnumerator<T> GetEnumerator();
+ #endregion
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ [Serializable]
+ public abstract class DirectedCollectionBase<T> : CollectionBase<T>, IDirectedCollectionValue<T>
+ {
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="itemequalityComparer"></param>
+ public DirectedCollectionBase(SCG.IEqualityComparer<T> itemequalityComparer) : base(itemequalityComparer) { }
+ /// <summary>
+ /// <code>Forwards</code> if same, else <code>Backwards</code>
+ /// </summary>
+ /// <value>The enumeration direction relative to the original collection.</value>
+ public virtual EnumerationDirection Direction { [Tested]get { return EnumerationDirection.Forwards; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public abstract IDirectedCollectionValue<T> Backwards();
+
+ IDirectedEnumerable<T> IDirectedEnumerable<T>.Backwards() { return this.Backwards(); }
+
+ /// <summary>
+ /// Check if there exists an item that satisfies a
+ /// specific predicate in this collection and return the first one in enumeration order.
+ /// </summary>
+ /// <param name="predicate">A delegate
+ /// (<see cref="T:C5.Fun`2"/> with <code>R == bool</code>) defining the predicate</param>
+ /// <param name="item"></param>
+ /// <returns>True is such an item exists</returns>
+ public virtual bool FindLast(Fun<T, bool> predicate, out T item)
+ {
+ foreach (T jtem in Backwards())
+ if (predicate(jtem))
+ {
+ item = jtem;
+ return true;
+ }
+ item = default(T);
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Base class (abstract) for sequenced collection implementations.
+ /// </summary>
+ [Serializable]
+ public abstract class SequencedBase<T> : DirectedCollectionBase<T>, IDirectedCollectionValue<T>
+ {
+ #region Fields
+
+ int iSequencedHashCode, iSequencedHashCodeStamp = -1;
+
+ #endregion
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="itemequalityComparer"></param>
+ public SequencedBase(SCG.IEqualityComparer<T> itemequalityComparer) : base(itemequalityComparer) { }
+
+ #region Util
+
+ //TODO: make random for release
+ const int HASHFACTOR = 31;
+
+ /// <summary>
+ /// Compute the unsequenced hash code of a collection
+ /// </summary>
+ /// <param name="items">The collection to compute hash code for</param>
+ /// <param name="itemequalityComparer">The item equalityComparer</param>
+ /// <returns>The hash code</returns>
+ [Tested]
+ public static int ComputeHashCode(ISequenced<T> items, SCG.IEqualityComparer<T> itemequalityComparer)
+ {
+ //NOTE: It must be possible to devise a much stronger combined hashcode,
+ //but unfortunately, it has to be universal. OR we could use a (strong)
+ //family and initialise its parameter randomly at load time of this class!
+ //(We would not want to have yet a flag to check for invalidation?!)
+ //NBNBNB: the current hashcode has the very bad property that items with hashcode 0
+ // is ignored.
+ int iIndexedHashCode = 0;
+
+ foreach (T item in items)
+ iIndexedHashCode = iIndexedHashCode * HASHFACTOR + itemequalityComparer.GetHashCode(item);
+
+ return iIndexedHashCode;
+ }
+
+
+ /// <summary>
+ /// Examine if tit and tat are equal as sequenced collections
+ /// using the specified item equalityComparer (assumed compatible with the two collections).
+ /// </summary>
+ /// <param name="collection1">The first collection</param>
+ /// <param name="collection2">The second collection</param>
+ /// <param name="itemequalityComparer">The item equalityComparer to use for comparison</param>
+ /// <returns>True if equal</returns>
+ [Tested]
+ public static bool StaticEquals(ISequenced<T> collection1, ISequenced<T> collection2, SCG.IEqualityComparer<T> itemequalityComparer)
+ {
+ if (object.ReferenceEquals(collection1, collection2))
+ return true;
+
+ if (collection1.Count != collection2.Count)
+ return false;
+
+ //This way we might run through both enumerations twice, but
+ //probably not (if the hash codes are good)
+ if (collection1.GetSequencedHashCode() != collection2.GetSequencedHashCode())
+ return false;
+
+ using (SCG.IEnumerator<T> dat = collection2.GetEnumerator(), dit = collection1.GetEnumerator())
+ {
+ while (dit.MoveNext())
+ {
+ dat.MoveNext();
+ if (!itemequalityComparer.Equals(dit.Current, dat.Current))
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
+ /// <summary>
+ /// Get the sequenced collection hash code of this collection: from the cached
+ /// value if present and up to date, else (re)compute.
+ /// </summary>
+ /// <returns>The hash code</returns>
+ public virtual int GetSequencedHashCode()
+ {
+ if (iSequencedHashCodeStamp == stamp)
+ return iSequencedHashCode;
+
+ iSequencedHashCode = ComputeHashCode((ISequenced<T>)this, itemequalityComparer);
+ iSequencedHashCodeStamp = stamp;
+ return iSequencedHashCode;
+ }
+
+
+ /// <summary>
+ /// Check if the contents of that is equal to the contents of this
+ /// in the sequenced sense. Using the item equalityComparer of this collection.
+ /// </summary>
+ /// <param name="otherCollection">The collection to compare to.</param>
+ /// <returns>True if equal</returns>
+ public virtual bool SequencedEquals(ISequenced<T> otherCollection)
+ {
+ return StaticEquals((ISequenced<T>)this, otherCollection, itemequalityComparer);
+ }
+
+
+ #endregion
+
+ /// <summary>
+ /// Create an enumerator for this collection.
+ /// </summary>
+ /// <returns>The enumerator</returns>
+ public override abstract SCG.IEnumerator<T> GetEnumerator();
+
+ /// <summary>
+ /// <code>Forwards</code> if same, else <code>Backwards</code>
+ /// </summary>
+ /// <value>The enumeration direction relative to the original collection.</value>
+ [Tested]
+ public override EnumerationDirection Direction { [Tested]get { return EnumerationDirection.Forwards; } }
+
+ /// <summary>
+ /// Check if there exists an item that satisfies a
+ /// specific predicate in this collection and return the index of the first one.
+ /// </summary>
+ /// <param name="predicate">A delegate
+ /// (<see cref="T:C5.Fun`2"/> with <code>R == bool</code>) defining the predicate</param>
+ /// <returns>the index, if found, a negative value else</returns>
+ public int FindIndex(Fun<T, bool> predicate)
+ {
+ int index = 0;
+ foreach (T item in this)
+ {
+ if (predicate(item))
+ return index;
+ index++;
+ }
+ return -1;
+ }
+
+ /// <summary>
+ /// Check if there exists an item that satisfies a
+ /// specific predicate in this collection and return the index of the last one.
+ /// </summary>
+ /// <param name="predicate">A delegate
+ /// (<see cref="T:C5.Fun`2"/> with <code>R == bool</code>) defining the predicate</param>
+ /// <returns>the index, if found, a negative value else</returns>
+ public int FindLastIndex(Fun<T, bool> predicate)
+ {
+ int index = Count - 1;
+ foreach (T item in Backwards())
+ {
+ if (predicate(item))
+ return index;
+ index--;
+ }
+ return -1;
+ }
+
+ }
+
+
+ /// <summary>
+ /// Base class for collection classes of dynamic array type implementations.
+ /// </summary>
+ [Serializable]
+ public abstract class ArrayBase<T> : SequencedBase<T>
+ {
+ #region Fields
+ /// <summary>
+ /// The actual internal array container. Will be extended on demand.
+ /// </summary>
+ protected T[] array;
+
+ /// <summary>
+ /// The offset into the internal array container of the first item. The offset is 0 for a
+ /// base dynamic array and may be positive for an updatable view into a base dynamic array.
+ /// </summary>
+ protected int offset;
+ #endregion
+
+ #region Util
+ /// <summary>
+ /// Double the size of the internal array.
+ /// </summary>
+ protected virtual void expand()
+ {
+ expand(2 * array.Length, size);
+ }
+
+
+ /// <summary>
+ /// Expand the internal array container.
+ /// </summary>
+ /// <param name="newcapacity">The new size of the internal array -
+ /// will be rounded upwards to a power of 2.</param>
+ /// <param name="newsize">The (new) size of the (base) collection.</param>
+ protected virtual void expand(int newcapacity, int newsize)
+ {
+ Debug.Assert(newcapacity >= newsize);
+
+ int newlength = array.Length;
+
+ while (newlength < newcapacity) newlength *= 2;
+
+ T[] newarray = new T[newlength];
+
+ Array.Copy(array, newarray, newsize);
+ array = newarray;
+ }
+
+
+ /// <summary>
+ /// Insert an item at a specific index, moving items to the right
+ /// upwards and expanding the array if necessary.
+ /// </summary>
+ /// <param name="i">The index at which to insert.</param>
+ /// <param name="item">The item to insert.</param>
+ protected virtual void insert(int i, T item)
+ {
+ if (size == array.Length)
+ expand();
+
+ if (i < size)
+ Array.Copy(array, i, array, i + 1, size - i);
+
+ array[i] = item;
+ size++;
+ }
+
+ #endregion
+
+ #region Constructors
+
+ /// <summary>
+ /// Create an empty ArrayBase object.
+ /// </summary>
+ /// <param name="capacity">The initial capacity of the internal array container.
+ /// Will be rounded upwards to the nearest power of 2 greater than or equal to 8.</param>
+ /// <param name="itemequalityComparer">The item equalityComparer to use, primarily for item equality</param>
+ public ArrayBase(int capacity, SCG.IEqualityComparer<T> itemequalityComparer)
+ : base(itemequalityComparer)
+ {
+ int newlength = 8;
+ while (newlength < capacity) newlength *= 2;
+ array = new T[newlength];
+ }
+
+ #endregion
+
+ #region IIndexed members
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">If the arguments does not describe a
+ /// valid range in the indexed collection, cf. <see cref="M:C5.CollectionBase`1.checkRange(System.Int32,System.Int32)"/>.</exception>
+ /// <value>The directed collection of items in a specific index interval.</value>
+ /// <param name="start">The low index of the interval (inclusive).</param>
+ /// <param name="count">The size of the range.</param>
+ [Tested]
+ public virtual IDirectedCollectionValue<T> this[int start, int count]
+ {
+ [Tested]
+ get
+ {
+ checkRange(start, count);
+ return new Range(this, start, count, true);
+ }
+ }
+
+ #endregion
+
+ #region IEditableCollection members
+ /// <summary>
+ /// Remove all items and reset size of internal array container.
+ /// </summary>
+ [Tested]
+ public virtual void Clear()
+ {
+ updatecheck();
+ array = new T[8];
+ size = 0;
+ }
+
+
+ /// <summary>
+ /// Create an array containing (copies) of the items of this collection in enumeration order.
+ /// </summary>
+ /// <returns>The new array</returns>
+ [Tested]
+ public override T[] ToArray()
+ {
+ T[] res = new T[size];
+
+ Array.Copy(array, offset, res, 0, size);
+ return res;
+ }
+
+
+ /// <summary>
+ /// Perform an internal consistency (invariant) test on the array base.
+ /// </summary>
+ /// <returns>True if test succeeds.</returns>
+ [Tested]
+ public virtual bool Check()
+ {
+ bool retval = true;
+
+ if (size > array.Length)
+ {
+ Console.WriteLine("Bad size ({0}) > array.Length ({1})", size, array.Length);
+ return false;
+ }
+
+ for (int i = 0; i < size; i++)
+ {
+ if ((object)(array[i]) == null)
+ {
+ Console.WriteLine("Bad element: null at index {0}", i);
+ return false;
+ }
+ }
+
+ return retval;
+ }
+
+ #endregion
+
+ #region IDirectedCollection<T> Members
+
+ /// <summary>
+ /// Create a directed collection with the same contents as this one, but
+ /// opposite enumeration sequence.
+ /// </summary>
+ /// <returns>The mirrored collection.</returns>
+ [Tested]
+ public override IDirectedCollectionValue<T> Backwards() { return this[0, size].Backwards(); }
+
+ #endregion
+
+ /// <summary>
+ /// Choose some item of this collection. The result is the last item in the internal array,
+ /// making it efficient to remove.
+ /// </summary>
+ /// <exception cref="NoSuchItemException">if collection is empty.</exception>
+ /// <returns></returns>
+ public override T Choose() { if (size > 0) return array[size - 1]; throw new NoSuchItemException(); }
+
+ #region IEnumerable<T> Members
+ /// <summary>
+ /// Create an enumerator for this array based collection.
+ /// </summary>
+ /// <returns>The enumerator</returns>
+ [Tested]
+ public override SCG.IEnumerator<T> GetEnumerator()
+ {
+ int thestamp = stamp, theend = size + offset, thestart = offset;
+
+ for (int i = thestart; i < theend; i++)
+ {
+ modifycheck(thestamp);
+ yield return array[i];
+ }
+ }
+ #endregion
+
+ #region Range nested class
+ /// <summary>
+ /// A helper class for defining results of interval queries on array based collections.
+ /// </summary>
+ protected class Range : DirectedCollectionValueBase<T>, IDirectedCollectionValue<T>
+ {
+ int start, count, delta, stamp;
+
+ ArrayBase<T> thebase;
+
+
+ internal Range(ArrayBase<T> thebase, int start, int count, bool forwards)
+ {
+ this.thebase = thebase; stamp = thebase.stamp;
+ delta = forwards ? 1 : -1;
+ this.start = start + thebase.offset; this.count = count;
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <exception cref="CollectionModifiedException">if underlying collection has been modified.</exception>
+ /// <value>True if this collection is empty.</value>
+ public override bool IsEmpty { get { thebase.modifycheck(stamp); return count == 0; } }
+
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <exception cref="CollectionModifiedException">if underlying collection has been modified.</exception>
+ /// <value>The number of items in the range</value>
+ [Tested]
+ public override int Count { [Tested]get { thebase.modifycheck(stamp); return count; } }
+
+ /// <summary>
+ /// The value is symbolic indicating the type of asymptotic complexity
+ /// in terms of the size of this collection (worst-case or amortized as
+ /// relevant).
+ /// </summary>
+ /// <value>A characterization of the speed of the
+ /// <exception cref="CollectionModifiedException">if underlying collection has been modified.</exception>
+ /// <code>Count</code> property in this collection.</value>
+ public override Speed CountSpeed { get { thebase.modifycheck(stamp); return Speed.Constant; } }
+
+ /// <summary>
+ /// Choose some item of this collection.
+ /// </summary>
+ /// <exception cref="CollectionModifiedException">if underlying collection has been modified.</exception>
+ /// <exception cref="NoSuchItemException">if range is empty.</exception>
+ /// <returns></returns>
+ public override T Choose()
+ {
+ thebase.modifycheck(stamp);
+ if (count == 0)
+ throw new NoSuchItemException();
+ return thebase.array[start];
+ }
+
+
+ /// <summary>
+ /// Create an enumerator for this range of an array based collection.
+ /// </summary>
+ /// <exception cref="CollectionModifiedException">if underlying collection has been modified.</exception>
+ /// <returns>The enumerator</returns>
+ [Tested]
+ public override SCG.IEnumerator<T> GetEnumerator()
+ {
+ for (int i = 0; i < count; i++)
+ {
+ thebase.modifycheck(stamp);
+ yield return thebase.array[start + delta * i];
+ }
+ }
+
+
+ /// <summary>
+ /// Create a araay collection range with the same contents as this one, but
+ /// opposite enumeration sequence.
+ /// </summary>
+ /// <exception cref="CollectionModifiedException">if underlying collection has been modified.</exception>
+ /// <returns>The mirrored collection.</returns>
+ [Tested]
+ public override IDirectedCollectionValue<T> Backwards()
+ {
+ thebase.modifycheck(stamp);
+
+ Range res = (Range)MemberwiseClone();
+
+ res.delta = -delta;
+ res.start = start + (count - 1) * delta;
+ return res;
+ }
+
+
+ IDirectedEnumerable<T> C5.IDirectedEnumerable<T>.Backwards()
+ {
+ return Backwards();
+ }
+
+
+ /// <summary>
+ /// <code>Forwards</code> if same, else <code>Backwards</code>
+ /// </summary>
+ /// <exception cref="CollectionModifiedException">if underlying collection has been modified.</exception>
+ /// <value>The enumeration direction relative to the original collection.</value>
+ [Tested]
+ public override EnumerationDirection Direction
+ {
+ [Tested]
+ get
+ {
+ thebase.modifycheck(stamp);
+ return delta > 0 ? EnumerationDirection.Forwards : EnumerationDirection.Backwards;
+ }
+ }
+ }
+ #endregion
+ }
+}
diff --git a/mcs/class/Mono.C5/C5/Comparer.cs b/mcs/class/Mono.C5/C5/Comparer.cs
new file mode 100644
index 00000000000..784b015e51a
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/Comparer.cs
@@ -0,0 +1,152 @@
+/*
+ Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+using C5;
+using System;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Diagnostics;
+using SCG = System.Collections.Generic;
+
+namespace C5
+{
+/// <summary>
+/// A default item comparer for an item type that is either generic (IComparable&lt;T&gt;)
+/// or ordinarily (System.IComparable) comparable.
+/// </summary>
+ public static class Comparer<T>
+ {
+ readonly static Type naturalComparerO = typeof(NaturalComparerO<>);
+
+ readonly static Type naturalComparer = typeof(NaturalComparer<>);
+
+ static SCG.IComparer<T> cachedComparer = null;
+
+ /// <summary>
+ /// Create a default comparer.
+ /// <para>The IComparer[T] object is constructed when this class is initialised, i.e.
+ /// its static constructors called. Thus, the property will be the same object
+ /// for the duration of an invocation of the runtime, but a value serialized in
+ /// another invocation and deserialized here will not be the same object.</para>
+ /// </summary>
+ /// <exception cref="NotComparableException">If T is not comparable</exception>
+ /// <value>The comparer</value>
+ [Tested]
+ public static SCG.IComparer<T> Default
+ {
+ get
+ {
+ if (cachedComparer != null)
+ return cachedComparer;
+
+ Type t = typeof(T);
+
+ if (t.IsValueType)
+ {
+ if (t.Equals(typeof(int)))
+ return cachedComparer = (SCG.IComparer<T>)(new IntComparer());
+
+ if (t.Equals(typeof(double)))
+ return cachedComparer = (SCG.IComparer<T>)(new DoubleComparer());
+
+ if (t.Equals(typeof(byte)))
+ return cachedComparer = (SCG.IComparer<T>)(new ByteComparer());
+ }
+
+ if (typeof(IComparable<T>).IsAssignableFrom(t))
+ {
+ Type c = naturalComparer.MakeGenericType(new Type[] { t });
+
+ return cachedComparer = (SCG.IComparer<T>)(c.GetConstructor(System.Type.EmptyTypes).Invoke(null));
+ }
+
+ if (t.GetInterface("System.IComparable") != null)
+ {
+ Type c = naturalComparerO.MakeGenericType(new Type[] { t });
+
+ return cachedComparer = (SCG.IComparer<T>)(c.GetConstructor(System.Type.EmptyTypes).Invoke(null));
+ }
+
+ throw new NotComparableException(String.Format("Cannot make comparer for type {0}", t));
+ }
+ }
+ }
+
+ /// <summary>
+ /// A natural generic IComparer for an IComparable&lt;T&gt; item type
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ public class NaturalComparer<T> : SCG.IComparer<T>
+ where T : IComparable<T>
+ {
+ /// <summary>
+ /// Compare two items
+ /// </summary>
+ /// <param name="item1">First item</param>
+ /// <param name="item2">Second item</param>
+ /// <returns>item1 &lt;=&gt; item2</returns>
+ [Tested]
+ public int Compare(T item1, T item2) { return item1 != null ? item1.CompareTo(item2) : item2 != null ? -1 : 0; }
+ }
+
+ /// <summary>
+ /// A natural generic IComparer for a System.IComparable item type
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ public class NaturalComparerO<T> : SCG.IComparer<T>
+ where T : System.IComparable
+ {
+ /// <summary>
+ /// Compare two items
+ /// </summary>
+ /// <param name="item1">First item</param>
+ /// <param name="item2">Second item</param>
+ /// <returns>item1 &lt;=&gt; item2</returns>
+ [Tested]
+ public int Compare(T item1, T item2) { return item1 != null ? item1.CompareTo(item2) : item2 != null ? -1 : 0; }
+ }
+
+ /// <summary>
+ /// A generic comparer for type T based on a Comparison[T] delegate
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ public class DelegateComparer<T> : SCG.IComparer<T>
+ {
+ readonly Comparison<T> cmp;
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="comparison"></param>
+ public DelegateComparer(Comparison<T> comparison)
+ {
+ if (comparison == null)
+ throw new NullReferenceException("Comparison cannot be null");
+ this.cmp = comparison;
+ }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item1">First item</param>
+ /// <param name="item2">Second item</param>
+ /// <returns>item1 &lt;=&gt; item2</returns>
+ public int Compare(T item1, T item2) { return cmp(item1, item2); }
+ }
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/C5/Delegates.cs b/mcs/class/Mono.C5/C5/Delegates.cs
new file mode 100644
index 00000000000..36792d8555b
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/Delegates.cs
@@ -0,0 +1,131 @@
+/*
+ Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+using C5;
+using System;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Diagnostics;
+
+#pragma warning disable 1711
+namespace C5
+{
+ /// <summary>
+ ///
+ /// </summary>
+ public delegate void Act();
+ /// <summary>
+ /// <para>
+ /// The type Act[T] corresponds to System.Action[T] in the .Net
+ /// Framework class library.
+ ///</para>
+ /// </summary>
+ /// <typeparam name="A1"></typeparam>
+ /// <param name="x1"></param>
+ public delegate void Act<A1>(A1 x1);
+ /// <summary>
+ ///
+ /// </summary>
+ /// <typeparam name="A1"></typeparam>
+ /// <typeparam name="A2"></typeparam>
+ /// <param name="x1"></param>
+ /// <param name="x2"></param>
+ public delegate void Act<A1, A2>(A1 x1, A2 x2);
+ /// <summary>
+ ///
+ /// </summary>
+ /// <typeparam name="A1"></typeparam>
+ /// <typeparam name="A2"></typeparam>
+ /// <typeparam name="A3"></typeparam>
+ /// <param name="x1"></param>
+ /// <param name="x2"></param>
+ /// <param name="x3"></param>
+ public delegate void Act<A1, A2, A3>(A1 x1, A2 x2, A3 x3);
+ /// <summary>
+ ///
+ /// </summary>
+ /// <typeparam name="A1"></typeparam>
+ /// <typeparam name="A2"></typeparam>
+ /// <typeparam name="A3"></typeparam>
+ /// <typeparam name="A4"></typeparam>
+ /// <param name="x1"></param>
+ /// <param name="x2"></param>
+ /// <param name="x3"></param>
+ /// <param name="x4"></param>
+ public delegate void Act<A1, A2, A3, A4>(A1 x1, A2 x2, A3 x3, A4 x4);
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <typeparam name="R"></typeparam>
+ /// <returns></returns>
+ public delegate R Fun<R>();
+ /// <summary>
+ /// Delegate type Fun[A1,R] is the type of functions (methods) from A1
+ /// to R, used to compute some transformation for a given collection
+ /// item.
+ /// <para>
+ /// The type Fun[T,U] corresponds to System.Converter[T,U] in the .Net
+ /// Framework class library, and the type Fun[T,bool] corresponds
+ /// System.Predicate[T] in the .Net Framework class library.</para>
+ /// </summary>
+ /// <typeparam name="A1"></typeparam>
+ /// <typeparam name="R"></typeparam>
+ /// <param name="x1"></param>
+ /// <returns></returns>
+ public delegate R Fun<A1, R>(A1 x1);
+ /// <summary>
+ ///
+ /// </summary>
+ /// <typeparam name="A1"></typeparam>
+ /// <typeparam name="A2"></typeparam>
+ /// <typeparam name="R"></typeparam>
+ /// <param name="x1"></param>
+ /// <param name="x2"></param>
+ /// <returns></returns>
+ public delegate R Fun<A1, A2, R>(A1 x1, A2 x2);
+ /// <summary>
+ ///
+ /// </summary>
+ /// <typeparam name="A1"></typeparam>
+ /// <typeparam name="A2"></typeparam>
+ /// <typeparam name="A3"></typeparam>
+ /// <typeparam name="R"></typeparam>
+ /// <param name="x1"></param>
+ /// <param name="x2"></param>
+ /// <param name="x3"></param>
+ /// <returns></returns>
+ public delegate R Fun<A1, A2, A3, R>(A1 x1, A2 x2, A3 x3);
+ /// <summary>
+ ///
+ /// </summary>
+ /// <typeparam name="A1"></typeparam>
+ /// <typeparam name="A2"></typeparam>
+ /// <typeparam name="A3"></typeparam>
+ /// <typeparam name="A4"></typeparam>
+ /// <typeparam name="R"></typeparam>
+ /// <param name="x1"></param>
+ /// <param name="x2"></param>
+ /// <param name="x3"></param>
+ /// <param name="x4"></param>
+ /// <returns></returns>
+ public delegate R Fun<A1, A2, A3, A4, R>(A1 x1, A2 x2, A3 x3, A4 x4);
+}
diff --git a/mcs/class/Mono.C5/C5/Dictionaries.cs b/mcs/class/Mono.C5/C5/Dictionaries.cs
new file mode 100644
index 00000000000..4370461c7ea
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/Dictionaries.cs
@@ -0,0 +1,1295 @@
+/*
+ Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+using System;
+using System.Diagnostics;
+using SCG = System.Collections.Generic;
+namespace C5
+{
+ /// <summary>
+ /// An entry in a dictionary from K to V.
+ /// </summary>
+ [Serializable]
+ public struct KeyValuePair<K, V> : IEquatable<KeyValuePair<K, V>>, IShowable
+ {
+ /// <summary>
+ /// The key field of the entry
+ /// </summary>
+ public K Key;
+
+ /// <summary>
+ /// The value field of the entry
+ /// </summary>
+ public V Value;
+
+ /// <summary>
+ /// Create an entry with specified key and value
+ /// </summary>
+ /// <param name="key">The key</param>
+ /// <param name="value">The value</param>
+ public KeyValuePair(K key, V value) { Key = key; Value = value; }
+
+
+ /// <summary>
+ /// Create an entry with a specified key. The value will be the default value of type <code>V</code>.
+ /// </summary>
+ /// <param name="key">The key</param>
+ public KeyValuePair(K key) { Key = key; Value = default(V); }
+
+
+ /// <summary>
+ /// Pretty print an entry
+ /// </summary>
+ /// <returns>(key, value)</returns>
+ [Tested]
+ public override string ToString() { return "(" + Key + ", " + Value + ")"; }
+
+
+ /// <summary>
+ /// Check equality of entries.
+ /// </summary>
+ /// <param name="obj">The other object</param>
+ /// <returns>True if obj is an entry of the same type and has the same key and value</returns>
+ [Tested]
+ public override bool Equals(object obj)
+ {
+ if (!(obj is KeyValuePair<K, V>))
+ return false;
+ KeyValuePair<K, V> other = (KeyValuePair<K, V>)obj;
+ return Equals(other);
+ }
+
+
+ /// <summary>
+ /// Get the hash code of the pair.
+ /// </summary>
+ /// <returns>The hash code</returns>
+ [Tested]
+ public override int GetHashCode() { return EqualityComparer<K>.Default.GetHashCode(Key) + 13984681 * EqualityComparer<V>.Default.GetHashCode(Value); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="other"></param>
+ /// <returns></returns>
+ public bool Equals(KeyValuePair<K, V> other)
+ {
+ return EqualityComparer<K>.Default.Equals(Key, other.Key) && EqualityComparer<V>.Default.Equals(Value, other.Value);
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="pair1"></param>
+ /// <param name="pair2"></param>
+ /// <returns></returns>
+ public static bool operator ==(KeyValuePair<K, V> pair1, KeyValuePair<K, V> pair2) { return pair1.Equals(pair2); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="pair1"></param>
+ /// <param name="pair2"></param>
+ /// <returns></returns>
+ public static bool operator !=(KeyValuePair<K, V> pair1, KeyValuePair<K, V> pair2) { return !pair1.Equals(pair2); }
+
+ #region IShowable Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="stringbuilder"></param>
+ /// <param name="formatProvider"></param>
+ /// <param name="rest"></param>
+ /// <returns></returns>
+ public bool Show(System.Text.StringBuilder stringbuilder, ref int rest, IFormatProvider formatProvider)
+ {
+ if (rest < 0)
+ return false;
+ if (!Showing.Show(Key, stringbuilder, ref rest, formatProvider))
+ return false;
+ stringbuilder.Append(" => ");
+ rest -= 4;
+ if (!Showing.Show(Value, stringbuilder, ref rest, formatProvider))
+ return false;
+ return rest >= 0;
+ }
+ #endregion
+
+ #region IFormattable Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="format"></param>
+ /// <param name="formatProvider"></param>
+ /// <returns></returns>
+ public string ToString(string format, IFormatProvider formatProvider)
+ {
+ return Showing.ShowString(this, format, formatProvider);
+ }
+
+ #endregion
+ }
+
+
+
+ /// <summary>
+ /// Default comparer for dictionary entries in a sorted dictionary.
+ /// Entry comparisons only look at keys and uses an externally defined comparer for that.
+ /// </summary>
+ [Serializable]
+ public class KeyValuePairComparer<K, V> : SCG.IComparer<KeyValuePair<K, V>>
+ {
+ SCG.IComparer<K> comparer;
+
+
+ /// <summary>
+ /// Create an entry comparer for a item comparer of the keys
+ /// </summary>
+ /// <param name="comparer">Comparer of keys</param>
+ public KeyValuePairComparer(SCG.IComparer<K> comparer)
+ {
+ if (comparer == null)
+ throw new NullReferenceException();
+ this.comparer = comparer;
+ }
+
+
+ /// <summary>
+ /// Compare two entries
+ /// </summary>
+ /// <param name="entry1">First entry</param>
+ /// <param name="entry2">Second entry</param>
+ /// <returns>The result of comparing the keys</returns>
+ [Tested]
+ public int Compare(KeyValuePair<K, V> entry1, KeyValuePair<K, V> entry2)
+ { return comparer.Compare(entry1.Key, entry2.Key); }
+ }
+
+
+
+ /// <summary>
+ /// Default equalityComparer for dictionary entries.
+ /// Operations only look at keys and uses an externaly defined equalityComparer for that.
+ /// </summary>
+ [Serializable]
+ public sealed class KeyValuePairEqualityComparer<K, V> : SCG.IEqualityComparer<KeyValuePair<K, V>>
+ {
+ SCG.IEqualityComparer<K> keyequalityComparer;
+
+
+ /// <summary>
+ /// Create an entry equalityComparer using the default equalityComparer for keys
+ /// </summary>
+ public KeyValuePairEqualityComparer() { keyequalityComparer = EqualityComparer<K>.Default; }
+
+
+ /// <summary>
+ /// Create an entry equalityComparer from a specified item equalityComparer for the keys
+ /// </summary>
+ /// <param name="keyequalityComparer">The key equalityComparer</param>
+ public KeyValuePairEqualityComparer(SCG.IEqualityComparer<K> keyequalityComparer)
+ {
+ if (keyequalityComparer == null)
+ throw new NullReferenceException("Key equality comparer cannot be null");
+ this.keyequalityComparer = keyequalityComparer;
+ }
+
+
+ /// <summary>
+ /// Get the hash code of the entry
+ /// </summary>
+ /// <param name="entry">The entry</param>
+ /// <returns>The hash code of the key</returns>
+ [Tested]
+ public int GetHashCode(KeyValuePair<K, V> entry) { return keyequalityComparer.GetHashCode(entry.Key); }
+
+
+ /// <summary>
+ /// Test two entries for equality
+ /// </summary>
+ /// <param name="entry1">First entry</param>
+ /// <param name="entry2">Second entry</param>
+ /// <returns>True if keys are equal</returns>
+ [Tested]
+ public bool Equals(KeyValuePair<K, V> entry1, KeyValuePair<K, V> entry2)
+ { return keyequalityComparer.Equals(entry1.Key, entry2.Key); }
+ }
+
+
+
+ /// <summary>
+ /// A base class for implementing a dictionary based on a set collection implementation.
+ /// <i>See the source code for <see cref="T:C5.HashDictionary`2"/> for an example</i>
+ ///
+ /// </summary>
+ [Serializable]
+ public abstract class DictionaryBase<K, V> : CollectionValueBase<KeyValuePair<K, V>>, IDictionary<K, V>
+ {
+ /// <summary>
+ /// The set collection of entries underlying this dictionary implementation
+ /// </summary>
+ protected ICollection<KeyValuePair<K, V>> pairs;
+
+ SCG.IEqualityComparer<K> keyequalityComparer;
+
+ #region Events
+ ProxyEventBlock<KeyValuePair<K, V>> eventBlock;
+
+ /// <summary>
+ /// The change event. Will be raised for every change operation on the collection.
+ /// </summary>
+ public override event CollectionChangedHandler<KeyValuePair<K, V>> CollectionChanged
+ {
+ add { (eventBlock ?? (eventBlock = new ProxyEventBlock<KeyValuePair<K, V>>(this, pairs))).CollectionChanged += value; }
+ remove { if (eventBlock != null) eventBlock.CollectionChanged -= value; }
+ }
+
+ /// <summary>
+ /// The change event. Will be raised for every change operation on the collection.
+ /// </summary>
+ public override event CollectionClearedHandler<KeyValuePair<K, V>> CollectionCleared
+ {
+ add { (eventBlock ?? (eventBlock = new ProxyEventBlock<KeyValuePair<K, V>>(this, pairs))).CollectionCleared += value; }
+ remove { if (eventBlock != null) eventBlock.CollectionCleared -= value; }
+ }
+
+ /// <summary>
+ /// The item added event. Will be raised for every individual addition to the collection.
+ /// </summary>
+ public override event ItemsAddedHandler<KeyValuePair<K, V>> ItemsAdded
+ {
+ add { (eventBlock ?? (eventBlock = new ProxyEventBlock<KeyValuePair<K, V>>(this, pairs))).ItemsAdded += value; }
+ remove { if (eventBlock != null) eventBlock.ItemsAdded -= value; }
+ }
+
+ /// <summary>
+ /// The item added event. Will be raised for every individual removal from the collection.
+ /// </summary>
+ public override event ItemsRemovedHandler<KeyValuePair<K, V>> ItemsRemoved
+ {
+ add { (eventBlock ?? (eventBlock = new ProxyEventBlock<KeyValuePair<K, V>>(this, pairs))).ItemsRemoved += value; }
+ remove { if (eventBlock != null) eventBlock.ItemsRemoved -= value; }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ public override EventTypeEnum ListenableEvents
+ {
+ get
+ {
+ return EventTypeEnum.Basic;
+ }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ public override EventTypeEnum ActiveEvents
+ {
+ get
+ {
+ return pairs.ActiveEvents;
+ }
+ }
+
+ #endregion
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="keyequalityComparer"></param>
+ public DictionaryBase(SCG.IEqualityComparer<K> keyequalityComparer) {
+ if (keyequalityComparer == null)
+ throw new NullReferenceException("Key equality comparer cannot be null");
+ this.keyequalityComparer = keyequalityComparer; }
+
+ #region IDictionary<K,V> Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public virtual SCG.IEqualityComparer<K> EqualityComparer { get { return keyequalityComparer; } }
+
+
+ /// <summary>
+ /// Add a new (key, value) pair (a mapping) to the dictionary.
+ /// </summary>
+ /// <exception cref="DuplicateNotAllowedException"> if there already is an entry with the same key. </exception>
+ /// <param name="key">Key to add</param>
+ /// <param name="value">Value to add</param>
+ [Tested]
+ public virtual void Add(K key, V value)
+ {
+ KeyValuePair<K, V> p = new KeyValuePair<K, V>(key, value);
+
+ if (!pairs.Add(p))
+ throw new DuplicateNotAllowedException("Key being added: '" + key + "'");
+ }
+
+ /// <summary>
+ /// Add the entries from a collection of <see cref="T:C5.KeyValuePair`2"/> pairs to this dictionary.
+ /// <para><b>TODO: add restrictions L:K and W:V when the .Net SDK allows it </b></para>
+ /// </summary>
+ /// <exception cref="DuplicateNotAllowedException">
+ /// If the input contains duplicate keys or a key already present in this dictionary.</exception>
+ /// <param name="entries"></param>
+ public virtual void AddAll<L,W>(SCG.IEnumerable<KeyValuePair<L, W>> entries)
+ where L : K
+ where W : V
+ {
+ foreach (KeyValuePair<L, W> pair in entries)
+ {
+ KeyValuePair<K, V> p = new KeyValuePair<K, V>(pair.Key, pair.Value);
+ if (!pairs.Add(p))
+ throw new DuplicateNotAllowedException("Key being added: '" + pair.Key + "'");
+ }
+ }
+
+ /// <summary>
+ /// Remove an entry with a given key from the dictionary
+ /// </summary>
+ /// <param name="key">The key of the entry to remove</param>
+ /// <returns>True if an entry was found (and removed)</returns>
+ [Tested]
+ public virtual bool Remove(K key)
+ {
+ KeyValuePair<K, V> p = new KeyValuePair<K, V>(key);
+
+ return pairs.Remove(p);
+ }
+
+
+ /// <summary>
+ /// Remove an entry with a given key from the dictionary and report its value.
+ /// </summary>
+ /// <param name="key">The key of the entry to remove</param>
+ /// <param name="value">On exit, the value of the removed entry</param>
+ /// <returns>True if an entry was found (and removed)</returns>
+ [Tested]
+ public virtual bool Remove(K key, out V value)
+ {
+ KeyValuePair<K, V> p = new KeyValuePair<K, V>(key);
+
+ if (pairs.Remove(p, out p))
+ {
+ value = p.Value;
+ return true;
+ }
+ else
+ {
+ value = default(V);
+ return false;
+ }
+ }
+
+
+ /// <summary>
+ /// Remove all entries from the dictionary
+ /// </summary>
+ [Tested]
+ public virtual void Clear() { pairs.Clear(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public virtual Speed ContainsSpeed { get { return pairs.ContainsSpeed; } }
+
+ /// <summary>
+ /// Check if there is an entry with a specified key
+ /// </summary>
+ /// <param name="key">The key to look for</param>
+ /// <returns>True if key was found</returns>
+ [Tested]
+ public virtual bool Contains(K key)
+ {
+ KeyValuePair<K, V> p = new KeyValuePair<K, V>(key);
+
+ return pairs.Contains(p);
+ }
+
+ class LiftedEnumerable<H> : SCG.IEnumerable<KeyValuePair<K, V>> where H : K
+ {
+ SCG.IEnumerable<H> keys;
+ public LiftedEnumerable(SCG.IEnumerable<H> keys) { this.keys = keys; }
+ public SCG.IEnumerator<KeyValuePair<K, V>> GetEnumerator() { foreach (H key in keys) yield return new KeyValuePair<K, V>(key); }
+
+ #region IEnumerable Members
+
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+ {
+ throw new Exception("The method or operation is not implemented.");
+ }
+
+ #endregion
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="keys"></param>
+ /// <returns></returns>
+ public virtual bool ContainsAll<H>(SCG.IEnumerable<H> keys) where H : K
+ {
+ return pairs.ContainsAll(new LiftedEnumerable<H>(keys));
+ }
+
+ /// <summary>
+ /// Check if there is an entry with a specified key and report the corresponding
+ /// value if found. This can be seen as a safe form of "val = this[key]".
+ /// </summary>
+ /// <param name="key">The key to look for</param>
+ /// <param name="value">On exit, the value of the entry</param>
+ /// <returns>True if key was found</returns>
+ [Tested]
+ public virtual bool Find(K key, out V value)
+ {
+ return Find(ref key, out value);
+ }
+ /// <summary>
+ /// Check if there is an entry with a specified key and report the corresponding
+ /// value if found. This can be seen as a safe form of "val = this[key]".
+ /// </summary>
+ /// <param name="key">The key to look for</param>
+ /// <param name="value">On exit, the value of the entry</param>
+ /// <returns>True if key was found</returns>
+ public virtual bool Find(ref K key, out V value)
+ {
+ KeyValuePair<K, V> p = new KeyValuePair<K, V>(key);
+
+ if (pairs.Find(ref p))
+ {
+ key = p.Key;
+ value = p.Value;
+ return true;
+ }
+ else
+ {
+ value = default(V);
+ return false;
+ }
+ }
+
+
+ /// <summary>
+ /// Look for a specific key in the dictionary and if found replace the value with a new one.
+ /// This can be seen as a non-adding version of "this[key] = val".
+ /// </summary>
+ /// <param name="key">The key to look for</param>
+ /// <param name="value">The new value</param>
+ /// <returns>True if key was found</returns>
+ [Tested]
+ public virtual bool Update(K key, V value)
+ {
+ KeyValuePair<K, V> p = new KeyValuePair<K, V>(key, value);
+
+ return pairs.Update(p);
+ }
+
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="key"></param>
+ /// <param name="value"></param>
+ /// <param name="oldvalue"></param>
+ /// <returns></returns>
+ public virtual bool Update(K key, V value, out V oldvalue)
+ {
+ KeyValuePair<K, V> p = new KeyValuePair<K, V>(key, value);
+
+ bool retval = pairs.Update(p, out p);
+ oldvalue = p.Value;
+ return retval;
+ }
+
+
+ /// <summary>
+ /// Look for a specific key in the dictionary. If found, report the corresponding value,
+ /// else add an entry with the key and the supplied value.
+ /// </summary>
+ /// <param name="key">On entry the key to look for</param>
+ /// <param name="value">On entry the value to add if the key is not found.
+ /// On exit the value found if any.</param>
+ /// <returns>True if key was found</returns>
+ [Tested]
+ public virtual bool FindOrAdd(K key, ref V value)
+ {
+ KeyValuePair<K, V> p = new KeyValuePair<K, V>(key, value);
+
+ if (!pairs.FindOrAdd(ref p))
+ return false;
+ else
+ {
+ value = p.Value;
+ //key = p.key;
+ return true;
+ }
+ }
+
+
+ /// <summary>
+ /// Update value in dictionary corresponding to key if found, else add new entry.
+ /// More general than "this[key] = val;" by reporting if key was found.
+ /// </summary>
+ /// <param name="key">The key to look for</param>
+ /// <param name="value">The value to add or replace with.</param>
+ /// <returns>True if entry was updated.</returns>
+ [Tested]
+ public virtual bool UpdateOrAdd(K key, V value)
+ {
+ return pairs.UpdateOrAdd(new KeyValuePair<K, V>(key, value));
+ }
+
+
+ /// <summary>
+ /// Update value in dictionary corresponding to key if found, else add new entry.
+ /// More general than "this[key] = val;" by reporting if key was found and the old value if any.
+ /// </summary>
+ /// <param name="key"></param>
+ /// <param name="value"></param>
+ /// <param name="oldvalue"></param>
+ /// <returns></returns>
+ public virtual bool UpdateOrAdd(K key, V value, out V oldvalue)
+ {
+ KeyValuePair<K, V> p = new KeyValuePair<K, V>(key, value);
+ bool retval = pairs.UpdateOrAdd(p, out p);
+ oldvalue = p.Value;
+ return retval;
+ }
+
+
+
+ #region Keys,Values support classes
+
+ internal class ValuesCollection : CollectionValueBase<V>, ICollectionValue<V>
+ {
+ ICollection<KeyValuePair<K, V>> pairs;
+
+
+ internal ValuesCollection(ICollection<KeyValuePair<K, V>> pairs)
+ { this.pairs = pairs; }
+
+
+ public override V Choose() { return pairs.Choose().Value; }
+
+ [Tested]
+ public override SCG.IEnumerator<V> GetEnumerator()
+ {
+ //Updatecheck is performed by the pairs enumerator
+ foreach (KeyValuePair<K, V> p in pairs)
+ yield return p.Value;
+ }
+
+ public override bool IsEmpty { get { return pairs.IsEmpty; } }
+
+ [Tested]
+ public override int Count { [Tested]get { return pairs.Count; } }
+
+ public override Speed CountSpeed { get { return Speed.Constant; } }
+ }
+
+
+
+ internal class KeysCollection : CollectionValueBase<K>, ICollectionValue<K>
+ {
+ ICollection<KeyValuePair<K, V>> pairs;
+
+
+ internal KeysCollection(ICollection<KeyValuePair<K, V>> pairs)
+ { this.pairs = pairs; }
+
+ public override K Choose() { return pairs.Choose().Key; }
+
+ [Tested]
+ public override SCG.IEnumerator<K> GetEnumerator()
+ {
+ foreach (KeyValuePair<K, V> p in pairs)
+ yield return p.Key;
+ }
+
+ public override bool IsEmpty { get { return pairs.IsEmpty; } }
+
+ [Tested]
+ public override int Count { [Tested]get { return pairs.Count; } }
+
+ public override Speed CountSpeed { get { return pairs.CountSpeed; } }
+ }
+ #endregion
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>A collection containg the all the keys of the dictionary</value>
+ [Tested]
+ public virtual ICollectionValue<K> Keys { [Tested]get { return new KeysCollection(pairs); } }
+
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>A collection containing all the values of the dictionary</value>
+ [Tested]
+ public virtual ICollectionValue<V> Values { [Tested]get { return new ValuesCollection(pairs); } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ public virtual Fun<K, V> Fun { get { return delegate(K k) { return this[k]; }; } }
+
+ /// <summary>
+ /// Indexer by key for dictionary.
+ /// <para>The get method will throw an exception if no entry is found. </para>
+ /// <para>The set method behaves like <see cref="M:C5.DictionaryBase`2.UpdateOrAdd(`0,`1)"/>.</para>
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> On get if no entry is found. </exception>
+ /// <value>The value corresponding to the key</value>
+ [Tested]
+ public virtual V this[K key]
+ {
+ [Tested]
+ get
+ {
+ KeyValuePair<K, V> p = new KeyValuePair<K, V>(key);
+
+ if (pairs.Find(ref p))
+ return p.Value;
+ else
+ throw new NoSuchItemException("Key '" + key.ToString() + "' not present in Dictionary");
+ }
+ [Tested]
+ set
+ { pairs.UpdateOrAdd(new KeyValuePair<K, V>(key, value)); }
+ }
+
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>True if dictionary is read only</value>
+ [Tested]
+ public virtual bool IsReadOnly { [Tested]get { return pairs.IsReadOnly; } }
+
+
+ /// <summary>
+ /// Check the integrity of the internal data structures of this dictionary.
+ /// </summary>
+ /// <returns>True if check does not fail.</returns>
+ [Tested]
+ public virtual bool Check() { return pairs.Check(); }
+
+ #endregion
+
+ #region ICollectionValue<KeyValuePair<K,V>> Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>True if this collection is empty.</value>
+ public override bool IsEmpty { get { return pairs.IsEmpty; } }
+
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>The number of entrues in the dictionary</value>
+ [Tested]
+ public override int Count { [Tested]get { return pairs.Count; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>The number of entrues in the dictionary</value>
+ [Tested]
+ public override Speed CountSpeed { [Tested]get { return pairs.CountSpeed; } }
+
+ /// <summary>
+ /// Choose some entry in this Dictionary.
+ /// </summary>
+ /// <exception cref="NoSuchItemException">if collection is empty.</exception>
+ /// <returns></returns>
+ public override KeyValuePair<K, V> Choose() { return pairs.Choose(); }
+
+ /// <summary>
+ /// Create an enumerator for the collection of entries of the dictionary
+ /// </summary>
+ /// <returns>The enumerator</returns>
+ [Tested]
+ public override SCG.IEnumerator<KeyValuePair<K, V>> GetEnumerator()
+ {
+ return pairs.GetEnumerator(); ;
+ }
+
+ #endregion
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="stringbuilder"></param>
+ /// <param name="rest"></param>
+ /// <param name="formatProvider"></param>
+ /// <returns></returns>
+ public override bool Show(System.Text.StringBuilder stringbuilder, ref int rest, IFormatProvider formatProvider)
+ {
+ return Showing.ShowDictionary<K, V>(this, stringbuilder, ref rest, formatProvider);
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public abstract object Clone();
+
+ }
+
+ /// <summary>
+ /// A base class for implementing a sorted dictionary based on a sorted set collection implementation.
+ /// <i>See the source code for <see cref="T:C5.TreeDictionary`2"/> for an example</i>
+ ///
+ /// </summary>
+ public abstract class SortedDictionaryBase<K, V> : DictionaryBase<K, V>, ISortedDictionary<K, V>
+ {
+ #region Fields
+
+ /// <summary>
+ ///
+ /// </summary>
+ protected ISorted<KeyValuePair<K, V>> sortedpairs;
+ SCG.IComparer<K> keycomparer;
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="keycomparer"></param>
+ /// <param name="keyequalityComparer"></param>
+ public SortedDictionaryBase(SCG.IComparer<K> keycomparer, SCG.IEqualityComparer<K> keyequalityComparer) : base(keyequalityComparer) { this.keycomparer = keycomparer; }
+
+ #endregion
+
+ #region ISortedDictionary<K,V> Members
+
+ /// <summary>
+ /// The key comparer used by this dictionary.
+ /// </summary>
+ /// <value></value>
+ public SCG.IComparer<K> Comparer { get { return keycomparer; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public new ISorted<K> Keys { get { return new SortedKeysCollection(this, sortedpairs, keycomparer, EqualityComparer); } }
+
+ /// <summary>
+ /// Get the entry in the dictionary whose key is the
+ /// predecessor of a specified key.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"></exception>
+ /// <param name="key">The key</param>
+ /// <returns>The entry</returns>
+ [Tested]
+ public KeyValuePair<K, V> Predecessor(K key)
+ {
+ KeyValuePair<K, V> p = new KeyValuePair<K, V>(key);
+
+ return sortedpairs.Predecessor(p);
+ }
+
+
+ /// <summary>
+ /// Get the entry in the dictionary whose key is the
+ /// weak predecessor of a specified key.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"></exception>
+ /// <param name="key">The key</param>
+ /// <returns>The entry</returns>
+ [Tested]
+ public KeyValuePair<K, V> WeakPredecessor(K key)
+ {
+ KeyValuePair<K, V> p = new KeyValuePair<K, V>(key);
+
+ return sortedpairs.WeakPredecessor(p);
+ }
+
+
+ /// <summary>
+ /// Get the entry in the dictionary whose key is the
+ /// successor of a specified key.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"></exception>
+ /// <param name="key">The key</param>
+ /// <returns>The entry</returns>
+ [Tested]
+ public KeyValuePair<K, V> Successor(K key)
+ {
+ KeyValuePair<K, V> p = new KeyValuePair<K, V>(key);
+
+ return sortedpairs.Successor(p);
+ }
+
+
+ /// <summary>
+ /// Get the entry in the dictionary whose key is the
+ /// weak successor of a specified key.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"></exception>
+ /// <param name="key">The key</param>
+ /// <returns>The entry</returns>
+ [Tested]
+ public KeyValuePair<K, V> WeakSuccessor(K key)
+ {
+ return sortedpairs.WeakSuccessor(new KeyValuePair<K, V>(key));
+ }
+
+ #endregion
+
+ #region ISortedDictionary<K,V> Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public KeyValuePair<K, V> FindMin()
+ {
+ return sortedpairs.FindMin();
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public KeyValuePair<K, V> DeleteMin()
+ {
+ return sortedpairs.DeleteMin();
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public KeyValuePair<K, V> FindMax()
+ {
+ return sortedpairs.FindMax();
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public KeyValuePair<K, V> DeleteMax()
+ {
+ return sortedpairs.DeleteMax();
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="cutter"></param>
+ /// <param name="lowEntry"></param>
+ /// <param name="lowIsValid"></param>
+ /// <param name="highEntry"></param>
+ /// <param name="highIsValid"></param>
+ /// <returns></returns>
+ public bool Cut(IComparable<K> cutter, out KeyValuePair<K, V> lowEntry, out bool lowIsValid, out KeyValuePair<K, V> highEntry, out bool highIsValid)
+ {
+ return sortedpairs.Cut(new KeyValuePairComparable(cutter), out lowEntry, out lowIsValid, out highEntry, out highIsValid);
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="bot"></param>
+ /// <returns></returns>
+ public IDirectedEnumerable<KeyValuePair<K, V>> RangeFrom(K bot)
+ {
+ return sortedpairs.RangeFrom(new KeyValuePair<K, V>(bot));
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="bot"></param>
+ /// <param name="top"></param>
+ /// <returns></returns>
+ public IDirectedEnumerable<KeyValuePair<K, V>> RangeFromTo(K bot, K top)
+ {
+ return sortedpairs.RangeFromTo(new KeyValuePair<K, V>(bot), new KeyValuePair<K, V>(top));
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="top"></param>
+ /// <returns></returns>
+ public IDirectedEnumerable<KeyValuePair<K, V>> RangeTo(K top)
+ {
+ return sortedpairs.RangeTo(new KeyValuePair<K, V>(top));
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public IDirectedCollectionValue<KeyValuePair<K, V>> RangeAll()
+ {
+ return sortedpairs.RangeAll();
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="items"></param>
+ public void AddSorted(SCG.IEnumerable<KeyValuePair<K, V>> items)
+ {
+ sortedpairs.AddSorted(items);
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="lowKey"></param>
+ public void RemoveRangeFrom(K lowKey)
+ {
+ sortedpairs.RemoveRangeFrom(new KeyValuePair<K, V>(lowKey));
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="lowKey"></param>
+ /// <param name="highKey"></param>
+ public void RemoveRangeFromTo(K lowKey, K highKey)
+ {
+ sortedpairs.RemoveRangeFromTo(new KeyValuePair<K, V>(lowKey), new KeyValuePair<K, V>(highKey));
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="highKey"></param>
+ public void RemoveRangeTo(K highKey)
+ {
+ sortedpairs.RemoveRangeTo(new KeyValuePair<K, V>(highKey));
+ }
+
+ #endregion
+
+ class KeyValuePairComparable : IComparable<KeyValuePair<K, V>>
+ {
+ IComparable<K> cutter;
+
+ internal KeyValuePairComparable(IComparable<K> cutter) { this.cutter = cutter; }
+
+ public int CompareTo(KeyValuePair<K, V> other) { return cutter.CompareTo(other.Key); }
+
+ public bool Equals(KeyValuePair<K, V> other) { return cutter.Equals(other.Key); }
+ }
+
+ class ProjectedDirectedEnumerable : MappedDirectedEnumerable<KeyValuePair<K, V>, K>
+ {
+ public ProjectedDirectedEnumerable(IDirectedEnumerable<KeyValuePair<K, V>> directedpairs) : base(directedpairs) { }
+
+ public override K Map(KeyValuePair<K, V> pair) { return pair.Key; }
+
+ }
+
+ class ProjectedDirectedCollectionValue : MappedDirectedCollectionValue<KeyValuePair<K, V>, K>
+ {
+ public ProjectedDirectedCollectionValue(IDirectedCollectionValue<KeyValuePair<K, V>> directedpairs) : base(directedpairs) { }
+
+ public override K Map(KeyValuePair<K, V> pair) { return pair.Key; }
+
+ }
+
+ class SortedKeysCollection : SequencedBase<K>, ISorted<K>
+ {
+ ISortedDictionary<K, V> sorteddict;
+ //TODO: eliminate this. Only problem is the Find method because we lack method on dictionary that also
+ // returns the actual key.
+ ISorted<KeyValuePair<K, V>> sortedpairs;
+ SCG.IComparer<K> comparer;
+
+ internal SortedKeysCollection(ISortedDictionary<K, V> sorteddict, ISorted<KeyValuePair<K, V>> sortedpairs, SCG.IComparer<K> comparer, SCG.IEqualityComparer<K> itemequalityComparer)
+ :base(itemequalityComparer)
+ {
+ this.sorteddict = sorteddict;
+ this.sortedpairs = sortedpairs;
+ this.comparer = comparer;
+ }
+
+ public override K Choose() { return sorteddict.Choose().Key; }
+
+ public override SCG.IEnumerator<K> GetEnumerator()
+ {
+ foreach (KeyValuePair<K, V> p in sorteddict)
+ yield return p.Key;
+ }
+
+ public override bool IsEmpty { get { return sorteddict.IsEmpty; } }
+
+ public override int Count { [Tested]get { return sorteddict.Count; } }
+
+ public override Speed CountSpeed { get { return sorteddict.CountSpeed; } }
+
+ #region ISorted<K> Members
+
+ public K FindMin() { return sorteddict.FindMin().Key; }
+
+ public K DeleteMin() { throw new ReadOnlyCollectionException(); }
+
+ public K FindMax() { return sorteddict.FindMax().Key; }
+
+ public K DeleteMax() { throw new ReadOnlyCollectionException(); }
+
+ public SCG.IComparer<K> Comparer { get { return comparer; } }
+
+ public K Predecessor(K item) { return sorteddict.Predecessor(item).Key; }
+
+ public K Successor(K item) { return sorteddict.Successor(item).Key; }
+
+ public K WeakPredecessor(K item) { return sorteddict.WeakPredecessor(item).Key; }
+
+ public K WeakSuccessor(K item) { return sorteddict.WeakSuccessor(item).Key; }
+
+ public bool Cut(IComparable<K> c, out K low, out bool lowIsValid, out K high, out bool highIsValid)
+ {
+ KeyValuePair<K, V> lowpair, highpair;
+ bool retval = sorteddict.Cut(c, out lowpair, out lowIsValid, out highpair, out highIsValid);
+ low = lowpair.Key;
+ high = highpair.Key;
+ return retval;
+ }
+
+ public IDirectedEnumerable<K> RangeFrom(K bot)
+ {
+ return new ProjectedDirectedEnumerable(sorteddict.RangeFrom(bot));
+ }
+
+ public IDirectedEnumerable<K> RangeFromTo(K bot, K top)
+ {
+ return new ProjectedDirectedEnumerable(sorteddict.RangeFromTo(bot, top));
+ }
+
+ public IDirectedEnumerable<K> RangeTo(K top)
+ {
+ return new ProjectedDirectedEnumerable(sorteddict.RangeTo(top));
+ }
+
+ public IDirectedCollectionValue<K> RangeAll()
+ {
+ return new ProjectedDirectedCollectionValue(sorteddict.RangeAll());
+ }
+
+ public void AddSorted<U>(SCG.IEnumerable<U> items) where U : K { throw new ReadOnlyCollectionException(); }
+
+ public void RemoveRangeFrom(K low) { throw new ReadOnlyCollectionException(); }
+
+ public void RemoveRangeFromTo(K low, K hi) { throw new ReadOnlyCollectionException(); }
+
+ public void RemoveRangeTo(K hi) { throw new ReadOnlyCollectionException(); }
+ #endregion
+
+ #region ICollection<K> Members
+ public Speed ContainsSpeed { get { return sorteddict.ContainsSpeed; } }
+
+ public bool Contains(K key) { return sorteddict.Contains(key); ; }
+
+ public int ContainsCount(K item) { return sorteddict.Contains(item) ? 1 : 0; }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public virtual ICollectionValue<K> UniqueItems()
+ {
+ return this;
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public virtual ICollectionValue<KeyValuePair<K, int>> ItemMultiplicities()
+ {
+ return new MultiplicityOne<K>(this);
+ }
+
+
+ public bool ContainsAll<U>(SCG.IEnumerable<U> items) where U : K
+ {
+ //TODO: optimize?
+ foreach (K item in items)
+ if (!sorteddict.Contains(item))
+ return false;
+ return true;
+ }
+
+ public bool Find(ref K item)
+ {
+ KeyValuePair<K, V> p = new KeyValuePair<K, V>(item);
+ bool retval = sortedpairs.Find(ref p);
+ item = p.Key;
+ return retval;
+ }
+
+ public bool FindOrAdd(ref K item) { throw new ReadOnlyCollectionException(); }
+
+ public bool Update(K item) { throw new ReadOnlyCollectionException(); }
+
+ public bool Update(K item, out K olditem) { throw new ReadOnlyCollectionException(); }
+
+ public bool UpdateOrAdd(K item) { throw new ReadOnlyCollectionException(); }
+
+ public bool UpdateOrAdd(K item, out K olditem) { throw new ReadOnlyCollectionException(); }
+
+ public bool Remove(K item) { throw new ReadOnlyCollectionException(); }
+
+ public bool Remove(K item, out K removeditem) { throw new ReadOnlyCollectionException(); }
+
+ public void RemoveAllCopies(K item) { throw new ReadOnlyCollectionException(); }
+
+ public void RemoveAll<U> (SCG.IEnumerable<U> items) where U : K { throw new ReadOnlyCollectionException(); }
+
+ public void Clear() { throw new ReadOnlyCollectionException(); }
+
+ public void RetainAll<U>(SCG.IEnumerable<U> items) where U : K { throw new ReadOnlyCollectionException(); }
+
+ #endregion
+
+ #region IExtensible<K> Members
+ public override bool IsReadOnly { get { return true; } }
+
+ public bool AllowsDuplicates { get { return false; } }
+
+ public bool DuplicatesByCounting { get { return true; } }
+
+ public bool Add(K item) { throw new ReadOnlyCollectionException(); }
+
+ public void AddAll(System.Collections.Generic.IEnumerable<K> items) { throw new ReadOnlyCollectionException(); }
+
+ public void AddAll<U>(System.Collections.Generic.IEnumerable<U> items) where U : K { throw new ReadOnlyCollectionException(); }
+
+ public bool Check() { return sorteddict.Check(); }
+
+ #endregion
+
+ #region IDirectedCollectionValue<K> Members
+
+ public override IDirectedCollectionValue<K> Backwards()
+ {
+ return RangeAll().Backwards();
+ }
+
+ #endregion
+
+ #region IDirectedEnumerable<K> Members
+
+ IDirectedEnumerable<K> IDirectedEnumerable<K>.Backwards() { return Backwards(); }
+ #endregion
+
+ #region ICloneable Members
+
+ //TODO: test
+ /// <summary>
+ /// Make a shallow copy of this SortedKeysCollection.
+ /// </summary>
+ /// <returns></returns>
+ public virtual object Clone()
+ {
+ //
+ SortedArrayDictionary<K, V> dictclone = new SortedArrayDictionary<K, V>(sortedpairs.Count, comparer, EqualityComparer);
+ SortedArray<KeyValuePair<K, V>> sortedpairsclone = (SortedArray<KeyValuePair<K, V>>)(dictclone.sortedpairs);
+ foreach (K key in sorteddict.Keys)
+ {
+ sortedpairsclone.Add(new KeyValuePair<K, V>(key, default(V)));
+ }
+ return new SortedKeysCollection(dictclone, sortedpairsclone, comparer, EqualityComparer);
+ }
+
+ #endregion
+
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="stringbuilder"></param>
+ /// <param name="rest"></param>
+ /// <param name="formatProvider"></param>
+ /// <returns></returns>
+ public override bool Show(System.Text.StringBuilder stringbuilder, ref int rest, IFormatProvider formatProvider)
+ {
+ return Showing.ShowDictionary<K, V>(this, stringbuilder, ref rest, formatProvider);
+ }
+
+ }
+
+ class SortedArrayDictionary<K, V> : SortedDictionaryBase<K, V>, IDictionary<K, V>, ISortedDictionary<K, V>
+ {
+ #region Constructors
+
+ public SortedArrayDictionary() : this(Comparer<K>.Default, EqualityComparer<K>.Default) { }
+
+ /// <summary>
+ /// Create a red-black tree dictionary using an external comparer for keys.
+ /// </summary>
+ /// <param name="comparer">The external comparer</param>
+ public SortedArrayDictionary(SCG.IComparer<K> comparer) : this(comparer, new ComparerZeroHashCodeEqualityComparer<K>(comparer)) { }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="comparer"></param>
+ /// <param name="equalityComparer"></param>
+ public SortedArrayDictionary(SCG.IComparer<K> comparer, SCG.IEqualityComparer<K> equalityComparer) : base(comparer,equalityComparer)
+ {
+ pairs = sortedpairs = new SortedArray<KeyValuePair<K, V>>(new KeyValuePairComparer<K, V>(comparer));
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="comparer"></param>
+ /// <param name="equalityComparer"></param>
+ /// <param name="capacity"></param>
+ public SortedArrayDictionary(int capacity, SCG.IComparer<K> comparer, SCG.IEqualityComparer<K> equalityComparer) : base(comparer,equalityComparer)
+ {
+ pairs = sortedpairs = new SortedArray<KeyValuePair<K, V>>(capacity, new KeyValuePairComparer<K, V>(comparer));
+ }
+ #endregion
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public override object Clone()
+ {
+ SortedArrayDictionary<K, V> clone = new SortedArrayDictionary<K, V>(Comparer, EqualityComparer);
+ clone.sortedpairs.AddSorted(sortedpairs);
+ return clone;
+ }
+
+ }
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/C5/Enums.cs b/mcs/class/Mono.C5/C5/Enums.cs
new file mode 100644
index 00000000000..a92301d83e2
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/Enums.cs
@@ -0,0 +1,98 @@
+/*
+ Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+using System;
+using System.Diagnostics;
+using SCG = System.Collections.Generic;
+namespace C5
+{
+
+ /// <summary>
+ /// The symbolic characterization of the speed of lookups for a collection.
+ /// The values may refer to worst-case, amortized and/or expected asymtotic
+ /// complexity wrt. the collection size.
+ /// </summary>
+ public enum Speed : short
+ {
+ /// <summary>
+ /// Counting the collection with the <code>Count property</code> may not return
+ /// (for a synthetic and potentially infinite collection).
+ /// </summary>
+ PotentiallyInfinite = 1,
+ /// <summary>
+ /// Lookup operations like <code>Contains(T item)</code> or the <code>Count</code>
+ /// property may take time O(n),
+ /// where n is the size of the collection.
+ /// </summary>
+ Linear = 2,
+ /// <summary>
+ /// Lookup operations like <code>Contains(T item)</code> or the <code>Count</code>
+ /// property takes time O(log n),
+ /// where n is the size of the collection.
+ /// </summary>
+ Log = 3,
+ /// <summary>
+ /// Lookup operations like <code>Contains(T item)</code> or the <code>Count</code>
+ /// property takes time O(1),
+ /// where n is the size of the collection.
+ /// </summary>
+ Constant = 4
+ }
+ /*
+ /// <summary>
+ ///
+ /// </summary>
+ public enum ItemEqualityTypeEnum
+ {
+ /// <summary>
+ /// Only an Equals(T,T)
+ /// </summary>
+ Equator,
+ /// <summary>
+ /// Equals(T,T) and GetHashCode(T)
+ /// </summary>
+ HashingEqualityComparer,
+ /// <summary>
+ /// Compare(T,T)
+ /// </summary>
+ Comparer,
+ /// <summary>
+ /// Compatible Compare(T,T) and GetHashCode(T)
+ /// </summary>
+ Both
+ }
+*/
+
+ /// <summary>
+ /// Direction of enumeration order relative to original collection.
+ /// </summary>
+ public enum EnumerationDirection
+ {
+ /// <summary>
+ /// Same direction
+ /// </summary>
+ Forwards,
+ /// <summary>
+ /// Opposite direction
+ /// </summary>
+ Backwards
+ }
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/C5/Events.cs b/mcs/class/Mono.C5/C5/Events.cs
new file mode 100644
index 00000000000..4a5d8d7d1b3
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/Events.cs
@@ -0,0 +1,532 @@
+/*
+ Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+using System;
+using System.Diagnostics;
+using SCG = System.Collections.Generic;
+
+namespace C5
+{
+ /// <summary>
+ ///
+ /// </summary>
+ [Flags]
+ public enum EventTypeEnum
+ {
+ /// <summary>
+ ///
+ /// </summary>
+ None = 0x00000000,
+ /// <summary>
+ ///
+ /// </summary>
+ Changed = 0x00000001,
+ /// <summary>
+ ///
+ /// </summary>
+ Cleared = 0x00000002,
+ /// <summary>
+ ///
+ /// </summary>
+ Added = 0x00000004,
+ /// <summary>
+ ///
+ /// </summary>
+ Removed = 0x00000008,
+ /// <summary>
+ ///
+ /// </summary>
+ Basic = 0x0000000f,
+ /// <summary>
+ ///
+ /// </summary>
+ Inserted = 0x00000010,
+ /// <summary>
+ ///
+ /// </summary>
+ RemovedAt = 0x00000020,
+ /// <summary>
+ ///
+ /// </summary>
+ All = 0x0000003f
+ }
+
+ /// <summary>
+ /// Holds the real events for a collection
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ [Serializable]
+ internal sealed class EventBlock<T>
+ {
+ internal EventTypeEnum events;
+
+ event CollectionChangedHandler<T> collectionChanged;
+ internal event CollectionChangedHandler<T> CollectionChanged
+ {
+ add
+ {
+ collectionChanged += value;
+ events |= EventTypeEnum.Changed;
+ }
+ remove
+ {
+ collectionChanged -= value;
+ if (collectionChanged == null)
+ events &= ~EventTypeEnum.Changed;
+ }
+ }
+ internal void raiseCollectionChanged(object sender)
+ { if (collectionChanged != null) collectionChanged(sender); }
+
+ event CollectionClearedHandler<T> collectionCleared;
+ internal event CollectionClearedHandler<T> CollectionCleared
+ {
+ add
+ {
+ collectionCleared += value;
+ events |= EventTypeEnum.Cleared;
+ }
+ remove
+ {
+ collectionCleared -= value;
+ if (collectionCleared == null)
+ events &= ~EventTypeEnum.Cleared;
+ }
+ }
+ internal void raiseCollectionCleared(object sender, bool full, int count)
+ { if (collectionCleared != null) collectionCleared(sender, new ClearedEventArgs(full, count)); }
+ internal void raiseCollectionCleared(object sender, bool full, int count, int? start)
+ { if (collectionCleared != null) collectionCleared(sender, new ClearedRangeEventArgs(full, count, start)); }
+
+ event ItemsAddedHandler<T> itemsAdded;
+ internal event ItemsAddedHandler<T> ItemsAdded
+ {
+ add
+ {
+ itemsAdded += value;
+ events |= EventTypeEnum.Added;
+ }
+ remove
+ {
+ itemsAdded -= value;
+ if (itemsAdded == null)
+ events &= ~EventTypeEnum.Added;
+ }
+ }
+ internal void raiseItemsAdded(object sender, T item, int count)
+ { if (itemsAdded != null) itemsAdded(sender, new ItemCountEventArgs<T>(item, count)); }
+
+ event ItemsRemovedHandler<T> itemsRemoved;
+ internal event ItemsRemovedHandler<T> ItemsRemoved
+ {
+ add
+ {
+ itemsRemoved += value;
+ events |= EventTypeEnum.Removed;
+ }
+ remove
+ {
+ itemsRemoved -= value;
+ if (itemsRemoved == null)
+ events &= ~EventTypeEnum.Removed;
+ }
+ }
+ internal void raiseItemsRemoved(object sender, T item, int count)
+ { if (itemsRemoved != null) itemsRemoved(sender, new ItemCountEventArgs<T>(item, count)); }
+
+ event ItemInsertedHandler<T> itemInserted;
+ internal event ItemInsertedHandler<T> ItemInserted
+ {
+ add
+ {
+ itemInserted += value;
+ events |= EventTypeEnum.Inserted;
+ }
+ remove
+ {
+ itemInserted -= value;
+ if (itemInserted == null)
+ events &= ~EventTypeEnum.Inserted;
+ }
+ }
+ internal void raiseItemInserted(object sender, T item, int index)
+ { if (itemInserted != null) itemInserted(sender, new ItemAtEventArgs<T>(item, index)); }
+
+ event ItemRemovedAtHandler<T> itemRemovedAt;
+ internal event ItemRemovedAtHandler<T> ItemRemovedAt
+ {
+ add
+ {
+ itemRemovedAt += value;
+ events |= EventTypeEnum.RemovedAt;
+ }
+ remove
+ {
+ itemRemovedAt -= value;
+ if (itemRemovedAt == null)
+ events &= ~EventTypeEnum.RemovedAt;
+ }
+ }
+ internal void raiseItemRemovedAt(object sender, T item, int index)
+ { if (itemRemovedAt != null) itemRemovedAt(sender, new ItemAtEventArgs<T>(item, index)); }
+ }
+
+ /// <summary>
+ /// Tentative, to conserve memory in GuardedCollectionValueBase
+ /// This should really be nested in Guarded collection value, only have a guardereal field
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ [Serializable]
+ internal sealed class ProxyEventBlock<T>
+ {
+ ICollectionValue<T> proxy, real;
+
+ internal ProxyEventBlock(ICollectionValue<T> proxy, ICollectionValue<T> real)
+ { this.proxy = proxy; this.real = real; }
+
+ event CollectionChangedHandler<T> collectionChanged;
+ CollectionChangedHandler<T> collectionChangedProxy;
+ internal event CollectionChangedHandler<T> CollectionChanged
+ {
+ add
+ {
+ if (collectionChanged == null)
+ {
+ if (collectionChangedProxy == null)
+ collectionChangedProxy = delegate(object sender) { collectionChanged(proxy); };
+ real.CollectionChanged += collectionChangedProxy;
+ }
+ collectionChanged += value;
+ }
+ remove
+ {
+ collectionChanged -= value;
+ if (collectionChanged == null)
+ real.CollectionChanged -= collectionChangedProxy;
+ }
+ }
+
+ event CollectionClearedHandler<T> collectionCleared;
+ CollectionClearedHandler<T> collectionClearedProxy;
+ internal event CollectionClearedHandler<T> CollectionCleared
+ {
+ add
+ {
+ if (collectionCleared == null)
+ {
+ if (collectionClearedProxy == null)
+ collectionClearedProxy = delegate(object sender, ClearedEventArgs e) { collectionCleared(proxy, e); };
+ real.CollectionCleared += collectionClearedProxy;
+ }
+ collectionCleared += value;
+ }
+ remove
+ {
+ collectionCleared -= value;
+ if (collectionCleared == null)
+ real.CollectionCleared -= collectionClearedProxy;
+ }
+ }
+
+ event ItemsAddedHandler<T> itemsAdded;
+ ItemsAddedHandler<T> itemsAddedProxy;
+ internal event ItemsAddedHandler<T> ItemsAdded
+ {
+ add
+ {
+ if (itemsAdded == null)
+ {
+ if (itemsAddedProxy == null)
+ itemsAddedProxy = delegate(object sender, ItemCountEventArgs<T> e) { itemsAdded(proxy, e); };
+ real.ItemsAdded += itemsAddedProxy;
+ }
+ itemsAdded += value;
+ }
+ remove
+ {
+ itemsAdded -= value;
+ if (itemsAdded == null)
+ real.ItemsAdded -= itemsAddedProxy;
+ }
+ }
+
+ event ItemInsertedHandler<T> itemInserted;
+ ItemInsertedHandler<T> itemInsertedProxy;
+ internal event ItemInsertedHandler<T> ItemInserted
+ {
+ add
+ {
+ if (itemInserted == null)
+ {
+ if (itemInsertedProxy == null)
+ itemInsertedProxy = delegate(object sender, ItemAtEventArgs<T> e) { itemInserted(proxy, e); };
+ real.ItemInserted += itemInsertedProxy;
+ }
+ itemInserted += value;
+ }
+ remove
+ {
+ itemInserted -= value;
+ if (itemInserted == null)
+ real.ItemInserted -= itemInsertedProxy;
+ }
+ }
+
+ event ItemsRemovedHandler<T> itemsRemoved;
+ ItemsRemovedHandler<T> itemsRemovedProxy;
+ internal event ItemsRemovedHandler<T> ItemsRemoved
+ {
+ add
+ {
+ if (itemsRemoved == null)
+ {
+ if (itemsRemovedProxy == null)
+ itemsRemovedProxy = delegate(object sender, ItemCountEventArgs<T> e) { itemsRemoved(proxy, e); };
+ real.ItemsRemoved += itemsRemovedProxy;
+ }
+ itemsRemoved += value;
+ }
+ remove
+ {
+ itemsRemoved -= value;
+ if (itemsRemoved == null)
+ real.ItemsRemoved -= itemsRemovedProxy;
+ }
+ }
+
+ event ItemRemovedAtHandler<T> itemRemovedAt;
+ ItemRemovedAtHandler<T> itemRemovedAtProxy;
+ internal event ItemRemovedAtHandler<T> ItemRemovedAt
+ {
+ add
+ {
+ if (itemRemovedAt == null)
+ {
+ if (itemRemovedAtProxy == null)
+ itemRemovedAtProxy = delegate(object sender, ItemAtEventArgs<T> e) { itemRemovedAt(proxy, e); };
+ real.ItemRemovedAt += itemRemovedAtProxy;
+ }
+ itemRemovedAt += value;
+ }
+ remove
+ {
+ itemRemovedAt -= value;
+ if (itemRemovedAt == null)
+ real.ItemRemovedAt -= itemRemovedAtProxy;
+ }
+ }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ public class ItemAtEventArgs<T> : EventArgs
+ {
+ /// <summary>
+ ///
+ /// </summary>
+ public readonly T Item;
+ /// <summary>
+ ///
+ /// </summary>
+ public readonly int Index;
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ /// <param name="index"></param>
+ public ItemAtEventArgs(T item, int index) { Item = item; Index = index; }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public override string ToString()
+ {
+ return String.Format("(ItemAtEventArgs {0} '{1}')", Index, Item);
+ }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ public class ItemCountEventArgs<T> : EventArgs
+ {
+ /// <summary>
+ ///
+ /// </summary>
+ public readonly T Item;
+ /// <summary>
+ ///
+ /// </summary>
+ public readonly int Count;
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="count"></param>
+ /// <param name="item"></param>
+ public ItemCountEventArgs(T item, int count) { Item = item; Count = count; }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public override string ToString()
+ {
+ return String.Format("(ItemCountEventArgs {0} '{1}')", Count, Item);
+ }
+ }
+
+
+
+ /// <summary>
+ ///
+ /// </summary>
+ public class ClearedEventArgs : EventArgs
+ {
+ /// <summary>
+ ///
+ /// </summary>
+ public readonly bool Full;
+ /// <summary>
+ ///
+ /// </summary>
+ public readonly int Count;
+ /// <summary>
+ ///
+ /// </summary>
+ ///
+ /// <param name="full">True if the operation cleared all of the collection</param>
+ /// <param name="count">The number of items removed by the clear.</param>
+ public ClearedEventArgs(bool full, int count) { Full = full; Count = count; }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public override string ToString()
+ {
+ return String.Format("(ClearedEventArgs {0} {1})", Count, Full);
+ }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ public class ClearedRangeEventArgs : ClearedEventArgs
+ {
+ //WE could let this be of type int? to allow
+ /// <summary>
+ ///
+ /// </summary>
+ public readonly int? Start;
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="full"></param>
+ /// <param name="count"></param>
+ /// <param name="start"></param>
+ public ClearedRangeEventArgs(bool full, int count, int? start) : base(full,count) { Start = start; }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public override string ToString()
+ {
+ return String.Format("(ClearedRangeEventArgs {0} {1} {2})", Count, Full, Start);
+ }
+ }
+
+ /// <summary>
+ /// The type of event raised after an operation on a collection has changed its contents.
+ /// Normally, a multioperation like AddAll,
+ /// <see cref="M:C5.IExtensible`1.AddAll(System.Collections.Generic.IEnumerable{`0})"/>
+ /// will only fire one CollectionChanged event. Any operation that changes the collection
+ /// must fire CollectionChanged as its last event.
+ /// </summary>
+ public delegate void CollectionChangedHandler<T>(object sender);
+
+ /// <summary>
+ /// The type of event raised after the Clear() operation on a collection.
+ /// <para/>
+ /// Note: The Clear() operation will not fire ItemsRemoved events.
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="eventArgs"></param>
+ public delegate void CollectionClearedHandler<T>(object sender, ClearedEventArgs eventArgs);
+
+ /// <summary>
+ /// The type of event raised after an item has been added to a collection.
+ /// The event will be raised at a point of time, where the collection object is
+ /// in an internally consistent state and before the corresponding CollectionChanged
+ /// event is raised.
+ /// <para/>
+ /// Note: an Update operation will fire an ItemsRemoved and an ItemsAdded event.
+ /// <para/>
+ /// Note: When an item is inserted into a list (<see cref="T:C5.IList`1"/>), both
+ /// ItemInserted and ItemsAdded events will be fired.
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="eventArgs">An object with the item that was added</param>
+ public delegate void ItemsAddedHandler<T>(object sender, ItemCountEventArgs<T> eventArgs);
+
+ /// <summary>
+ /// The type of event raised after an item has been removed from a collection.
+ /// The event will be raised at a point of time, where the collection object is
+ /// in an internally consistent state and before the corresponding CollectionChanged
+ /// event is raised.
+ /// <para/>
+ /// Note: The Clear() operation will not fire ItemsRemoved events.
+ /// <para/>
+ /// Note: an Update operation will fire an ItemsRemoved and an ItemsAdded event.
+ /// <para/>
+ /// Note: When an item is removed from a list by the RemoveAt operation, both an
+ /// ItemsRemoved and an ItemRemovedAt event will be fired.
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="eventArgs">An object with the item that was removed</param>
+ public delegate void ItemsRemovedHandler<T>(object sender, ItemCountEventArgs<T> eventArgs);
+
+ /// <summary>
+ /// The type of event raised after an item has been inserted into a list by an Insert,
+ /// InsertFirst or InsertLast operation.
+ /// The event will be raised at a point of time, where the collection object is
+ /// in an internally consistent state and before the corresponding CollectionChanged
+ /// event is raised.
+ /// <para/>
+ /// Note: an ItemsAdded event will also be fired.
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="eventArgs"></param>
+ public delegate void ItemInsertedHandler<T>(object sender, ItemAtEventArgs<T> eventArgs);
+
+ /// <summary>
+ /// The type of event raised after an item has been removed from a list by a RemoveAt(int i)
+ /// operation (or RemoveFirst(), RemoveLast(), Remove() operation).
+ /// The event will be raised at a point of time, where the collection object is
+ /// in an internally consistent state and before the corresponding CollectionChanged
+ /// event is raised.
+ /// <para/>
+ /// Note: an ItemRemoved event will also be fired.
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="eventArgs"></param>
+ public delegate void ItemRemovedAtHandler<T>(object sender, ItemAtEventArgs<T> eventArgs);
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/C5/Exceptions.cs b/mcs/class/Mono.C5/C5/Exceptions.cs
new file mode 100644
index 00000000000..2480b22c6df
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/Exceptions.cs
@@ -0,0 +1,244 @@
+/*
+ Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+using System;
+using System.Diagnostics;
+using SCG = System.Collections.Generic;
+
+namespace C5
+{
+ /// <summary>
+ /// An exception to throw from library code when an internal inconsistency is encountered.
+ /// </summary>
+ public class InternalException : Exception
+ {
+ internal InternalException(string message) : base(message) { }
+ }
+
+ /// <summary>
+ /// An exception thrown by an update operation on a Read-Only collection or dictionary.
+ /// <para>This exception will be thrown unconditionally when an update operation
+ /// (method or set property) is called. No check is made to see if the update operation,
+ /// if allowed, would actually change the collection. </para>
+ /// </summary>
+ [Serializable]
+ public class ReadOnlyCollectionException : Exception
+ {
+ /// <summary>
+ /// Create a simple exception with no further explanation.
+ /// </summary>
+ public ReadOnlyCollectionException() : base() { }
+ /// <summary>
+ /// Create the exception with an explanation of the reason.
+ /// </summary>
+ /// <param name="message"></param>
+ public ReadOnlyCollectionException(string message) : base(message) { }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ [Serializable]
+ public class FixedSizeCollectionException : Exception
+ {
+ /// <summary>
+ /// Create a simple exception with no further explanation.
+ /// </summary>
+ public FixedSizeCollectionException() : base() { }
+ /// <summary>
+ /// Create the exception with an explanation of the reason.
+ /// </summary>
+ /// <param name="message"></param>
+ public FixedSizeCollectionException(string message) : base(message) { }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ [Serializable]
+ public class UnlistenableEventException : Exception
+ {
+ /// <summary>
+ /// Create a simple exception with no further explanation.
+ /// </summary>
+ public UnlistenableEventException() : base() { }
+ /// <summary>
+ /// Create the exception with an explanation of the reason.
+ /// </summary>
+ /// <param name="message"></param>
+ public UnlistenableEventException(string message) : base(message) { }
+ }
+
+ /// <summary>
+ /// An exception thrown by enumerators, range views etc. when accessed after
+ /// the underlying collection has been modified.
+ /// </summary>
+ [Serializable]
+ public class CollectionModifiedException : Exception
+ {
+ /// <summary>
+ /// Create a simple exception with no further explanation.
+ /// </summary>
+ public CollectionModifiedException() : base() { }
+ /// <summary>
+ /// Create the exception with an explanation of the reason.
+ /// </summary>
+ /// <param name="message"></param>
+ public CollectionModifiedException(string message) : base(message) { }
+ }
+
+ /// <summary>
+ /// An excption thrown when trying to access a view (a list view on a <see cref="T:C5.IList`1"/> or
+ /// a snapshot on a <see cref="T:C5.IPersistentSorted`1"/>)
+ /// that has been invalidated by some earlier operation.
+ /// <para>
+ /// The typical scenario is a view on a list that hash been invalidated by a call to
+ /// Sort, Reverse or Shuffle on some other, overlapping view or the whole list.
+ /// </para>
+ /// </summary>
+ [Serializable]
+ public class ViewDisposedException : Exception
+ {
+ /// <summary>
+ /// Create a simple exception with no further explanation.
+ /// </summary>
+ public ViewDisposedException() : base() { }
+ /// <summary>
+ /// Create the exception with an explanation of the reason.
+ /// </summary>
+ /// <param name="message"></param>
+ public ViewDisposedException(string message) : base(message) { }
+ }
+
+ /// <summary>
+ /// An exception thrown by a lookup or lookup with update operation that does not
+ /// find the lookup item and has no other means to communicate failure.
+ /// <para>The typical scenario is a lookup by key in a dictionary with an indexer,
+ /// see e.g. <see cref="P:C5.IDictionary`2.Item(`0)"/></para>
+ /// </summary>
+ [Serializable]
+ public class NoSuchItemException : Exception
+ {
+ /// <summary>
+ /// Create a simple exception with no further explanation.
+ /// </summary>
+ public NoSuchItemException() : base() { }
+ /// <summary>
+ /// Create the exception with an explanation of the reason.
+ /// </summary>
+ /// <param name="message"></param>
+ public NoSuchItemException(string message) : base(message) { }
+ }
+
+ /// <summary>
+ /// An exception thrown by an operation on a list (<see cref="T:C5.IList`1"/>)
+ /// that only makes sense for a view, not for an underlying list.
+ /// </summary>
+ [Serializable]
+ public class NotAViewException : Exception
+ {
+ /// <summary>
+ /// Create a simple exception with no further explanation.
+ /// </summary>
+ public NotAViewException() : base() { }
+ /// <summary>
+ /// Create the exception with an explanation of the reason.
+ /// </summary>
+ /// <param name="message"></param>
+ public NotAViewException(string message) : base(message) { }
+ }
+
+ /// <summary>
+ /// An exception thrown when an operation attempts to create a duplicate in a collection with set semantics
+ /// (<see cref="P:C5.IExtensible`1.AllowsDuplicates"/> is false) or attempts to create a duplicate key in a dictionary.
+ /// <para>With collections this can only happen with Insert operations on lists, since the Add operations will
+ /// not try to create duplictes and either ignore the failure or report it in a bool return value.
+ /// </para>
+ /// <para>With dictionaries this can happen with the <see cref="M:C5.IDictionary`2.Add(`0,`1)"/> metod.</para>
+ /// </summary>
+ [Serializable]
+ public class DuplicateNotAllowedException : Exception
+ {
+ /// <summary>
+ /// Create a simple exception with no further explanation.
+ /// </summary>
+ public DuplicateNotAllowedException() : base() { }
+ /// <summary>
+ /// Create the exception with an explanation of the reason.
+ /// </summary>
+ /// <param name="message"></param>
+ public DuplicateNotAllowedException(string message) : base(message) { }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ [Serializable]
+ public class InvalidPriorityQueueHandleException : Exception
+ {
+ /// <summary>
+ /// Create a simple exception with no further explanation.
+ /// </summary>
+ public InvalidPriorityQueueHandleException() : base() { }
+ /// <summary>
+ /// Create the exception with an explanation of the reason.
+ /// </summary>
+ /// <param name="message"></param>
+ public InvalidPriorityQueueHandleException(string message) : base(message) { }
+ }
+
+ /// <summary>
+ /// An exception thrown by an operation that need to construct a natural
+ /// comparer for a type.
+ /// </summary>
+ [Serializable]
+ public class NotComparableException : Exception
+ {
+ /// <summary>
+ /// Create a simple exception with no further explanation.
+ /// </summary>
+ public NotComparableException() : base() { }
+ /// <summary>
+ /// Create the exception with an explanation of the reason.
+ /// </summary>
+ /// <param name="message"></param>
+ public NotComparableException(string message) : base(message) { }
+ }
+
+ /// <summary>
+ /// An exception thrown by operations on a list that expects an argument
+ /// that is a view on the same underlying list.
+ /// </summary>
+ [Serializable]
+ public class IncompatibleViewException : Exception
+ {
+ /// <summary>
+ /// Create a simple exception with no further explanation.
+ /// </summary>
+ public IncompatibleViewException() : base() { }
+ /// <summary>
+ /// Create the exception with an explanation of the reason.
+ /// </summary>
+ /// <param name="message"></param>
+ public IncompatibleViewException(string message) : base(message) { }
+ }
+
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/C5/Formatting.cs b/mcs/class/Mono.C5/C5/Formatting.cs
new file mode 100644
index 00000000000..5d4a1449f42
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/Formatting.cs
@@ -0,0 +1,247 @@
+/*
+ Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+using C5;
+using System;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Diagnostics;
+using System.Text;
+
+namespace C5
+{
+ /// <summary>
+ /// <i>(Describe usage of "L:300" format string.)</i>
+ /// </summary>
+ public interface IShowable : IFormattable
+ {
+ //TODO: wonder if we should use TextWriters instead of StringBuilders?
+ /// <summary>
+ /// Format <code>this</code> using at most approximately <code>rest</code> chars and
+ /// append the result, possibly truncated, to stringbuilder.
+ /// Subtract the actual number of used chars from <code>rest</code>.
+ /// </summary>
+ /// <param name="stringbuilder"></param>
+ /// <param name="rest"></param>
+ /// <param name="formatProvider"></param>
+ /// <returns>True if the appended formatted string was complete (not truncated).</returns>
+ bool Show(StringBuilder stringbuilder, ref int rest, IFormatProvider formatProvider);
+ }
+ // ------------------------------------------------------------
+
+ // Static helper methods for Showing collections
+
+ /// <summary>
+ ///
+ /// </summary>
+ public static class Showing
+ {
+ /// <summary>
+ /// Show <code>Object obj</code> by appending it to <code>stringbuilder</code>
+ /// </summary>
+ /// <param name="obj"></param>
+ /// <param name="stringbuilder"></param>
+ /// <param name="rest"></param>
+ /// <param name="formatProvider"></param>
+ /// <returns>True if <code>obj</code> was shown completely.</returns>
+ public static bool Show(Object obj, StringBuilder stringbuilder, ref int rest, IFormatProvider formatProvider)
+ {
+ if (rest <= 0)
+ return false;
+ else if (obj is IShowable)
+ return ((IShowable)obj).Show(stringbuilder, ref rest, formatProvider);
+ int oldLength = stringbuilder.Length;
+ stringbuilder.AppendFormat(formatProvider, "{0}", obj);
+ rest -= (stringbuilder.Length - oldLength);
+ return true;
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="showable"></param>
+ /// <param name="format"></param>
+ /// <param name="formatProvider"></param>
+ /// <returns></returns>
+ public static String ShowString(IShowable showable, String format, IFormatProvider formatProvider)
+ {
+ int rest = maxLength(format);
+ StringBuilder sb = new StringBuilder();
+ showable.Show(sb, ref rest, formatProvider);
+ return sb.ToString();
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="format"></param>
+ /// <returns></returns>
+ static int maxLength(String format)
+ {
+ //TODO: validate format string
+ if (format == null)
+ return 80;
+ if (format.Length > 1 && format.StartsWith("L"))
+ {
+ return int.Parse(format.Substring(1));
+ }
+ else
+ return int.MaxValue;
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="items"></param>
+ /// <param name="stringbuilder"></param>
+ /// <param name="rest"></param>
+ /// <param name="formatProvider"></param>
+ /// <returns>True if collection was shown completely</returns>
+ public static bool ShowCollectionValue<T>(ICollectionValue<T> items, StringBuilder stringbuilder, ref int rest, IFormatProvider formatProvider)
+ {
+ string startdelim = "{ ", enddelim = " }";
+ bool showIndexes = false;
+ bool showMultiplicities = false;
+ //TODO: do not test here at run time, but select code at compile time
+ // perhaps by delivering the print type to this metod
+ if (items is IList<T>)
+ {
+ startdelim = "[ ";
+ enddelim = " ]";
+ //TODO: should have been (items as IIndexed<T>).IndexingSpeed
+ showIndexes = (items as IList<T>).IndexingSpeed == Speed.Constant;
+ }
+ else if (items is ICollection<T>)
+ {
+ ICollection<T> coll = items as ICollection<T>;
+ if (coll.AllowsDuplicates)
+ {
+ startdelim = "{{ ";
+ enddelim = " }}";
+ if (coll.DuplicatesByCounting)
+ showMultiplicities = true;
+ }
+ }
+
+ stringbuilder.Append(startdelim);
+ rest -= 2 * startdelim.Length;
+ bool first = true;
+ bool complete = true;
+ int index = 0;
+
+ if (showMultiplicities)
+ {
+ foreach (KeyValuePair<T, int> p in (items as ICollection<T>).ItemMultiplicities())
+ {
+ complete = false;
+ if (rest <= 0)
+ break;
+ if (first)
+ first = false;
+ else
+ {
+ stringbuilder.Append(", ");
+ rest -= 2;
+ }
+ if (complete = Showing.Show(p.Key, stringbuilder, ref rest, formatProvider))
+ {
+ string multiplicityString = string.Format("(*{0})", p.Value);
+ stringbuilder.Append(multiplicityString);
+ rest -= multiplicityString.Length;
+ }
+ }
+ }
+ else
+ {
+ foreach (T x in items)
+ {
+ complete = false;
+ if (rest <= 0)
+ break;
+ if (first)
+ first = false;
+ else
+ {
+ stringbuilder.Append(", ");
+ rest -= 2;
+ }
+ if (showIndexes)
+ {
+ string indexString = string.Format("{0}:", index++);
+ stringbuilder.Append(indexString);
+ rest -= indexString.Length;
+ }
+ complete = Showing.Show(x, stringbuilder, ref rest, formatProvider);
+ }
+ }
+ if (!complete)
+ {
+ stringbuilder.Append("...");
+ rest -= 3;
+ }
+ stringbuilder.Append(enddelim);
+ return complete;
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <typeparam name="K"></typeparam>
+ /// <typeparam name="V"></typeparam>
+ ///
+ /// <param name="dictionary"></param>
+ /// <param name="stringbuilder"></param>
+ /// <param name="formatProvider"></param>
+ /// <param name="rest"></param>
+ /// <returns></returns>
+ public static bool ShowDictionary<K, V>(IDictionary<K, V> dictionary, StringBuilder stringbuilder, ref int rest, IFormatProvider formatProvider)
+ {
+ bool sorted = dictionary is ISortedDictionary<K, V>;
+ stringbuilder.Append(sorted ? "[ " : "{ ");
+ rest -= 4; // Account for "( " and " )"
+ bool first = true;
+ bool complete = true;
+
+ foreach (KeyValuePair<K, V> p in dictionary)
+ {
+ complete = false;
+ if (rest <= 0)
+ break;
+ if (first)
+ first = false;
+ else
+ {
+ stringbuilder.Append(", ");
+ rest -= 2;
+ }
+ complete = Showing.Show(p, stringbuilder, ref rest, formatProvider);
+ }
+ if (!complete)
+ {
+ stringbuilder.Append("...");
+ rest -= 3;
+ }
+ stringbuilder.Append(sorted ? " ]" : " }");
+ return complete;
+ }
+ }
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/C5/Hashers.cs b/mcs/class/Mono.C5/C5/Hashers.cs
new file mode 100644
index 00000000000..70778c57e0c
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/Hashers.cs
@@ -0,0 +1,489 @@
+/*
+ Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+using C5;
+using System;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Diagnostics;
+using SCG = System.Collections.Generic;
+
+namespace C5
+{
+ /// <summary>
+ /// Utility class for building default generic equalityComparers.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ public static class EqualityComparer<T>
+ {
+ readonly static Type isequenced = typeof(ISequenced<>);
+
+ readonly static Type icollection = typeof(ICollection<>);
+
+ readonly static Type orderedcollectionequalityComparer = typeof(SequencedCollectionEqualityComparer<,>);
+
+ readonly static Type unorderedcollectionequalityComparer = typeof(UnsequencedCollectionEqualityComparer<,>);
+
+ readonly static Type equalityequalityComparer = typeof(EquatableEqualityComparer<>);
+
+ readonly static Type iequalitytype = typeof(IEquatable<T>);
+
+ static SCG.IEqualityComparer<T> cachedDefault = null;
+
+ //TODO: find the right word for initialized+invocation
+ /// <summary>
+ /// A default generic equalityComparer for type T. The procedure is as follows:
+ /// <list>
+ /// <item>If T is int, double, byte or char,
+ /// the equalityComparer will be a standard equalityComparer for that type</item>
+ /// <item>If the actual generic argument T implements the generic interface
+ /// <see cref="T:C5.ISequenced`1"/> for some value W of its generic parameter T,
+ /// the equalityComparer will be <see cref="T:C5.SequencedCollectionEqualityComparer`2"/></item>
+ /// <item>If the actual generic argument T implements
+ /// <see cref="T:C5.ICollectionValue`1"/> for some value W of its generic parameter T,
+ /// the equalityComparer will be <see cref="T:C5.UnsequencedCollectionEqualityComparer`2"/></item>
+ /// <item>If T is a type implementing <see cref="T:C5.IEquatable`1"/>, the equalityComparer
+ /// will be <see cref="T:C5.EquatableEqualityComparer`1"/></item>
+ /// <item>If T is a type not implementing <see cref="T:C5.IEquatable`1"/>, the equalityComparer
+ /// will be <see cref="T:C5.NaturalEqualityComparer`1"/> </item>
+ /// </list>
+ /// The <see cref="T:C5.IEqualityComparer`1"/> object is constructed when this class is initialised, i.e.
+ /// its static constructors called. Thus, the property will be the same object
+ /// for the duration of an invocation of the runtime, but a value serialized in
+ /// another invocation and deserialized here will not be the same object.
+ /// </summary>
+ /// <value></value>
+ public static SCG.IEqualityComparer<T> Default
+ {
+ get
+ {
+ if (cachedDefault != null)
+ return cachedDefault;
+
+ Type t = typeof(T);
+
+ if (t.IsValueType)
+ {
+ if (t.Equals(typeof(int)))
+ return cachedDefault = (SCG.IEqualityComparer<T>)(IntEqualityComparer.Default);
+ else if (t.Equals(typeof(double)))
+ return cachedDefault = (SCG.IEqualityComparer<T>)(DoubleEqualityComparer.Default);
+ else if (t.Equals(typeof(byte)))
+ return cachedDefault = (SCG.IEqualityComparer<T>)(ByteEqualityComparer.Default);
+ else if (t.Equals(typeof(char)))
+ return cachedDefault = (SCG.IEqualityComparer<T>)(CharEqualityComparer.Default);
+ }
+ Type[] interfaces = t.GetInterfaces();
+ if (t.IsGenericType && t.GetGenericTypeDefinition().Equals(isequenced))
+ return createAndCache(orderedcollectionequalityComparer.MakeGenericType(new Type[] { t, t.GetGenericArguments()[0] }));
+ foreach (Type ty in interfaces)
+ {
+ if (ty.IsGenericType && ty.GetGenericTypeDefinition().Equals(isequenced))
+ return createAndCache(orderedcollectionequalityComparer.MakeGenericType(new Type[] { t, ty.GetGenericArguments()[0] }));
+ }
+ if (t.IsGenericType && t.GetGenericTypeDefinition().Equals(icollection))
+ return createAndCache(unorderedcollectionequalityComparer.MakeGenericType(new Type[] { t, t.GetGenericArguments()[0] }));
+ foreach (Type ty in interfaces)
+ {
+ if (ty.IsGenericType && ty.GetGenericTypeDefinition().Equals(icollection))
+ return createAndCache(unorderedcollectionequalityComparer.MakeGenericType(new Type[] { t, ty.GetGenericArguments()[0] }));
+ }
+ if (iequalitytype.IsAssignableFrom(t))
+ return createAndCache(equalityequalityComparer.MakeGenericType(new Type[] { t }));
+ else
+ return cachedDefault = NaturalEqualityComparer<T>.Default;
+ }
+ }
+ static SCG.IEqualityComparer<T> createAndCache(Type equalityComparertype)
+ {
+ return cachedDefault = (SCG.IEqualityComparer<T>)(equalityComparertype.GetProperty("Default", BindingFlags.Static | BindingFlags.Public).GetValue(null, null));
+ }
+ }
+
+ /// <summary>
+ /// A default item equalityComparer calling through to
+ /// the GetHashCode and Equals methods inherited from System.Object.
+ /// </summary>
+ public sealed class NaturalEqualityComparer<T> : SCG.IEqualityComparer<T>
+ {
+ static NaturalEqualityComparer<T> cached;
+ NaturalEqualityComparer() { }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public static NaturalEqualityComparer<T> Default { get { return cached ?? (cached = new NaturalEqualityComparer<T>()); } }
+ //TODO: check if null check is reasonable
+ //Answer: if we have struct C<T> { T t; int i;} and implement GetHashCode as
+ //the sum of hashcodes, and T may be any type, we cannot make the null check
+ //inside the definition of C<T> in a reasonable way.
+ /// <summary>
+ /// Get the hash code with respect to this item equalityComparer
+ /// </summary>
+ /// <param name="item">The item</param>
+ /// <returns>The hash code</returns>
+ [Tested]
+ public int GetHashCode(T item) { return item == null ? 0 : item.GetHashCode(); }
+
+
+ /// <summary>
+ /// Check if two items are equal with respect to this item equalityComparer
+ /// </summary>
+ /// <param name="item1">first item</param>
+ /// <param name="item2">second item</param>
+ /// <returns>True if equal</returns>
+ [Tested]
+ public bool Equals(T item1, T item2)
+ {
+ return item1 == null ? item2 == null : item1.Equals(item2);
+ }
+ }
+
+ /// <summary>
+ /// A default equalityComparer for a type, T, implementing <see cref="T:C5.IEquatable`1"/>.
+ ///
+ /// The equalityComparer forwards calls to GetHashCode and Equals to the methods
+ /// on T. The point is that it is Equals(T) and not Equals(object)
+ /// that is called. This will save a boxing/unboxing pair if T is a value type
+ /// and in general a runtime type check.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ public class EquatableEqualityComparer<T> : SCG.IEqualityComparer<T> where T : IEquatable<T>
+ {
+ static EquatableEqualityComparer<T> cached = new EquatableEqualityComparer<T>();
+ EquatableEqualityComparer() { }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public static EquatableEqualityComparer<T> Default { get { return cached ?? (cached = new EquatableEqualityComparer<T>()); } }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public int GetHashCode(T item) { return item == null ? 0 : item.GetHashCode(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item1"></param>
+ /// <param name="item2"></param>
+ /// <returns></returns>
+ public bool Equals(T item1, T item2) { return item1 == null ? item2 == null : item1.Equals(item2); }
+ }
+
+ /// <summary>
+ /// A equalityComparer for a reference type that uses reference equality for equality and the hash code from object as hash code.
+ /// </summary>
+ /// <typeparam name="T">The item type. Must be a reference type.</typeparam>
+ public class ReferenceEqualityComparer<T> : SCG.IEqualityComparer<T> where T : class
+ {
+ static ReferenceEqualityComparer<T> cached;
+ ReferenceEqualityComparer() { }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public static ReferenceEqualityComparer<T> Default { get { return cached ?? (cached = new ReferenceEqualityComparer<T>()); } }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public int GetHashCode(T item)
+ {
+ return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(item);
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="i1"></param>
+ /// <param name="i2"></param>
+ /// <returns></returns>
+ public bool Equals(T i1, T i2)
+ {
+ return object.ReferenceEquals(i1, i2);
+ }
+ }
+
+ /// <summary>
+ /// An equalityComparer compatible with a given comparer. All hash codes are 0,
+ /// meaning that anything based on hash codes will be quite inefficient.
+ /// <para><b>Note: this will give a new EqualityComparer each time created!</b></para>
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ public class ComparerZeroHashCodeEqualityComparer<T> : SCG.IEqualityComparer<T>
+ {
+ SCG.IComparer<T> comparer;
+ /// <summary>
+ /// Create a trivial <see cref="T:C5.IEqualityComparer`1"/> compatible with the
+ /// <see cref="T:C5.IComparer`1"/> <code>comparer</code>
+ /// </summary>
+ /// <param name="comparer"></param>
+ public ComparerZeroHashCodeEqualityComparer(SCG.IComparer<T> comparer)
+ {
+ if (comparer == null)
+ throw new NullReferenceException("Compaer cannot be null");
+ this.comparer = comparer;
+ }
+ /// <summary>
+ /// A trivial, inefficient hash fuction. Compatible with any equality relation.
+ /// </summary>
+ /// <param name="item"></param>
+ /// <returns>0</returns>
+ public int GetHashCode(T item) { return 0; }
+ /// <summary>
+ /// Equality of two items as defined by the comparer.
+ /// </summary>
+ /// <param name="item1"></param>
+ /// <param name="item2"></param>
+ /// <returns></returns>
+ public bool Equals(T item1, T item2) { return comparer.Compare(item1, item2) == 0; }
+ }
+
+ /// <summary>
+ /// Prototype for an sequenced equalityComparer for something (T) that implements ISequenced[W]
+ /// This will use ISequenced[W] specific implementations of the equalityComparer operations
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <typeparam name="W"></typeparam>
+ public class SequencedCollectionEqualityComparer<T, W> : SCG.IEqualityComparer<T>
+ where T : ISequenced<W>
+ {
+ static SequencedCollectionEqualityComparer<T, W> cached;
+ SequencedCollectionEqualityComparer() { }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public static SequencedCollectionEqualityComparer<T, W> Default { get { return cached ?? (cached = new SequencedCollectionEqualityComparer<T, W>()); } }
+ /// <summary>
+ /// Get the hash code with respect to this sequenced equalityComparer
+ /// </summary>
+ /// <param name="collection">The collection</param>
+ /// <returns>The hash code</returns>
+ [Tested]
+ public int GetHashCode(T collection) { return collection.GetSequencedHashCode(); }
+
+
+ /// <summary>
+ /// Check if two items are equal with respect to this sequenced equalityComparer
+ /// </summary>
+ /// <param name="collection1">first collection</param>
+ /// <param name="collection2">second collection</param>
+ /// <returns>True if equal</returns>
+ [Tested]
+ public bool Equals(T collection1, T collection2) { return collection1 == null ? collection2 == null : collection1.SequencedEquals(collection2); }
+ }
+
+ /// <summary>
+ /// Prototype for an unsequenced equalityComparer for something (T) that implements ICollection[W]
+ /// This will use ICollection[W] specific implementations of the equalityComparer operations
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <typeparam name="W"></typeparam>
+ public class UnsequencedCollectionEqualityComparer<T, W> : SCG.IEqualityComparer<T>
+ where T : ICollection<W>
+ {
+ static UnsequencedCollectionEqualityComparer<T, W> cached;
+ UnsequencedCollectionEqualityComparer() { }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public static UnsequencedCollectionEqualityComparer<T, W> Default { get { return cached ?? (cached = new UnsequencedCollectionEqualityComparer<T, W>()); } }
+ /// <summary>
+ /// Get the hash code with respect to this unsequenced equalityComparer
+ /// </summary>
+ /// <param name="collection">The collection</param>
+ /// <returns>The hash code</returns>
+ [Tested]
+ public int GetHashCode(T collection) { return collection.GetUnsequencedHashCode(); }
+
+
+ /// <summary>
+ /// Check if two collections are equal with respect to this unsequenced equalityComparer
+ /// </summary>
+ /// <param name="collection1">first collection</param>
+ /// <param name="collection2">second collection</param>
+ /// <returns>True if equal</returns>
+ [Tested]
+ public bool Equals(T collection1, T collection2) { return collection1 == null ? collection2 == null : collection1.UnsequencedEquals(collection2); }
+ }
+
+}
+
+
+
+
+
+#if EXPERIMENTAL
+namespace C5.EqualityComparerBuilder
+{
+
+ /// <summary>
+ /// IEqualityComparer factory class: examines at instatiation time if T is an
+ /// interface implementing "int GetHashCode()" and "bool Equals(T)".
+ /// If those are not present, MakeEqualityComparer will return a default equalityComparer,
+ /// else this class will implement IequalityComparer[T] via Invoke() on the
+ /// reflected method infos.
+ /// </summary>
+ public class ByInvoke<T> : SCG.IEqualityComparer<T>
+ {
+ internal static readonly System.Reflection.MethodInfo hinfo, einfo;
+
+
+ static ByInvoke()
+ {
+ Type t = typeof(T);
+
+ if (!t.IsInterface) return;
+
+ BindingFlags f = BindingFlags.Public | BindingFlags.Instance;
+
+ hinfo = t.GetMethod("GetHashCode", f, null, new Type[0], null);
+ einfo = t.GetMethod("Equals", f, null, new Type[1] { t }, null);
+ }
+
+
+ private ByInvoke() { }
+
+/// <summary>
+///
+/// </summary>
+/// <returns></returns>
+ public static SCG.IEqualityComparer<T> MakeEqualityComparer()
+ {
+ if (hinfo != null && einfo != null)
+ return new ByInvoke<T>();
+ else
+ return NaturalEqualityComparer<T>.Default;
+ }
+
+/// <summary>
+///
+/// </summary>
+/// <param name="item"></param>
+/// <returns></returns>
+ public int GetHashCode(T item)
+ {
+ return (int)(hinfo.Invoke(item, null));
+ }
+
+/// <summary>
+///
+/// </summary>
+/// <param name="i1"></param>
+/// <param name="i2"></param>
+/// <returns></returns>
+ public bool Equals(T i1, T i2)
+ {
+ return (bool)(einfo.Invoke(i1, new object[1] { i2 }));
+ }
+ }
+
+
+
+ /// <summary>
+ /// Like ByInvoke, but tries to build a equalityComparer by RTCG to
+ /// avoid the Invoke() overhead.
+ /// </summary>
+ public class ByRTCG
+ {
+ private static ModuleBuilder moduleBuilder;
+
+ private static AssemblyBuilder assemblyBuilder;
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="hinfo"></param>
+ /// <param name="einfo"></param>
+ /// <returns></returns>
+ public static SCG.IEqualityComparer<T> CreateEqualityComparer<T>(MethodInfo hinfo, MethodInfo einfo)
+ {
+ if (moduleBuilder == null)
+ {
+ string assmname = "LeFake";
+ string filename = assmname + ".dll";
+ AssemblyName assemblyName = new AssemblyName("LeFake");
+ AppDomain appdomain = AppDomain.CurrentDomain;
+ AssemblyBuilderAccess acc = AssemblyBuilderAccess.RunAndSave;
+
+ assemblyBuilder = appdomain.DefineDynamicAssembly(assemblyName, acc);
+ moduleBuilder = assemblyBuilder.DefineDynamicModule(assmname, filename);
+ }
+
+ Type t = typeof(T);
+ Type o_t = typeof(object);
+ Type h_t = typeof(SCG.IEqualityComparer<T>);
+ Type i_t = typeof(int);
+ //TODO: protect uid for thread safety!
+ string name = "C5.Dynamic.EqualityComparer_" + Guid.NewGuid().ToString();
+ TypeAttributes tatt = TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed;
+ TypeBuilder tb = moduleBuilder.DefineType(name, tatt, o_t, new Type[1] { h_t });
+ MethodAttributes matt = MethodAttributes.Public | MethodAttributes.Virtual;
+ MethodBuilder mb = tb.DefineMethod("GetHashCode", matt, i_t, new Type[1] { t });
+ ILGenerator ilg = mb.GetILGenerator();
+
+ ilg.Emit(OpCodes.Ldarg_1);
+ ilg.Emit(OpCodes.Callvirt, hinfo);
+ ilg.Emit(OpCodes.Ret);
+ mb = tb.DefineMethod("Equals", matt, typeof(bool), new Type[2] { t, t });
+ ilg = mb.GetILGenerator();
+ ilg.Emit(OpCodes.Ldarg_1);
+ ilg.Emit(OpCodes.Ldarg_2);
+ ilg.Emit(OpCodes.Callvirt, einfo);
+ ilg.Emit(OpCodes.Ret);
+
+ Type equalityComparer_t = tb.CreateType();
+ object equalityComparer = equalityComparer_t.GetConstructor(new Type[0]).Invoke(null);
+
+ return (SCG.IEqualityComparer<T>)equalityComparer;
+ }
+
+/// <summary>
+///
+/// </summary>
+/// <typeparam name="T"></typeparam>
+/// <returns></returns>
+ public static SCG.IEqualityComparer<T> build<T>()
+ {
+ MethodInfo hinfo = ByInvoke<T>.hinfo, einfo = ByInvoke<T>.einfo;
+
+ if (hinfo != null && einfo != null)
+ return CreateEqualityComparer<T>(hinfo, einfo);
+ else
+ return EqualityComparer<T>.Default;
+ }
+
+/// <summary>
+///
+/// </summary>
+ public void dump()
+ {
+ assemblyBuilder.Save("LeFake.dll");
+ }
+ }
+}
+#endif
diff --git a/mcs/class/Mono.C5/C5/Interfaces.cs b/mcs/class/Mono.C5/C5/Interfaces.cs
new file mode 100644
index 00000000000..3ae5abe85d4
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/Interfaces.cs
@@ -0,0 +1,1884 @@
+/*
+ Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+using System;
+using SCG = System.Collections.Generic;
+namespace C5
+{
+ /// <summary>
+ /// A generic collection, that can be enumerated backwards.
+ /// </summary>
+ public interface IDirectedEnumerable<T> : SCG.IEnumerable<T>
+ {
+ /// <summary>
+ /// Create a collection containing the same items as this collection, but
+ /// whose enumerator will enumerate the items backwards. The new collection
+ /// will become invalid if the original is modified. Method typically used as in
+ /// <code>foreach (T x in coll.Backwards()) {...}</code>
+ /// </summary>
+ /// <returns>The backwards collection.</returns>
+ IDirectedEnumerable<T> Backwards();
+
+
+ /// <summary>
+ /// <code>Forwards</code> if same, else <code>Backwards</code>
+ /// </summary>
+ /// <value>The enumeration direction relative to the original collection.</value>
+ EnumerationDirection Direction { get;}
+ }
+
+ /// <summary>
+ /// A generic collection that may be enumerated and can answer
+ /// efficiently how many items it contains. Like <code>IEnumerable&lt;T&gt;</code>,
+ /// this interface does not prescribe any operations to initialize or update the
+ /// collection. The main usage for this interface is to be the return type of
+ /// query operations on generic collection.
+ /// </summary>
+ public interface ICollectionValue<T> : SCG.IEnumerable<T>, IShowable
+ {
+ /// <summary>
+ /// A flag bitmap of the events subscribable to by this collection.
+ /// </summary>
+ /// <value></value>
+ EventTypeEnum ListenableEvents { get;}
+
+ /// <summary>
+ /// A flag bitmap of the events currently subscribed to by this collection.
+ /// </summary>
+ /// <value></value>
+ EventTypeEnum ActiveEvents { get;}
+
+ /// <summary>
+ /// The change event. Will be raised for every change operation on the collection.
+ /// </summary>
+ event CollectionChangedHandler<T> CollectionChanged;
+
+ /// <summary>
+ /// The change event. Will be raised for every clear operation on the collection.
+ /// </summary>
+ event CollectionClearedHandler<T> CollectionCleared;
+
+ /// <summary>
+ /// The item added event. Will be raised for every individual addition to the collection.
+ /// </summary>
+ event ItemsAddedHandler<T> ItemsAdded;
+
+ /// <summary>
+ /// The item inserted event. Will be raised for every individual insertion to the collection.
+ /// </summary>
+ event ItemInsertedHandler<T> ItemInserted;
+
+ /// <summary>
+ /// The item removed event. Will be raised for every individual removal from the collection.
+ /// </summary>
+ event ItemsRemovedHandler<T> ItemsRemoved;
+
+ /// <summary>
+ /// The item removed at event. Will be raised for every individual removal at from the collection.
+ /// </summary>
+ event ItemRemovedAtHandler<T> ItemRemovedAt;
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>True if this collection is empty.</value>
+ bool IsEmpty { get;}
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>The number of items in this collection</value>
+ int Count { get;}
+
+ /// <summary>
+ /// The value is symbolic indicating the type of asymptotic complexity
+ /// in terms of the size of this collection (worst-case or amortized as
+ /// relevant).
+ /// </summary>
+ /// <value>A characterization of the speed of the
+ /// <code>Count</code> property in this collection.</value>
+ Speed CountSpeed { get;}
+
+ /// <summary>
+ /// Copy the items of this collection to a contiguous part of an array.
+ /// </summary>
+ /// <param name="array">The array to copy to</param>
+ /// <param name="index">The index at which to copy the first item</param>
+ void CopyTo(T[] array, int index);
+
+ /// <summary>
+ /// Create an array with the items of this collection (in the same order as an
+ /// enumerator would output them).
+ /// </summary>
+ /// <returns>The array</returns>
+ T[] ToArray();
+
+ /// <summary>
+ /// Apply a delegate to all items of this collection.
+ /// </summary>
+ /// <param name="action">The delegate to apply</param>
+ void Apply(Act<T> action);
+
+
+ /// <summary>
+ /// Check if there exists an item that satisfies a
+ /// specific predicate in this collection.
+ /// </summary>
+ /// <param name="predicate">A delegate
+ /// (<see cref="T:C5.Fun`2"/> with <code>R == bool</code>) defining the predicate</param>
+ /// <returns>True is such an item exists</returns>
+ bool Exists(Fun<T, bool> predicate);
+
+ /// <summary>
+ /// Check if there exists an item that satisfies a
+ /// specific predicate in this collection and return the first one in enumeration order.
+ /// </summary>
+ /// <param name="predicate">A delegate
+ /// (<see cref="T:C5.Fun`2"/> with <code>R == bool</code>) defining the predicate</param>
+ /// <param name="item"></param>
+ /// <returns>True is such an item exists</returns>
+ bool Find(Fun<T, bool> predicate, out T item);
+
+
+ /// <summary>
+ /// Check if all items in this collection satisfies a specific predicate.
+ /// </summary>
+ /// <param name="predicate">A delegate
+ /// (<see cref="T:C5.Fun`2"/> with <code>R == bool</code>) defining the predicate</param>
+ /// <returns>True if all items satisfies the predicate</returns>
+ bool All(Fun<T, bool> predicate);
+
+ /// <summary>
+ /// Choose some item of this collection.
+ /// <para>Implementations must assure that the item
+ /// returned may be efficiently removed.</para>
+ /// <para>Implementors may decide to implement this method in a way such that repeated
+ /// calls do not necessarily give the same result, i.e. so that the result of the following
+ /// test is undetermined:
+ /// <code>coll.Choose() == coll.Choose()</code></para>
+ /// </summary>
+ /// <exception cref="NoSuchItemException">if collection is empty.</exception>
+ /// <returns></returns>
+ T Choose();
+
+ /// <summary>
+ /// Create an enumerable, enumerating the items of this collection that satisfies
+ /// a certain condition.
+ /// </summary>
+ /// <param name="filter">The T->bool filter delegate defining the condition</param>
+ /// <returns>The filtered enumerable</returns>
+ SCG.IEnumerable<T> Filter(Fun<T, bool> filter);
+ }
+
+
+
+ /// <summary>
+ /// A sized generic collection, that can be enumerated backwards.
+ /// </summary>
+ public interface IDirectedCollectionValue<T> : ICollectionValue<T>, IDirectedEnumerable<T>
+ {
+ /// <summary>
+ /// Create a collection containing the same items as this collection, but
+ /// whose enumerator will enumerate the items backwards. The new collection
+ /// will become invalid if the original is modified. Method typically used as in
+ /// <code>foreach (T x in coll.Backwards()) {...}</code>
+ /// </summary>
+ /// <returns>The backwards collection.</returns>
+ new IDirectedCollectionValue<T> Backwards();
+
+ /// <summary>
+ /// Check if there exists an item that satisfies a
+ /// specific predicate in this collection and return the first one in enumeration order.
+ /// </summary>
+ /// <param name="predicate">A delegate
+ /// (<see cref="T:C5.Fun`2"/> with <code>R == bool</code>) defining the predicate</param>
+ /// <param name="item"></param>
+ /// <returns>True is such an item exists</returns>
+ bool FindLast(Fun<T, bool> predicate, out T item);
+ }
+
+
+ /// <summary>
+ /// A generic collection to which one may add items. This is just the intersection
+ /// of the main stream generic collection interfaces and the priority queue interface,
+ /// <see cref="T:C5.ICollection`1"/> and <see cref="T:C5.IPriorityQueue`1"/>.
+ /// </summary>
+ public interface IExtensible<T> : ICollectionValue<T>, ICloneable
+ {
+ /// <summary>
+ /// If true any call of an updating operation will throw an
+ /// <code>ReadOnlyCollectionException</code>
+ /// </summary>
+ /// <value>True if this collection is read-only.</value>
+ bool IsReadOnly { get;}
+
+ //TODO: wonder where the right position of this is
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>False if this collection has set semantics, true if bag semantics.</value>
+ bool AllowsDuplicates { get;}
+
+ //TODO: wonder where the right position of this is. And the semantics.
+ /// <summary>
+ /// (Here should be a discussion of the role of equalityComparers. Any ).
+ /// </summary>
+ /// <value>The equalityComparer used by this collection to check equality of items.
+ /// Or null (????) if collection does not check equality at all or uses a comparer.</value>
+ SCG.IEqualityComparer<T> EqualityComparer { get;}
+
+ //ItemEqualityTypeEnum ItemEqualityType {get ;}
+
+ //TODO: find a good name
+
+ /// <summary>
+ /// By convention this is true for any collection with set semantics.
+ /// </summary>
+ /// <value>True if only one representative of a group of equal items
+ /// is kept in the collection together with the total count.</value>
+ bool DuplicatesByCounting { get;}
+
+ /// <summary>
+ /// Add an item to this collection if possible. If this collection has set
+ /// semantics, the item will be added if not already in the collection. If
+ /// bag semantics, the item will always be added.
+ /// </summary>
+ /// <param name="item">The item to add.</param>
+ /// <returns>True if item was added.</returns>
+ bool Add(T item);
+
+ /// <summary>
+ /// Add the elements from another collection with a more specialized item type
+ /// to this collection. If this
+ /// collection has set semantics, only items not already in the collection
+ /// will be added.
+ /// </summary>
+ /// <typeparam name="U">The type of items to add</typeparam>
+ /// <param name="items">The items to add</param>
+ void AddAll<U>(SCG.IEnumerable<U> items) where U : T;
+
+ //void Clear(); // for priority queue
+ //int Count why not?
+ /// <summary>
+ /// Check the integrity of the internal data structures of this collection.
+ /// <i>This is only relevant for developers of the library</i>
+ /// </summary>
+ /// <returns>True if check was passed.</returns>
+ bool Check();
+ }
+
+ /// <summary>
+ /// The simplest interface of a main stream generic collection
+ /// with lookup, insertion and removal operations.
+ /// </summary>
+ public interface ICollection<T> : IExtensible<T>
+ {
+ //This is somewhat similar to the RandomAccess marker itf in java
+ /// <summary>
+ /// The value is symbolic indicating the type of asymptotic complexity
+ /// in terms of the size of this collection (worst-case or amortized as
+ /// relevant).
+ /// <para>See <see cref="T:C5.Speed"/> for the set of symbols.</para>
+ /// </summary>
+ /// <value>A characterization of the speed of lookup operations
+ /// (<code>Contains()</code> etc.) of the implementation of this collection.</value>
+ Speed ContainsSpeed { get;}
+
+ /// <summary>
+ /// The unordered collection hashcode is defined as the sum of
+ /// <code>h(hashcode(item))</code> over the items
+ /// of the collection, where the function <code>h</code> is a function from
+ /// int to int of the form <code> t -> (a0*t+b0)^(a1*t+b1)^(a2*t+b2)</code>, where
+ /// the ax and bx are the same for all collection classes.
+ /// <para>The current implementation uses fixed values for the ax and bx,
+ /// specified as constants in the code.</para>
+ /// </summary>
+ /// <returns>The unordered hashcode of this collection.</returns>
+ int GetUnsequencedHashCode();
+
+
+ /// <summary>
+ /// Compare the contents of this collection to another one without regards to
+ /// the sequence order. The comparison will use this collection's itemequalityComparer
+ /// to compare individual items.
+ /// </summary>
+ /// <param name="otherCollection">The collection to compare to.</param>
+ /// <returns>True if this collection and that contains the same items.</returns>
+ bool UnsequencedEquals(ICollection<T> otherCollection);
+
+
+ /// <summary>
+ /// Check if this collection contains (an item equivalent to according to the
+ /// itemequalityComparer) a particular value.
+ /// </summary>
+ /// <param name="item">The value to check for.</param>
+ /// <returns>True if the items is in this collection.</returns>
+ bool Contains(T item);
+
+
+ /// <summary>
+ /// Count the number of items of the collection equal to a particular value.
+ /// Returns 0 if and only if the value is not in the collection.
+ /// </summary>
+ /// <param name="item">The value to count.</param>
+ /// <returns>The number of copies found.</returns>
+ int ContainsCount(T item);
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ ICollectionValue<T> UniqueItems();
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ ICollectionValue<KeyValuePair<T, int>> ItemMultiplicities();
+
+ /// <summary>
+ /// Check whether this collection contains all the values in another collection.
+ /// If this collection has bag semantics (<code>AllowsDuplicates==true</code>)
+ /// the check is made with respect to multiplicities, else multiplicities
+ /// are not taken into account.
+ /// </summary>
+ /// <param name="items">The </param>
+ /// <typeparam name="U"></typeparam>
+ /// <returns>True if all values in <code>items</code>is in this collection.</returns>
+ bool ContainsAll<U>(SCG.IEnumerable<U> items) where U : T;
+
+
+ /// <summary>
+ /// Check if this collection contains an item equivalent according to the
+ /// itemequalityComparer to a particular value. If so, return in the ref argument (a
+ /// binary copy of) the actual value found.
+ /// </summary>
+ /// <param name="item">The value to look for.</param>
+ /// <returns>True if the items is in this collection.</returns>
+ bool Find(ref T item);
+
+
+ //This should probably just be bool Add(ref T item); !!!
+ /// <summary>
+ /// Check if this collection contains an item equivalent according to the
+ /// itemequalityComparer to a particular value. If so, return in the ref argument (a
+ /// binary copy of) the actual value found. Else, add the item to the collection.
+ /// </summary>
+ /// <param name="item">The value to look for.</param>
+ /// <returns>True if the item was found (hence not added).</returns>
+ bool FindOrAdd(ref T item);
+
+
+ /// <summary>
+ /// Check if this collection contains an item equivalent according to the
+ /// itemequalityComparer to a particular value. If so, update the item in the collection
+ /// with a (binary copy of) the supplied value. If the collection has bag semantics,
+ /// it depends on the value of DuplicatesByCounting if this updates all equivalent copies in
+ /// the collection or just one.
+ /// </summary>
+ /// <param name="item">Value to update.</param>
+ /// <returns>True if the item was found and hence updated.</returns>
+ bool Update(T item);
+
+ /// <summary>
+ /// Check if this collection contains an item equivalent according to the
+ /// itemequalityComparer to a particular value. If so, update the item in the collection
+ /// with a (binary copy of) the supplied value. If the collection has bag semantics,
+ /// it depends on the value of DuplicatesByCounting if this updates all equivalent copies in
+ /// the collection or just one.
+ /// </summary>
+ /// <param name="item">Value to update.</param>
+ /// <param name="olditem">On output the olditem, if found.</param>
+ /// <returns>True if the item was found and hence updated.</returns>
+ bool Update(T item, out T olditem);
+
+
+ /// <summary>
+ /// Check if this collection contains an item equivalent according to the
+ /// itemequalityComparer to a particular value. If so, update the item in the collection
+ /// to with a binary copy of the supplied value; else add the value to the collection.
+ /// </summary>
+ /// <param name="item">Value to add or update.</param>
+ /// <returns>True if the item was found and updated (hence not added).</returns>
+ bool UpdateOrAdd(T item);
+
+
+ /// <summary>
+ /// Check if this collection contains an item equivalent according to the
+ /// itemequalityComparer to a particular value. If so, update the item in the collection
+ /// to with a binary copy of the supplied value; else add the value to the collection.
+ /// </summary>
+ /// <param name="item">Value to add or update.</param>
+ /// <param name="olditem">On output the olditem, if found.</param>
+ /// <returns>True if the item was found and updated (hence not added).</returns>
+ bool UpdateOrAdd(T item, out T olditem);
+
+ /// <summary>
+ /// Remove a particular item from this collection. If the collection has bag
+ /// semantics only one copy equivalent to the supplied item is removed.
+ /// </summary>
+ /// <param name="item">The value to remove.</param>
+ /// <returns>True if the item was found (and removed).</returns>
+ bool Remove(T item);
+
+
+ /// <summary>
+ /// Remove a particular item from this collection if found. If the collection
+ /// has bag semantics only one copy equivalent to the supplied item is removed,
+ /// which one is implementation dependent.
+ /// If an item was removed, report a binary copy of the actual item removed in
+ /// the argument.
+ /// </summary>
+ /// <param name="item">The value to remove.</param>
+ /// <param name="removeditem">The value removed if any.</param>
+ /// <returns>True if the item was found (and removed).</returns>
+ bool Remove(T item, out T removeditem);
+
+
+ /// <summary>
+ /// Remove all items equivalent to a given value.
+ /// </summary>
+ /// <param name="item">The value to remove.</param>
+ void RemoveAllCopies(T item);
+
+
+ /// <summary>
+ /// Remove all items in another collection from this one. If this collection
+ /// has bag semantics, take multiplicities into account.
+ /// </summary>
+ /// <typeparam name="U"></typeparam>
+ /// <param name="items">The items to remove.</param>
+ void RemoveAll<U>(SCG.IEnumerable<U> items) where U : T;
+
+ //void RemoveAll(Fun<T, bool> predicate);
+
+ /// <summary>
+ /// Remove all items from this collection.
+ /// </summary>
+ void Clear();
+
+
+ /// <summary>
+ /// Remove all items not in some other collection from this one. If this collection
+ /// has bag semantics, take multiplicities into account.
+ /// </summary>
+ /// <typeparam name="U"></typeparam>
+ /// <param name="items">The items to retain.</param>
+ void RetainAll<U>(SCG.IEnumerable<U> items) where U : T;
+
+ //void RetainAll(Fun<T, bool> predicate);
+ //IDictionary<T> UniqueItems()
+ }
+
+
+
+ /// <summary>
+ /// An editable collection maintaining a definite sequence order of the items.
+ ///
+ /// <i>Implementations of this interface must compute the hash code and
+ /// equality exactly as prescribed in the method definitions in order to
+ /// be consistent with other collection classes implementing this interface.</i>
+ /// <i>This interface is usually implemented by explicit interface implementation,
+ /// not as ordinary virtual methods.</i>
+ /// </summary>
+ public interface ISequenced<T> : ICollection<T>, IDirectedCollectionValue<T>
+ {
+ /// <summary>
+ /// The hashcode is defined as <code>h(...h(h(h(x1),x2),x3),...,xn)</code> for
+ /// <code>h(a,b)=CONSTANT*a+b</code> and the x's the hash codes of the items of
+ /// this collection.
+ /// </summary>
+ /// <returns>The sequence order hashcode of this collection.</returns>
+ int GetSequencedHashCode();
+
+
+ /// <summary>
+ /// Compare this sequenced collection to another one in sequence order.
+ /// </summary>
+ /// <param name="otherCollection">The sequenced collection to compare to.</param>
+ /// <returns>True if this collection and that contains equal (according to
+ /// this collection's itemequalityComparer) in the same sequence order.</returns>
+ bool SequencedEquals(ISequenced<T> otherCollection);
+ }
+
+
+
+ /// <summary>
+ /// A sequenced collection, where indices of items in the order are maintained
+ /// </summary>
+ public interface IIndexed<T> : ISequenced<T>
+ {
+ /// <summary>
+ /// </summary>
+ /// <exception cref="IndexOutOfRangeException"> if <code>index</code> is negative or
+ /// &gt;= the size of the collection.</exception>
+ /// <value>The <code>index</code>'th item of this list.</value>
+ /// <param name="index">the index to lookup</param>
+ T this[int index] { get;}
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ Speed IndexingSpeed { get;}
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException"></exception>
+ /// <value>The directed collection of items in a specific index interval.</value>
+ /// <param name="start">The low index of the interval (inclusive).</param>
+ /// <param name="count">The size of the range.</param>
+ IDirectedCollectionValue<T> this[int start, int count] { get;}
+
+
+ /// <summary>
+ /// Searches for an item in the list going forwards from the start.
+ /// </summary>
+ /// <param name="item">Item to search for.</param>
+ /// <returns>Index of item from start. A negative number if item not found,
+ /// namely the two-complement of the index at which the Add operation would put the item.</returns>
+ int IndexOf(T item);
+
+
+ /// <summary>
+ /// Searches for an item in the list going backwards from the end.
+ /// </summary>
+ /// <param name="item">Item to search for.</param>
+ /// <returns>Index of of item from the end. A negative number if item not found,
+ /// namely the two-complement of the index at which the Add operation would put the item.</returns>
+ int LastIndexOf(T item);
+
+ /// <summary>
+ /// Check if there exists an item that satisfies a
+ /// specific predicate in this collection and return the index of the first one.
+ /// </summary>
+ /// <param name="predicate">A delegate
+ /// (<see cref="T:C5.Fun`2"/> with <code>R == bool</code>) defining the predicate</param>
+ /// <returns>the index, if found, a negative value else</returns>
+ int FindIndex(Fun<T, bool> predicate);
+
+ /// <summary>
+ /// Check if there exists an item that satisfies a
+ /// specific predicate in this collection and return the index of the last one.
+ /// </summary>
+ /// <param name="predicate">A delegate
+ /// (<see cref="T:C5.Fun`2"/> with <code>R == bool</code>) defining the predicate</param>
+ /// <returns>the index, if found, a negative value else</returns>
+ int FindLastIndex(Fun<T, bool> predicate);
+
+
+ /// <summary>
+ /// Remove the item at a specific position of the list.
+ /// </summary>
+ /// <exception cref="IndexOutOfRangeException"> if <code>index</code> is negative or
+ /// &gt;= the size of the collection.</exception>
+ /// <param name="index">The index of the item to remove.</param>
+ /// <returns>The removed item.</returns>
+ T RemoveAt(int index);
+
+
+ /// <summary>
+ /// Remove all items in an index interval.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException"> if start or count
+ /// is negative or start+count &gt; the size of the collection.</exception>
+ /// <param name="start">The index of the first item to remove.</param>
+ /// <param name="count">The number of items to remove.</param>
+ void RemoveInterval(int start, int count);
+ }
+
+ //TODO: decide if this should extend ICollection
+ /// <summary>
+ /// The interface describing the operations of a LIFO stack data structure.
+ /// </summary>
+ /// <typeparam name="T">The item type</typeparam>
+ public interface IStack<T> : IDirectedCollectionValue<T>
+ {
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ bool AllowsDuplicates { get;}
+ /// <summary>
+ /// Get the <code>index</code>'th element of the stack. The bottom of the stack has index 0.
+ /// </summary>
+ /// <param name="index"></param>
+ /// <returns></returns>
+ T this[int index] { get;}
+ /// <summary>
+ /// Push an item to the top of the stack.
+ /// </summary>
+ /// <param name="item">The item</param>
+ void Push(T item);
+ /// <summary>
+ /// Pop the item at the top of the stack from the stack.
+ /// </summary>
+ /// <returns>The popped item.</returns>
+ T Pop();
+ }
+
+ /// <summary>
+ /// The interface describing the operations of a FIFO queue data structure.
+ /// </summary>
+ /// <typeparam name="T">The item type</typeparam>
+ public interface IQueue<T> : IDirectedCollectionValue<T>
+ {
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ bool AllowsDuplicates { get;}
+ /// <summary>
+ /// Get the <code>index</code>'th element of the queue. The front of the queue has index 0.
+ /// </summary>
+ /// <param name="index"></param>
+ /// <returns></returns>
+ T this[int index] { get;}
+ /// <summary>
+ /// Enqueue an item at the back of the queue.
+ /// </summary>
+ /// <param name="item">The item</param>
+ void Enqueue(T item);
+ /// <summary>
+ /// Dequeue an item from the front of the queue.
+ /// </summary>
+ /// <returns>The item</returns>
+ T Dequeue();
+ }
+
+
+ /// <summary>
+ /// This is an indexed collection, where the item order is chosen by
+ /// the user at insertion time.
+ ///
+ /// NBNBNB: we need a description of the view functionality here!
+ /// </summary>
+ public interface IList<T> : IIndexed<T>, IDisposable
+ {
+ /// <summary>
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if this list is empty.</exception>
+ /// <value>The first item in this list.</value>
+ T First { get;}
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if this list is empty.</exception>
+ /// <value>The last item in this list.</value>
+ T Last { get;}
+
+ /// <summary>
+ /// Since <code>Add(T item)</code> always add at the end of the list,
+ /// this describes if list has FIFO or LIFO semantics.
+ /// </summary>
+ /// <value>True if the <code>Remove()</code> operation removes from the
+ /// start of the list, false if it removes from the end.</value>
+ bool FIFO { get; set;}
+
+ /// <summary>
+ ///
+ /// </summary>
+ bool IsFixedSize { get; }
+
+ /// <summary>
+ /// On this list, this indexer is read/write.
+ /// </summary>
+ /// <exception cref="IndexOutOfRangeException"> if index is negative or
+ /// &gt;= the size of the collection.</exception>
+ /// <value>The index'th item of this list.</value>
+ /// <param name="index">The index of the item to fetch or store.</param>
+ new T this[int index] { get; set;}
+
+ /// <summary>
+ /// Insert an item at a specific index location in this list.
+ /// </summary>
+ /// <exception cref="IndexOutOfRangeException"> if <code>index</code> is negative or
+ /// &gt; the size of the collection.</exception>
+ /// <exception cref="DuplicateNotAllowedException"> if the list has
+ /// <code>AllowsDuplicates==false</code> and the item is
+ /// already in the list.</exception>
+ /// <param name="index">The index at which to insert.</param>
+ /// <param name="item">The item to insert.</param>
+ void Insert(int index, T item);
+
+ /// <summary>
+ /// Insert an item at the end of a compatible view, used as a pointer.
+ /// <para>The <code>pointer</code> must be a view on the same list as
+ /// <code>this</code> and the endpoitn of <code>pointer</code> must be
+ /// a valid insertion point of <code>this</code></para>
+ /// </summary>
+ /// <exception cref="IncompatibleViewException">If <code>pointer</code>
+ /// is not a view on the same list as <code>this</code></exception>
+ /// <exception cref="IndexOutOfRangeException"><b>??????</b> if the endpoint of
+ /// <code>pointer</code> is not inside <code>this</code></exception>
+ /// <exception cref="DuplicateNotAllowedException"> if the list has
+ /// <code>AllowsDuplicates==false</code> and the item is
+ /// already in the list.</exception>
+ /// <param name="pointer"></param>
+ /// <param name="item"></param>
+ void Insert(IList<T> pointer, T item);
+
+ /// <summary>
+ /// Insert an item at the front of this list.
+ /// <exception cref="DuplicateNotAllowedException"/> if the list has
+ /// <code>AllowsDuplicates==false</code> and the item is
+ /// already in the list.
+ /// </summary>
+ /// <param name="item">The item to insert.</param>
+ void InsertFirst(T item);
+
+ /// <summary>
+ /// Insert an item at the back of this list.
+ /// <exception cref="DuplicateNotAllowedException"/> if the list has
+ /// <code>AllowsDuplicates==false</code> and the item is
+ /// already in the list.
+ /// </summary>
+ /// <param name="item">The item to insert.</param>
+ void InsertLast(T item);
+
+ /// <summary>
+ /// Insert into this list all items from an enumerable collection starting
+ /// at a particular index.
+ /// </summary>
+ /// <exception cref="IndexOutOfRangeException"> if <code>index</code> is negative or
+ /// &gt; the size of the collection.</exception>
+ /// <exception cref="DuplicateNotAllowedException"> if the list has
+ /// <code>AllowsDuplicates==false</code> and one of the items to insert is
+ /// already in the list.</exception>
+ /// <param name="index">Index to start inserting at</param>
+ /// <param name="items">Items to insert</param>
+ /// <typeparam name="U"></typeparam>
+ void InsertAll<U>(int index, SCG.IEnumerable<U> items) where U : T;
+
+ /// <summary>
+ /// Create a new list consisting of the items of this list satisfying a
+ /// certain predicate.
+ /// </summary>
+ /// <param name="filter">The filter delegate defining the predicate.</param>
+ /// <returns>The new list.</returns>
+ IList<T> FindAll(Fun<T, bool> filter);
+
+ /// <summary>
+ /// Create a new list consisting of the results of mapping all items of this
+ /// list. The new list will use the default equalityComparer for the item type V.
+ /// </summary>
+ /// <typeparam name="V">The type of items of the new list</typeparam>
+ /// <param name="mapper">The delegate defining the map.</param>
+ /// <returns>The new list.</returns>
+ IList<V> Map<V>(Fun<T, V> mapper);
+
+ /// <summary>
+ /// Create a new list consisting of the results of mapping all items of this
+ /// list. The new list will use a specified equalityComparer for the item type.
+ /// </summary>
+ /// <typeparam name="V">The type of items of the new list</typeparam>
+ /// <param name="mapper">The delegate defining the map.</param>
+ /// <param name="equalityComparer">The equalityComparer to use for the new list</param>
+ /// <returns>The new list.</returns>
+ IList<V> Map<V>(Fun<T, V> mapper, SCG.IEqualityComparer<V> equalityComparer);
+
+ /// <summary>
+ /// Remove one item from the list: from the front if <code>FIFO</code>
+ /// is true, else from the back.
+ /// <exception cref="NoSuchItemException"/> if this list is empty.
+ /// </summary>
+ /// <returns>The removed item.</returns>
+ T Remove();
+
+ /// <summary>
+ /// Remove one item from the front of the list.
+ /// <exception cref="NoSuchItemException"/> if this list is empty.
+ /// </summary>
+ /// <returns>The removed item.</returns>
+ T RemoveFirst();
+
+ /// <summary>
+ /// Remove one item from the back of the list.
+ /// <exception cref="NoSuchItemException"/> if this list is empty.
+ /// </summary>
+ /// <returns>The removed item.</returns>
+ T RemoveLast();
+
+ /// <summary>
+ /// Create a list view on this list.
+ /// <exception cref="ArgumentOutOfRangeException"/> if the view would not fit into
+ /// this list.
+ /// </summary>
+ /// <param name="start">The index in this list of the start of the view.</param>
+ /// <param name="count">The size of the view.</param>
+ /// <returns>The new list view.</returns>
+ IList<T> View(int start, int count);
+
+ /// <summary>
+ /// Create a list view on this list containing the (first) occurrence of a particular item.
+ /// <exception cref="NoSuchItemException"/> if the item is not in this list.
+ /// </summary>
+ /// <param name="item">The item to find.</param>
+ /// <returns>The new list view.</returns>
+ IList<T> ViewOf(T item);
+
+ /// <summary>
+ /// Create a list view on this list containing the last occurrence of a particular item.
+ /// <exception cref="NoSuchItemException"/> if the item is not in this list.
+ /// </summary>
+ /// <param name="item">The item to find.</param>
+ /// <returns>The new list view.</returns>
+ IList<T> LastViewOf(T item);
+
+ /// <summary>
+ /// Null if this list is not a view.
+ /// </summary>
+ /// <value>Underlying list for view.</value>
+ IList<T> Underlying { get;}
+
+ /// <summary>
+ /// </summary>
+ /// <value>Offset for this list view or 0 for an underlying list.</value>
+ int Offset { get;}
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ bool IsValid { get;}
+
+ /// <summary>
+ /// Slide this list view along the underlying list.
+ /// </summary>
+ /// <exception cref="NotAViewException"> if this list is not a view.</exception>
+ /// <exception cref="ArgumentOutOfRangeException"> if the operation
+ /// would bring either end of the view outside the underlying list.</exception>
+ /// <param name="offset">The signed amount to slide: positive to slide
+ /// towards the end.</param>
+ IList<T> Slide(int offset);
+
+ /// <summary>
+ /// Slide this list view along the underlying list, changing its size.
+ ///
+ /// </summary>
+ /// <exception cref="NotAViewException"> if this list is not a view.</exception>
+ /// <exception cref="ArgumentOutOfRangeException"> if the operation
+ /// would bring either end of the view outside the underlying list.</exception>
+ /// <param name="offset">The signed amount to slide: positive to slide
+ /// towards the end.</param>
+ /// <param name="size">The new size of the view.</param>
+ IList<T> Slide(int offset, int size);
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="offset"></param>
+ /// <returns></returns>
+ bool TrySlide(int offset);
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="offset"></param>
+ /// <param name="size"></param>
+ /// <returns></returns>
+ bool TrySlide(int offset, int size);
+
+ /// <summary>
+ ///
+ /// <para>Returns null if <code>otherView</code> is strictly to the left of this view</para>
+ /// </summary>
+ /// <param name="otherView"></param>
+ /// <exception cref="IncompatibleViewException">If otherView does not have the same underlying list as this</exception>
+ /// <exception cref="ArgumentOutOfRangeException">If <code>otherView</code> is strictly to the left of this view</exception>
+ /// <returns></returns>
+ IList<T> Span(IList<T> otherView);
+
+ /// <summary>
+ /// Reverse the list so the items are in the opposite sequence order.
+ /// </summary>
+ void Reverse();
+
+ /// <summary>
+ /// Check if this list is sorted according to the default sorting order
+ /// for the item type T, as defined by the <see cref="T:C5.Comparer`1"/> class
+ /// </summary>
+ /// <exception cref="NotComparableException">if T is not comparable</exception>
+ /// <returns>True if the list is sorted, else false.</returns>
+ bool IsSorted();
+
+ /// <summary>
+ /// Check if this list is sorted according to a specific sorting order.
+ /// </summary>
+ /// <param name="comparer">The comparer defining the sorting order.</param>
+ /// <returns>True if the list is sorted, else false.</returns>
+ bool IsSorted(SCG.IComparer<T> comparer);
+
+ /// <summary>
+ /// Sort the items of the list according to the default sorting order
+ /// for the item type T, as defined by the <see cref="T:C5.Comparer`1"/> class
+ /// </summary>
+ /// <exception cref="NotComparableException">if T is not comparable</exception>
+ void Sort();
+
+ /// <summary>
+ /// Sort the items of the list according to a specified sorting order.
+ /// <para>The sorting does not perform duplicate elimination or identify items
+ /// according to the comparer or itemequalityComparer. I.e. the list as an
+ /// unsequenced collection with binary equality, will not change.
+ /// </para>
+ /// </summary>
+ /// <param name="comparer">The comparer defining the sorting order.</param>
+ void Sort(SCG.IComparer<T> comparer);
+
+
+ /// <summary>
+ /// Randomly shuffle the items of this list.
+ /// </summary>
+ void Shuffle();
+
+
+ /// <summary>
+ /// Shuffle the items of this list according to a specific random source.
+ /// </summary>
+ /// <param name="rnd">The random source.</param>
+ void Shuffle(Random rnd);
+ }
+
+
+ /// <summary>
+ /// The base type of a priority queue handle
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ public interface IPriorityQueueHandle<T>
+ {
+ //TODO: make abstract and prepare for double dispatch:
+ //public virtual bool Delete(IPriorityQueue<T> q) { throw new InvalidFooException();}
+ //bool Replace(T item);
+ }
+
+
+ /// <summary>
+ /// A generic collection of items prioritized by a comparison (order) relation.
+ /// Supports adding items and reporting or removing extremal elements.
+ /// <para>
+ ///
+ /// </para>
+ /// When adding an item, the user may choose to have a handle allocated for this item in the queue.
+ /// The resulting handle may be used for deleting the item even if not extremal, and for replacing the item.
+ /// A priority queue typically only holds numeric priorities associated with some objects
+ /// maintained separately in other collection objects.
+ /// </summary>
+ public interface IPriorityQueue<T> : IExtensible<T>
+ {
+ /// <summary>
+ /// Find the current least item of this priority queue.
+ /// </summary>
+ /// <returns>The least item.</returns>
+ T FindMin();
+
+
+ /// <summary>
+ /// Remove the least item from this priority queue.
+ /// </summary>
+ /// <returns>The removed item.</returns>
+ T DeleteMin();
+
+
+ /// <summary>
+ /// Find the current largest item of this priority queue.
+ /// </summary>
+ /// <returns>The largest item.</returns>
+ T FindMax();
+
+
+ /// <summary>
+ /// Remove the largest item from this priority queue.
+ /// </summary>
+ /// <returns>The removed item.</returns>
+ T DeleteMax();
+
+ /// <summary>
+ /// The comparer object supplied at creation time for this collection
+ /// </summary>
+ /// <value>The comparer</value>
+ SCG.IComparer<T> Comparer { get;}
+ /// <summary>
+ /// Get or set the item corresponding to a handle. Throws exceptions on
+ /// invalid handles.
+ /// </summary>
+ /// <param name="handle"></param>
+ /// <returns></returns>
+ T this[IPriorityQueueHandle<T> handle] { get; set;}
+
+ /// <summary>
+ /// Check if the entry corresponding to a handle is in the priority queue.
+ /// </summary>
+ /// <param name="handle"></param>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ bool Find(IPriorityQueueHandle<T> handle, out T item);
+
+ /// <summary>
+ /// Add an item to the priority queue, receiving a
+ /// handle for the item in the queue,
+ /// or reusing an existing unused handle.
+ /// </summary>
+ /// <param name="handle">On output: a handle for the added item.
+ /// On input: null for allocating a new handle, or a currently unused handle for reuse.
+ /// A handle for reuse must be compatible with this priority queue,
+ /// by being created by a priority queue of the same runtime type, but not
+ /// necessarily the same priority queue object.</param>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ bool Add(ref IPriorityQueueHandle<T> handle, T item);
+
+ /// <summary>
+ /// Delete an item with a handle from a priority queue
+ /// </summary>
+ /// <param name="handle">The handle for the item. The handle will be invalidated, but reusable.</param>
+ /// <returns>The deleted item</returns>
+ T Delete(IPriorityQueueHandle<T> handle);
+
+ /// <summary>
+ /// Replace an item with a handle in a priority queue with a new item.
+ /// Typically used for changing the priority of some queued object.
+ /// </summary>
+ /// <param name="handle">The handle for the old item</param>
+ /// <param name="item">The new item</param>
+ /// <returns>The old item</returns>
+ T Replace(IPriorityQueueHandle<T> handle, T item);
+
+ /// <summary>
+ /// Find the current least item of this priority queue.
+ /// </summary>
+ /// <param name="handle">On return: the handle of the item.</param>
+ /// <returns>The least item.</returns>
+ T FindMin(out IPriorityQueueHandle<T> handle);
+
+ /// <summary>
+ /// Find the current largest item of this priority queue.
+ /// </summary>
+ /// <param name="handle">On return: the handle of the item.</param>
+ /// <returns>The largest item.</returns>
+
+ T FindMax(out IPriorityQueueHandle<T> handle);
+
+ /// <summary>
+ /// Remove the least item from this priority queue.
+ /// </summary>
+ /// <param name="handle">On return: the handle of the removed item.</param>
+ /// <returns>The removed item.</returns>
+
+ T DeleteMin(out IPriorityQueueHandle<T> handle);
+
+ /// <summary>
+ /// Remove the largest item from this priority queue.
+ /// </summary>
+ /// <param name="handle">On return: the handle of the removed item.</param>
+ /// <returns>The removed item.</returns>
+ T DeleteMax(out IPriorityQueueHandle<T> handle);
+ }
+
+
+
+ /// <summary>
+ /// A sorted collection, i.e. a collection where items are maintained and can be searched for in sorted order.
+ /// Thus the sequence order is given as a sorting order.
+ ///
+ /// <para>The sorting order is defined by a comparer, an object of type IComparer&lt;T&gt;
+ /// (<see cref="T:C5.IComparer`1"/>). Implementors of this interface will normally let the user
+ /// define the comparer as an argument to a constructor.
+ /// Usually there will also be constructors without a comparer argument, in which case the
+ /// comparer should be the defalt comparer for the item type, <see cref="P:C5.Comparer`1.Default"/>.</para>
+ ///
+ /// <para>The comparer of the sorted collection is available as the <code>Comparer</code> property
+ /// (<see cref="P:C5.ISorted`1.Comparer"/>).</para>
+ ///
+ /// <para>The methods are grouped according to
+ /// <list>
+ /// <item>Extrema: report or report and delete an extremal item. This is reminiscent of simplified priority queues.</item>
+ /// <item>Nearest neighbor: report predecessor or successor in the collection of an item. Cut belongs to this group.</item>
+ /// <item>Range: report a view of a range of elements or remove all elements in a range.</item>
+ /// <item>AddSorted: add a collection of items known to be sorted in the same order (should be faster) (to be removed?)</item>
+ /// </list>
+ /// </para>
+ ///
+ /// <para>Since this interface extends ISequenced&lt;T&gt;, sorted collections will also have an
+ /// item equalityComparer (<see cref="P:C5.IExtensible`1.EqualityComparer"/>). This equalityComparer will not be used in connection with
+ /// the inner workings of the sorted collection, but will be used if the sorted collection is used as
+ /// an item in a collection of unsequenced or sequenced collections,
+ /// (<see cref="T:C5.ICollection`1"/> and <see cref="T:C5.ISequenced`1"/>)</para>
+ ///
+ /// <para>Note that code may check if two sorted collections has the same sorting order
+ /// by checking if the Comparer properties are equal. This is done a few places in this library
+ /// for optimization purposes.</para>
+ /// </summary>
+ public interface ISorted<T> : ISequenced<T>
+ {
+ /// <summary>
+ /// Find the current least item of this sorted collection.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if the collection is empty.</exception>
+ /// <returns>The least item.</returns>
+ T FindMin();
+
+
+ /// <summary>
+ /// Remove the least item from this sorted collection.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if the collection is empty.</exception>
+ /// <returns>The removed item.</returns>
+ T DeleteMin();
+
+
+ /// <summary>
+ /// Find the current largest item of this sorted collection.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if the collection is empty.</exception>
+ /// <returns>The largest item.</returns>
+ T FindMax();
+
+
+ /// <summary>
+ /// Remove the largest item from this sorted collection.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if the collection is empty.</exception>
+ /// <returns>The removed item.</returns>
+ T DeleteMax();
+
+ /// <summary>
+ /// The comparer object supplied at creation time for this sorted collection.
+ /// </summary>
+ /// <value>The comparer</value>
+ SCG.IComparer<T> Comparer { get;}
+
+ /// <summary>
+ /// Find the strict predecessor in the sorted collection of a particular value,
+ /// that is, the largest item in the collection less than the supplied value.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if no such element exists (the
+ /// supplied value is less than or equal to the minimum of this collection.)</exception>
+ /// <param name="item">The item to find the predecessor for.</param>
+ /// <returns>The predecessor.</returns>
+ T Predecessor(T item);
+
+
+ /// <summary>
+ /// Find the strict successor in the sorted collection of a particular value,
+ /// that is, the least item in the collection greater than the supplied value.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if no such element exists (the
+ /// supplied value is greater than or equal to the maximum of this collection.)</exception>
+ /// <param name="item">The item to find the successor for.</param>
+ /// <returns>The successor.</returns>
+ T Successor(T item);
+
+
+ /// <summary>
+ /// Find the weak predecessor in the sorted collection of a particular value,
+ /// that is, the largest item in the collection less than or equal to the supplied value.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if no such element exists (the
+ /// supplied value is less than the minimum of this collection.)</exception>
+ /// <param name="item">The item to find the weak predecessor for.</param>
+ /// <returns>The weak predecessor.</returns>
+ T WeakPredecessor(T item);
+
+
+ /// <summary>
+ /// Find the weak successor in the sorted collection of a particular value,
+ /// that is, the least item in the collection greater than or equal to the supplied value.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if no such element exists (the
+ /// supplied value is greater than the maximum of this collection.)</exception>
+ ///<param name="item">The item to find the weak successor for.</param>
+ /// <returns>The weak successor.</returns>
+ T WeakSuccessor(T item);
+
+
+ /// <summary>
+ /// Given a "cut" function from the items of the sorted collection to <code>int</code>
+ /// whose only sign changes when going through items in increasing order
+ /// can be
+ /// <list>
+ /// <item>from positive to zero</item>
+ /// <item>from positive to negative</item>
+ /// <item>from zero to negative</item>
+ /// </list>
+ /// The "cut" function is supplied as the <code>CompareTo</code> method
+ /// of an object <code>c</code> implementing
+ /// <code>IComparable&lt;T&gt;</code>.
+ /// A typical example is the case where <code>T</code> is comparable and
+ /// <code>cutFunction</code> is itself of type <code>T</code>.
+ /// <para>This method performs a search in the sorted collection for the ranges in which the
+ /// "cut" function is negative, zero respectively positive. If <code>T</code> is comparable
+ /// and <code>c</code> is of type <code>T</code>, this is a safe way (no exceptions thrown)
+ /// to find predecessor and successor of <code>c</code>.
+ /// </para>
+ /// <para> If the supplied cut function does not satisfy the sign-change condition,
+ /// the result of this call is undefined.
+ /// </para>
+ ///
+ /// </summary>
+ /// <param name="cutFunction">The cut function <code>T</code> to <code>int</code>, given
+ /// by the <code>CompareTo</code> method of an object implementing
+ /// <code>IComparable&lt;T&gt;</code>.</param>
+ /// <param name="low">Returns the largest item in the collection, where the
+ /// cut function is positive (if any).</param>
+ /// <param name="lowIsValid">Returns true if the cut function is positive somewhere
+ /// on this collection.</param>
+ /// <param name="high">Returns the least item in the collection, where the
+ /// cut function is negative (if any).</param>
+ /// <param name="highIsValid">Returns true if the cut function is negative somewhere
+ /// on this collection.</param>
+ /// <returns>True if the cut function is zero somewhere
+ /// on this collection.</returns>
+ bool Cut(IComparable<T> cutFunction, out T low, out bool lowIsValid, out T high, out bool highIsValid);
+
+
+ /// <summary>
+ /// Query this sorted collection for items greater than or equal to a supplied value.
+ /// <para>The returned collection is not a copy but a view into the collection.</para>
+ /// <para>The view is fragile in the sense that changes to the underlying collection will
+ /// invalidate the view so that further operations on the view throws InvalidView exceptions.</para>
+ /// </summary>
+ /// <param name="bot">The lower bound (inclusive).</param>
+ /// <returns>The result directed collection.</returns>
+ IDirectedEnumerable<T> RangeFrom(T bot);
+
+
+ /// <summary>
+ /// Query this sorted collection for items between two supplied values.
+ /// <para>The returned collection is not a copy but a view into the collection.</para>
+ /// <para>The view is fragile in the sense that changes to the underlying collection will
+ /// invalidate the view so that further operations on the view throws InvalidView exceptions.</para>
+ /// </summary>
+ /// <param name="bot">The lower bound (inclusive).</param>
+ /// <param name="top">The upper bound (exclusive).</param>
+ /// <returns>The result directed collection.</returns>
+ IDirectedEnumerable<T> RangeFromTo(T bot, T top);
+
+
+ /// <summary>
+ /// Query this sorted collection for items less than a supplied value.
+ /// <para>The returned collection is not a copy but a view into the collection.</para>
+ /// <para>The view is fragile in the sense that changes to the underlying collection will
+ /// invalidate the view so that further operations on the view throws InvalidView exceptions.</para>
+ /// </summary>
+ /// <param name="top">The upper bound (exclusive).</param>
+ /// <returns>The result directed collection.</returns>
+ IDirectedEnumerable<T> RangeTo(T top);
+
+
+ /// <summary>
+ /// Create a directed collection with the same items as this collection.
+ /// <para>The returned collection is not a copy but a view into the collection.</para>
+ /// <para>The view is fragile in the sense that changes to the underlying collection will
+ /// invalidate the view so that further operations on the view throws InvalidView exceptions.</para>
+ /// </summary>
+ /// <returns>The result directed collection.</returns>
+ IDirectedCollectionValue<T> RangeAll();
+
+
+ //TODO: remove now that we assume that we can check the sorting order?
+ /// <summary>
+ /// Add all the items from another collection with an enumeration order that
+ /// is increasing in the items.
+ /// </summary>
+ /// <exception cref="ArgumentException"> if the enumerated items turns out
+ /// not to be in increasing order.</exception>
+ /// <param name="items">The collection to add.</param>
+ /// <typeparam name="U"></typeparam>
+ void AddSorted<U>(SCG.IEnumerable<U> items) where U : T;
+
+
+ /// <summary>
+ /// Remove all items of this collection above or at a supplied threshold.
+ /// </summary>
+ /// <param name="low">The lower threshold (inclusive).</param>
+ void RemoveRangeFrom(T low);
+
+
+ /// <summary>
+ /// Remove all items of this collection between two supplied thresholds.
+ /// </summary>
+ /// <param name="low">The lower threshold (inclusive).</param>
+ /// <param name="hi">The upper threshold (exclusive).</param>
+ void RemoveRangeFromTo(T low, T hi);
+
+
+ /// <summary>
+ /// Remove all items of this collection below a supplied threshold.
+ /// </summary>
+ /// <param name="hi">The upper threshold (exclusive).</param>
+ void RemoveRangeTo(T hi);
+ }
+
+
+
+ /// <summary>
+ /// A collection where items are maintained in sorted order together
+ /// with their indexes in that order.
+ /// </summary>
+ public interface IIndexedSorted<T> : ISorted<T>, IIndexed<T>
+ {
+ /// <summary>
+ /// Determine the number of items at or above a supplied threshold.
+ /// </summary>
+ /// <param name="bot">The lower bound (inclusive)</param>
+ /// <returns>The number of matcing items.</returns>
+ int CountFrom(T bot);
+
+
+ /// <summary>
+ /// Determine the number of items between two supplied thresholds.
+ /// </summary>
+ /// <param name="bot">The lower bound (inclusive)</param>
+ /// <param name="top">The upper bound (exclusive)</param>
+ /// <returns>The number of matcing items.</returns>
+ int CountFromTo(T bot, T top);
+
+
+ /// <summary>
+ /// Determine the number of items below a supplied threshold.
+ /// </summary>
+ /// <param name="top">The upper bound (exclusive)</param>
+ /// <returns>The number of matcing items.</returns>
+ int CountTo(T top);
+
+
+ /// <summary>
+ /// Query this sorted collection for items greater than or equal to a supplied value.
+ /// </summary>
+ /// <param name="bot">The lower bound (inclusive).</param>
+ /// <returns>The result directed collection.</returns>
+ new IDirectedCollectionValue<T> RangeFrom(T bot);
+
+
+ /// <summary>
+ /// Query this sorted collection for items between two supplied values.
+ /// </summary>
+ /// <param name="bot">The lower bound (inclusive).</param>
+ /// <param name="top">The upper bound (exclusive).</param>
+ /// <returns>The result directed collection.</returns>
+ new IDirectedCollectionValue<T> RangeFromTo(T bot, T top);
+
+
+ /// <summary>
+ /// Query this sorted collection for items less than a supplied value.
+ /// </summary>
+ /// <param name="top">The upper bound (exclusive).</param>
+ /// <returns>The result directed collection.</returns>
+ new IDirectedCollectionValue<T> RangeTo(T top);
+
+
+ /// <summary>
+ /// Create a new indexed sorted collection consisting of the items of this
+ /// indexed sorted collection satisfying a certain predicate.
+ /// </summary>
+ /// <param name="predicate">The filter delegate defining the predicate.</param>
+ /// <returns>The new indexed sorted collection.</returns>
+ IIndexedSorted<T> FindAll(Fun<T, bool> predicate);
+
+
+ /// <summary>
+ /// Create a new indexed sorted collection consisting of the results of
+ /// mapping all items of this list.
+ /// <exception cref="ArgumentException"/> if the map is not increasing over
+ /// the items of this collection (with respect to the two given comparison
+ /// relations).
+ /// </summary>
+ /// <param name="mapper">The delegate definging the map.</param>
+ /// <param name="comparer">The comparion relation to use for the result.</param>
+ /// <returns>The new sorted collection.</returns>
+ IIndexedSorted<V> Map<V>(Fun<T, V> mapper, SCG.IComparer<V> comparer);
+ }
+
+
+
+ /// <summary>
+ /// The type of a sorted collection with persistence
+ /// </summary>
+ public interface IPersistentSorted<T> : ISorted<T>, IDisposable
+ {
+ /// <summary>
+ /// Make a (read-only) snap shot of this collection.
+ /// </summary>
+ /// <returns>The snap shot.</returns>
+ ISorted<T> Snapshot();
+ }
+
+
+
+ /*************************************************************************/
+ /// <summary>
+ /// A dictionary with keys of type K and values of type V. Equivalent to a
+ /// finite partial map from K to V.
+ /// </summary>
+ public interface IDictionary<K, V> : ICollectionValue<KeyValuePair<K, V>>, ICloneable
+ {
+ /// <summary>
+ /// The key equalityComparer.
+ /// </summary>
+ /// <value></value>
+ SCG.IEqualityComparer<K> EqualityComparer { get;}
+
+ /// <summary>
+ /// Indexer for dictionary.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if no entry is found. </exception>
+ /// <value>The value corresponding to the key</value>
+ V this[K key] { get; set;}
+
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>True if dictionary is read-only</value>
+ bool IsReadOnly { get;}
+
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>A collection containg the all the keys of the dictionary</value>
+ ICollectionValue<K> Keys { get;}
+
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>A collection containing all the values of the dictionary</value>
+ ICollectionValue<V> Values { get;}
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>A delegate of type <see cref="T:C5.Fun`2"/> defining the partial function from K to V give by the dictionary.</value>
+ Fun<K, V> Fun { get; }
+
+
+ //TODO: resolve inconsistency: Add thows exception if key already there, AddAll ignores keys already There?
+ /// <summary>
+ /// Add a new (key, value) pair (a mapping) to the dictionary.
+ /// </summary>
+ /// <exception cref="DuplicateNotAllowedException"> if there already is an entry with the same key. </exception>>
+ /// <param name="key">Key to add</param>
+ /// <param name="val">Value to add</param>
+ void Add(K key, V val);
+
+ /// <summary>
+ /// Add the entries from a collection of <see cref="T:C5.KeyValuePair`2"/> pairs to this dictionary.
+ /// </summary>
+ /// <exception cref="DuplicateNotAllowedException">
+ /// If the input contains duplicate keys or a key already present in this dictionary.</exception>
+ /// <param name="entries"></param>
+ void AddAll<U, W>(SCG.IEnumerable<KeyValuePair<U, W>> entries)
+ where U : K
+ where W : V
+ ;
+
+ /// <summary>
+ /// The value is symbolic indicating the type of asymptotic complexity
+ /// in terms of the size of this collection (worst-case or amortized as
+ /// relevant).
+ /// <para>See <see cref="T:C5.Speed"/> for the set of symbols.</para>
+ /// </summary>
+ /// <value>A characterization of the speed of lookup operations
+ /// (<code>Contains()</code> etc.) of the implementation of this dictionary.</value>
+ Speed ContainsSpeed { get;}
+
+ /// <summary>
+ /// Check whether this collection contains all the values in another collection.
+ /// If this collection has bag semantics (<code>AllowsDuplicates==true</code>)
+ /// the check is made with respect to multiplicities, else multiplicities
+ /// are not taken into account.
+ /// </summary>
+ /// <param name="items">The </param>
+ /// <returns>True if all values in <code>items</code>is in this collection.</returns>
+ bool ContainsAll<H>(SCG.IEnumerable<H> items) where H : K;
+
+ /// <summary>
+ /// Remove an entry with a given key from the dictionary
+ /// </summary>
+ /// <param name="key">The key of the entry to remove</param>
+ /// <returns>True if an entry was found (and removed)</returns>
+ bool Remove(K key);
+
+
+ /// <summary>
+ /// Remove an entry with a given key from the dictionary and report its value.
+ /// </summary>
+ /// <param name="key">The key of the entry to remove</param>
+ /// <param name="val">On exit, the value of the removed entry</param>
+ /// <returns>True if an entry was found (and removed)</returns>
+ bool Remove(K key, out V val);
+
+
+ /// <summary>
+ /// Remove all entries from the dictionary
+ /// </summary>
+ void Clear();
+
+
+ /// <summary>
+ /// Check if there is an entry with a specified key
+ /// </summary>
+ /// <param name="key">The key to look for</param>
+ /// <returns>True if key was found</returns>
+ bool Contains(K key);
+
+
+ /// <summary>
+ /// Check if there is an entry with a specified key and report the corresponding
+ /// value if found. This can be seen as a safe form of "val = this[key]".
+ /// </summary>
+ /// <param name="key">The key to look for</param>
+ /// <param name="val">On exit, the value of the entry</param>
+ /// <returns>True if key was found</returns>
+ bool Find(K key, out V val);
+
+ /// <summary>
+ /// Check if there is an entry with a specified key and report the corresponding
+ /// value if found. This can be seen as a safe form of "val = this[key]".
+ /// </summary>
+ /// <param name="key">The key to look for</param>
+ /// <param name="val">On exit, the value of the entry</param>
+ /// <returns>True if key was found</returns>
+ bool Find(ref K key, out V val);
+
+
+ /// <summary>
+ /// Look for a specific key in the dictionary and if found replace the value with a new one.
+ /// This can be seen as a non-adding version of "this[key] = val".
+ /// </summary>
+ /// <param name="key">The key to look for</param>
+ /// <param name="val">The new value</param>
+ /// <returns>True if key was found</returns>
+ bool Update(K key, V val); //no-adding
+
+
+ /// <summary>
+ /// Look for a specific key in the dictionary and if found replace the value with a new one.
+ /// This can be seen as a non-adding version of "this[key] = val" reporting the old value.
+ /// </summary>
+ /// <param name="key">The key to look for</param>
+ /// <param name="val">The new value</param>
+ /// <param name="oldval">The old value if any</param>
+ /// <returns>True if key was found</returns>
+ bool Update(K key, V val, out V oldval); //no-adding
+
+ /// <summary>
+ /// Look for a specific key in the dictionary. If found, report the corresponding value,
+ /// else add an entry with the key and the supplied value.
+ /// </summary>
+ /// <param name="key">The key to look for</param>
+ /// <param name="val">On entry the value to add if the key is not found.
+ /// On exit the value found if any.</param>
+ /// <returns>True if key was found</returns>
+ bool FindOrAdd(K key, ref V val); //mixture
+
+
+ /// <summary>
+ /// Update value in dictionary corresponding to key if found, else add new entry.
+ /// More general than "this[key] = val;" by reporting if key was found.
+ /// </summary>
+ /// <param name="key">The key to look for</param>
+ /// <param name="val">The value to add or replace with.</param>
+ /// <returns>True if key was found and value updated.</returns>
+ bool UpdateOrAdd(K key, V val);
+
+
+ /// <summary>
+ /// Update value in dictionary corresponding to key if found, else add new entry.
+ /// More general than "this[key] = val;" by reporting if key was found.
+ /// </summary>
+ /// <param name="key">The key to look for</param>
+ /// <param name="val">The value to add or replace with.</param>
+ /// <param name="oldval">The old value if any</param>
+ /// <returns>True if key was found and value updated.</returns>
+ bool UpdateOrAdd(K key, V val, out V oldval);
+
+
+ /// <summary>
+ /// Check the integrity of the internal data structures of this dictionary.
+ /// Only avaliable in DEBUG builds???
+ /// </summary>
+ /// <returns>True if check does not fail.</returns>
+ bool Check();
+ }
+
+
+
+ /// <summary>
+ /// A dictionary with sorted keys.
+ /// </summary>
+ public interface ISortedDictionary<K, V> : IDictionary<K, V>
+ {
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ new ISorted<K> Keys { get;}
+
+ /// <summary>
+ /// Find the current least item of this sorted collection.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if the collection is empty.</exception>
+ /// <returns>The least item.</returns>
+ KeyValuePair<K, V> FindMin();
+
+
+ /// <summary>
+ /// Remove the least item from this sorted collection.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if the collection is empty.</exception>
+ /// <returns>The removed item.</returns>
+ KeyValuePair<K, V> DeleteMin();
+
+
+ /// <summary>
+ /// Find the current largest item of this sorted collection.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if the collection is empty.</exception>
+ /// <returns>The largest item.</returns>
+ KeyValuePair<K, V> FindMax();
+
+
+ /// <summary>
+ /// Remove the largest item from this sorted collection.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if the collection is empty.</exception>
+ /// <returns>The removed item.</returns>
+ KeyValuePair<K, V> DeleteMax();
+
+ /// <summary>
+ /// The key comparer used by this dictionary.
+ /// </summary>
+ /// <value></value>
+ SCG.IComparer<K> Comparer { get;}
+
+ /// <summary>
+ /// Find the entry with the largest key less than a given key.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if there is no such entry. </exception>
+ /// <param name="key">The key to compare to</param>
+ /// <returns>The entry</returns>
+ KeyValuePair<K, V> Predecessor(K key);
+
+
+ /// <summary>
+ /// Find the entry with the least key greater than a given key.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if there is no such entry. </exception>
+ /// <param name="key">The key to compare to</param>
+ /// <returns>The entry</returns>
+ KeyValuePair<K, V> Successor(K key);
+
+
+ /// <summary>
+ /// Find the entry with the largest key less than or equal to a given key.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if there is no such entry. </exception>
+ /// <param name="key">The key to compare to</param>
+ /// <returns>The entry</returns>
+ KeyValuePair<K, V> WeakPredecessor(K key);
+
+
+ /// <summary>
+ /// Find the entry with the least key greater than or equal to a given key.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if there is no such entry. </exception>
+ /// <param name="key">The key to compare to</param>
+ /// <returns>The entry</returns>
+ KeyValuePair<K, V> WeakSuccessor(K key);
+
+ /// <summary>
+ /// Given a "cut" function from the items of the sorted collection to <code>int</code>
+ /// whose only sign changes when going through items in increasing order
+ /// can be
+ /// <list>
+ /// <item>from positive to zero</item>
+ /// <item>from positive to negative</item>
+ /// <item>from zero to negative</item>
+ /// </list>
+ /// The "cut" function is supplied as the <code>CompareTo</code> method
+ /// of an object <code>c</code> implementing
+ /// <code>IComparable&lt;K&gt;</code>.
+ /// A typical example is the case where <code>K</code> is comparable and
+ /// <code>c</code> is itself of type <code>K</code>.
+ /// <para>This method performs a search in the sorted collection for the ranges in which the
+ /// "cut" function is negative, zero respectively positive. If <code>K</code> is comparable
+ /// and <code>c</code> is of type <code>K</code>, this is a safe way (no exceptions thrown)
+ /// to find predecessor and successor of <code>c</code>.
+ /// </para>
+ /// <para> If the supplied cut function does not satisfy the sign-change condition,
+ /// the result of this call is undefined.
+ /// </para>
+ ///
+ /// </summary>
+ /// <param name="cutFunction">The cut function <code>K</code> to <code>int</code>, given
+ /// by the <code>CompareTo</code> method of an object implementing
+ /// <code>IComparable&lt;K&gt;</code>.</param>
+ /// <param name="lowEntry">Returns the largest item in the collection, where the
+ /// cut function is positive (if any).</param>
+ /// <param name="lowIsValid">Returns true if the cut function is positive somewhere
+ /// on this collection.</param>
+ /// <param name="highEntry">Returns the least item in the collection, where the
+ /// cut function is negative (if any).</param>
+ /// <param name="highIsValid">Returns true if the cut function is negative somewhere
+ /// on this collection.</param>
+ /// <returns>True if the cut function is zero somewhere
+ /// on this collection.</returns>
+ bool Cut(IComparable<K> cutFunction, out KeyValuePair<K, V> lowEntry, out bool lowIsValid, out KeyValuePair<K, V> highEntry, out bool highIsValid);
+
+ /// <summary>
+ /// Query this sorted collection for items greater than or equal to a supplied value.
+ /// <para>The returned collection is not a copy but a view into the collection.</para>
+ /// <para>The view is fragile in the sense that changes to the underlying collection will
+ /// invalidate the view so that further operations on the view throws InvalidView exceptions.</para>
+ /// </summary>
+ /// <param name="bot">The lower bound (inclusive).</param>
+ /// <returns>The result directed collection.</returns>
+ IDirectedEnumerable<KeyValuePair<K, V>> RangeFrom(K bot);
+
+
+ /// <summary>
+ /// Query this sorted collection for items between two supplied values.
+ /// <para>The returned collection is not a copy but a view into the collection.</para>
+ /// <para>The view is fragile in the sense that changes to the underlying collection will
+ /// invalidate the view so that further operations on the view throws InvalidView exceptions.</para>
+ /// </summary>
+ /// <param name="lowerBound">The lower bound (inclusive).</param>
+ /// <param name="upperBound">The upper bound (exclusive).</param>
+ /// <returns>The result directed collection.</returns>
+ IDirectedEnumerable<KeyValuePair<K, V>> RangeFromTo(K lowerBound, K upperBound);
+
+
+ /// <summary>
+ /// Query this sorted collection for items less than a supplied value.
+ /// <para>The returned collection is not a copy but a view into the collection.</para>
+ /// <para>The view is fragile in the sense that changes to the underlying collection will
+ /// invalidate the view so that further operations on the view throws InvalidView exceptions.</para>
+ /// </summary>
+ /// <param name="top">The upper bound (exclusive).</param>
+ /// <returns>The result directed collection.</returns>
+ IDirectedEnumerable<KeyValuePair<K, V>> RangeTo(K top);
+
+
+ /// <summary>
+ /// Create a directed collection with the same items as this collection.
+ /// <para>The returned collection is not a copy but a view into the collection.</para>
+ /// <para>The view is fragile in the sense that changes to the underlying collection will
+ /// invalidate the view so that further operations on the view throws InvalidView exceptions.</para>
+ /// </summary>
+ /// <returns>The result directed collection.</returns>
+ IDirectedCollectionValue<KeyValuePair<K, V>> RangeAll();
+
+
+ //TODO: remove now that we assume that we can check the sorting order?
+ /// <summary>
+ /// Add all the items from another collection with an enumeration order that
+ /// is increasing in the items.
+ /// </summary>
+ /// <exception cref="ArgumentException"> if the enumerated items turns out
+ /// not to be in increasing order.</exception>
+ /// <param name="items">The collection to add.</param>
+ void AddSorted(SCG.IEnumerable<KeyValuePair<K, V>> items);
+
+
+ /// <summary>
+ /// Remove all items of this collection above or at a supplied threshold.
+ /// </summary>
+ /// <param name="low">The lower threshold (inclusive).</param>
+ void RemoveRangeFrom(K low);
+
+
+ /// <summary>
+ /// Remove all items of this collection between two supplied thresholds.
+ /// </summary>
+ /// <param name="low">The lower threshold (inclusive).</param>
+ /// <param name="hi">The upper threshold (exclusive).</param>
+ void RemoveRangeFromTo(K low, K hi);
+
+
+ /// <summary>
+ /// Remove all items of this collection below a supplied threshold.
+ /// </summary>
+ /// <param name="hi">The upper threshold (exclusive).</param>
+ void RemoveRangeTo(K hi);
+ }
+
+
+
+ /*******************************************************************/
+ /*/// <summary>
+ /// The type of an item comparer
+ /// <i>Implementations of this interface must asure that the method is self-consistent
+ /// and defines a sorting order on items, or state precise conditions under which this is true.</i>
+ /// <i>Implementations <b>must</b> assure that repeated calls of
+ /// the method to the same (in reference or binary identity sense) arguments
+ /// will return values with the same sign (-1, 0 or +1), or state precise conditions
+ /// under which the user
+ /// can be assured repeated calls will return the same sign.</i>
+ /// <i>Implementations of this interface must always return values from the method
+ /// and never throw exceptions.</i>
+ /// <i>This interface is identical to System.Collections.Generic.IComparer&lt;T&gt;</i>
+ /// </summary>
+ public interface IComparer<T>
+ {
+ /// <summary>
+ /// Compare two items with respect to this item comparer
+ /// </summary>
+ /// <param name="item1">First item</param>
+ /// <param name="item2">Second item</param>
+ /// <returns>Positive if item1 is greater than item2, 0 if they are equal, negative if item1 is less than item2</returns>
+ int Compare(T item1, T item2);
+ }
+
+ /// <summary>
+ /// The type of an item equalityComparer.
+ /// <i>Implementations of this interface <b>must</b> assure that the methods are
+ /// consistent, that is, that whenever two items i1 and i2 satisfies that Equals(i1,i2)
+ /// returns true, then GetHashCode returns the same value for i1 and i2.</i>
+ /// <i>Implementations of this interface <b>must</b> assure that repeated calls of
+ /// the methods to the same (in reference or binary identity sense) arguments
+ /// will return the same values, or state precise conditions under which the user
+ /// can be assured repeated calls will return the same values.</i>
+ /// <i>Implementations of this interface must always return values from the methods
+ /// and never throw exceptions.</i>
+ /// <i>This interface is similar in function to System.IKeyComparer&lt;T&gt;</i>
+ /// </summary>
+ public interface SCG.IEqualityComparer<T>
+ {
+ /// <summary>
+ /// Get the hash code with respect to this item equalityComparer
+ /// </summary>
+ /// <param name="item">The item</param>
+ /// <returns>The hash code</returns>
+ int GetHashCode(T item);
+
+
+ /// <summary>
+ /// Check if two items are equal with respect to this item equalityComparer
+ /// </summary>
+ /// <param name="item1">first item</param>
+ /// <param name="item2">second item</param>
+ /// <returns>True if equal</returns>
+ bool Equals(T item1, T item2);
+ }*/
+}
diff --git a/mcs/class/Mono.C5/C5/MappedEnumerators.cs b/mcs/class/Mono.C5/C5/MappedEnumerators.cs
new file mode 100644
index 00000000000..580a34d0d1e
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/MappedEnumerators.cs
@@ -0,0 +1,145 @@
+/*
+ Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+using System;
+using System.Diagnostics;
+using SCG = System.Collections.Generic;
+namespace C5
+{
+ abstract class MappedDirectedCollectionValue<T, V> : DirectedCollectionValueBase<V>, IDirectedCollectionValue<V>
+ {
+ IDirectedCollectionValue<T> directedcollectionvalue;
+
+ abstract public V Map(T item);
+
+ public MappedDirectedCollectionValue(IDirectedCollectionValue<T> directedcollectionvalue)
+ {
+ this.directedcollectionvalue = directedcollectionvalue;
+ }
+
+ public override V Choose() { return Map(directedcollectionvalue.Choose()); }
+
+ public override bool IsEmpty { get { return directedcollectionvalue.IsEmpty; } }
+
+ public override int Count { get { return directedcollectionvalue.Count; } }
+
+ public override Speed CountSpeed { get { return directedcollectionvalue.CountSpeed; } }
+
+ public override IDirectedCollectionValue<V> Backwards()
+ {
+ MappedDirectedCollectionValue<T, V> retval = (MappedDirectedCollectionValue<T, V>)MemberwiseClone();
+ retval.directedcollectionvalue = directedcollectionvalue.Backwards();
+ return retval;
+ //If we made this classs non-abstract we could do
+ //return new MappedDirectedCollectionValue<T,V>(directedcollectionvalue.Backwards());;
+ }
+
+
+ public override SCG.IEnumerator<V> GetEnumerator()
+ {
+ foreach (T item in directedcollectionvalue)
+ yield return Map(item);
+ }
+
+ public override EnumerationDirection Direction
+ {
+ get { return directedcollectionvalue.Direction; }
+ }
+
+ IDirectedEnumerable<V> IDirectedEnumerable<V>.Backwards()
+ {
+ return Backwards();
+ }
+
+
+ }
+
+ abstract class MappedCollectionValue<T, V> : CollectionValueBase<V>, ICollectionValue<V>
+ {
+ ICollectionValue<T> collectionvalue;
+
+ abstract public V Map(T item);
+
+ public MappedCollectionValue(ICollectionValue<T> collectionvalue)
+ {
+ this.collectionvalue = collectionvalue;
+ }
+
+ public override V Choose() { return Map(collectionvalue.Choose()); }
+
+ public override bool IsEmpty { get { return collectionvalue.IsEmpty; } }
+
+ public override int Count { get { return collectionvalue.Count; } }
+
+ public override Speed CountSpeed { get { return collectionvalue.CountSpeed; } }
+
+ public override SCG.IEnumerator<V> GetEnumerator()
+ {
+ foreach (T item in collectionvalue)
+ yield return Map(item);
+ }
+ }
+
+ class MultiplicityOne<K> : MappedCollectionValue<K, KeyValuePair<K, int>>
+ {
+ public MultiplicityOne(ICollectionValue<K> coll):base(coll) { }
+ public override KeyValuePair<K, int> Map(K k) { return new KeyValuePair<K, int>(k, 1); }
+ }
+
+ class DropMultiplicity<K> : MappedCollectionValue<KeyValuePair<K, int>, K>
+ {
+ public DropMultiplicity(ICollectionValue<KeyValuePair<K, int>> coll):base(coll) { }
+ public override K Map(KeyValuePair<K, int> kvp) { return kvp.Key; }
+ }
+
+ abstract class MappedDirectedEnumerable<T, V> : EnumerableBase<V>, IDirectedEnumerable<V>
+ {
+ IDirectedEnumerable<T> directedenumerable;
+
+ abstract public V Map(T item);
+
+ public MappedDirectedEnumerable(IDirectedEnumerable<T> directedenumerable)
+ {
+ this.directedenumerable = directedenumerable;
+ }
+
+ public IDirectedEnumerable<V> Backwards()
+ {
+ MappedDirectedEnumerable<T, V> retval = (MappedDirectedEnumerable<T, V>)MemberwiseClone();
+ retval.directedenumerable = directedenumerable.Backwards();
+ return retval;
+ //If we made this classs non-abstract we could do
+ //return new MappedDirectedCollectionValue<T,V>(directedcollectionvalue.Backwards());;
+ }
+
+
+ public override SCG.IEnumerator<V> GetEnumerator()
+ {
+ foreach (T item in directedenumerable)
+ yield return Map(item);
+ }
+
+ public EnumerationDirection Direction
+ {
+ get { return directedenumerable.Direction; }
+ }
+ }
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/C5/Random.cs b/mcs/class/Mono.C5/C5/Random.cs
new file mode 100644
index 00000000000..28df260b85f
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/Random.cs
@@ -0,0 +1,172 @@
+/*
+ Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+using System;
+using System.Diagnostics;
+using SCG = System.Collections.Generic;
+namespace C5
+{
+ /// <summary>
+ /// A modern random number generator based on G. Marsaglia:
+ /// Seeds for Random Number Generators, Communications of the
+ /// ACM 46, 5 (May 2003) 90-93; and a posting by Marsaglia to
+ /// comp.lang.c on 2003-04-03.
+ /// </summary>
+ public class C5Random : Random
+ {
+ private uint[] Q = new uint[16];
+
+ private uint c = 362436, i = 15;
+
+
+ private uint Cmwc()
+ {
+ ulong t, a = 487198574UL;
+ uint x, r = 0xfffffffe;
+
+ i = (i + 1) & 15;
+ t = a * Q[i] + c;
+ c = (uint)(t >> 32);
+ x = (uint)(t + c);
+ if (x < c)
+ {
+ x++;
+ c++;
+ }
+
+ return Q[i] = r - x;
+ }
+
+
+ /// <summary>
+ /// Get a new random System.Double value
+ /// </summary>
+ /// <returns>The random double</returns>
+ public override double NextDouble()
+ {
+ return Cmwc() / 4294967296.0;
+ }
+
+
+ /// <summary>
+ /// Get a new random System.Double value
+ /// </summary>
+ /// <returns>The random double</returns>
+ protected override double Sample()
+ {
+ return NextDouble();
+ }
+
+
+ /// <summary>
+ /// Get a new random System.Int32 value
+ /// </summary>
+ /// <returns>The random int</returns>
+ public override int Next()
+ {
+ return (int)Cmwc();
+ }
+
+
+ /// <summary>
+ /// Get a random non-negative integer less than a given upper bound
+ /// </summary>
+ /// <exception cref="ArgumentException">If max is negative</exception>
+ /// <param name="max">The upper bound (exclusive)</param>
+ /// <returns></returns>
+ public override int Next(int max)
+ {
+ if (max < 0)
+ throw new ArgumentException("max must be non-negative");
+
+ return (int)(Cmwc() / 4294967296.0 * max);
+ }
+
+
+ /// <summary>
+ /// Get a random integer between two given bounds
+ /// </summary>
+ /// <exception cref="ArgumentException">If max is less than min</exception>
+ /// <param name="min">The lower bound (inclusive)</param>
+ /// <param name="max">The upper bound (exclusive)</param>
+ /// <returns></returns>
+ public override int Next(int min, int max)
+ {
+ if (min > max)
+ throw new ArgumentException("min must be less than or equal to max");
+
+ return min + (int)(Cmwc() / 4294967296.0 * (max - min));
+ }
+
+ /// <summary>
+ /// Fill a array of byte with random bytes
+ /// </summary>
+ /// <param name="buffer">The array to fill</param>
+ public override void NextBytes(byte[] buffer)
+ {
+ for (int i = 0, length = buffer.Length; i < length; i++)
+ buffer[i] = (byte)Cmwc();
+ }
+
+
+ /// <summary>
+ /// Create a random number generator seed by system time.
+ /// </summary>
+ public C5Random() : this(DateTime.Now.Ticks)
+ {
+ }
+
+
+ /// <summary>
+ /// Create a random number generator with a given seed
+ /// </summary>
+ /// <exception cref="ArgumentException">If seed is zero</exception>
+ /// <param name="seed">The seed</param>
+ public C5Random(long seed)
+ {
+ if (seed == 0)
+ throw new ArgumentException("Seed must be non-zero");
+
+ uint j = (uint)(seed & 0xFFFFFFFF);
+
+ for (int i = 0; i < 16; i++)
+ {
+ j ^= j << 13;
+ j ^= j >> 17;
+ j ^= j << 5;
+ Q[i] = j;
+ }
+
+ Q[15] = (uint)(seed ^ (seed >> 32));
+ }
+
+ /// <summary>
+ /// Create a random number generator with a specified internal start state.
+ /// </summary>
+ /// <exception cref="ArgumentException">If Q is not of length exactly 16</exception>
+ /// <param name="Q">The start state. Must be a collection of random bits given by an array of exactly 16 uints.</param>
+ public C5Random(uint[] Q)
+ {
+ if (Q.Length != 16)
+ throw new ArgumentException("Q must have length 16, was " + Q.Length);
+ Array.Copy(Q, this.Q, 16);
+ }
+ }
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/C5/Records.cs b/mcs/class/Mono.C5/C5/Records.cs
new file mode 100644
index 00000000000..47adaa9c070
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/Records.cs
@@ -0,0 +1,510 @@
+/*
+ Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+using C5;
+using System;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Diagnostics;
+
+namespace C5
+{
+ struct RecConst
+ {
+ public const int HASHFACTOR = 387281;
+ }
+ /// <summary>
+ /// A generic record type with two fields.
+ /// <para>
+ /// Equality is defined field by field, using the <code>Equals</code> method
+ /// inherited from <code>System.Object</code> (i.e. using <see cref="T:C5.NaturalEqualityComparer`1"/>).
+ /// </para>
+ /// <para>
+ /// This type is similar to <see cref="T:C5.KeyValuePair`2"/>, but the latter
+ /// uses <see cref="P:C5.EqualityComparer`1.Default"/> to define field equality instead of <see cref="T:C5.NaturalEqualityComparer`1"/>.
+ /// </para>
+ /// </summary>
+ /// <typeparam name="T1"></typeparam>
+ /// <typeparam name="T2"></typeparam>
+ public struct Rec<T1, T2> : IEquatable<Rec<T1, T2>>, IShowable
+ {
+ /// <summary>
+ ///
+ /// </summary>
+ public readonly T1 X1;
+ /// <summary>
+ ///
+ /// </summary>
+ public readonly T2 X2;
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="x1"></param>
+ /// <param name="x2"></param>
+ [Tested]
+ public Rec(T1 x1, T2 x2)
+ {
+ this.X1 = x1; this.X2 = x2;
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="other"></param>
+ /// <returns></returns>
+ [Tested]
+ public bool Equals(Rec<T1, T2> other)
+ {
+ return
+ (X1 == null ? other.X1 == null : X1.Equals(other.X1)) &&
+ (X2 == null ? other.X2 == null : X2.Equals(other.X2))
+ ;
+ }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="obj"></param>
+ /// <returns></returns>
+ [Tested]
+ public override bool Equals(object obj)
+ {
+ return obj is Rec<T1, T2> ? Equals((Rec<T1, T2>)obj) : false;
+ }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="record1"></param>
+ /// <param name="record2"></param>
+ /// <returns></returns>
+ [Tested]
+ public static bool operator ==(Rec<T1, T2> record1, Rec<T1, T2> record2)
+ {
+ return record1.Equals(record2);
+ }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="record1"></param>
+ /// <param name="record2"></param>
+ /// <returns></returns>
+ [Tested]
+ public static bool operator !=(Rec<T1, T2> record1, Rec<T1, T2> record2)
+ {
+ return !record1.Equals(record2);
+ }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ [Tested]
+ public override int GetHashCode()
+ {
+ //TODO: don't use 0 as hashcode for null, but something else!
+ int hashcode = X1 == null ? 0 : X1.GetHashCode();
+ hashcode = hashcode * RecConst.HASHFACTOR + (X2 == null ? 0 : X2.GetHashCode());
+ return hashcode;
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public override string ToString()
+ {
+ return String.Format("({0}, {1})", X1, X2);
+ }
+
+ #region IShowable Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="stringbuilder"></param>
+ /// <param name="rest"></param>
+ /// <param name="formatProvider"></param>
+ /// <returns></returns>
+ public bool Show(System.Text.StringBuilder stringbuilder, ref int rest, IFormatProvider formatProvider)
+ {
+ bool incomplete = true;
+ stringbuilder.Append("(");
+ rest -= 2;
+ try
+ {
+ if (incomplete = !Showing.Show(X1, stringbuilder, ref rest, formatProvider))
+ return false;
+ stringbuilder.Append(", ");
+ rest -= 2;
+ if (incomplete = !Showing.Show(X2, stringbuilder, ref rest, formatProvider))
+ return false;
+ }
+ finally
+ {
+ if (incomplete)
+ {
+ stringbuilder.Append("...");
+ rest -= 3;
+ }
+ stringbuilder.Append(")");
+ }
+ return true;
+ }
+ #endregion
+
+ #region IFormattable Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="format"></param>
+ /// <param name="formatProvider"></param>
+ /// <returns></returns>
+ public string ToString(string format, IFormatProvider formatProvider)
+ {
+ return Showing.ShowString(this, format, formatProvider);
+ }
+
+ #endregion
+ }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <typeparam name="T1"></typeparam>
+ /// <typeparam name="T2"></typeparam>
+ /// <typeparam name="T3"></typeparam>
+ public struct Rec<T1, T2, T3> : IEquatable<Rec<T1, T2, T3>>, IShowable
+ {
+ /// <summary>
+ ///
+ /// </summary>
+ public readonly T1 X1;
+ /// <summary>
+ ///
+ /// </summary>
+ public readonly T2 X2;
+ /// <summary>
+ ///
+ /// </summary>
+ public readonly T3 X3;
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="x1"></param>
+ /// <param name="x2"></param>
+ /// <param name="x3"></param>
+ [Tested]
+ public Rec(T1 x1, T2 x2, T3 x3)
+ {
+ this.X1 = x1; this.X2 = x2; this.X3 = x3;
+ }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="other"></param>
+ /// <returns></returns>
+ [Tested]
+ public bool Equals(Rec<T1, T2, T3> other)
+ {
+ return
+ (X1 == null ? other.X1 == null : X1.Equals(other.X1)) &&
+ (X2 == null ? other.X2 == null : X2.Equals(other.X2)) &&
+ (X3 == null ? other.X3 == null : X3.Equals(other.X3))
+ ;
+ }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="obj"></param>
+ /// <returns></returns>
+ [Tested]
+ public override bool Equals(object obj)
+ {
+ return obj is Rec<T1, T2, T3> ? Equals((Rec<T1, T2, T3>)obj) : false;
+ }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="record1"></param>
+ /// <param name="record2"></param>
+ /// <returns></returns>
+ [Tested]
+ public static bool operator ==(Rec<T1, T2, T3> record1, Rec<T1, T2, T3> record2)
+ {
+ return record1.Equals(record2);
+ }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="record1"></param>
+ /// <param name="record2"></param>
+ /// <returns></returns>
+ [Tested]
+ public static bool operator !=(Rec<T1, T2, T3> record1, Rec<T1, T2, T3> record2)
+ {
+ return !record1.Equals(record2);
+ }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ [Tested]
+ public override int GetHashCode()
+ {
+ //TODO: don't use 0 as hashcode for null, but something else!
+ int hashcode = X1 == null ? 0 : X1.GetHashCode();
+ hashcode = hashcode * RecConst.HASHFACTOR + (X2 == null ? 0 : X2.GetHashCode());
+ hashcode = hashcode * RecConst.HASHFACTOR + (X3 == null ? 0 : X3.GetHashCode());
+ return hashcode;
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public override string ToString()
+ {
+ return String.Format("({0}, {1}, {2})", X1, X2, X3);
+ }
+ #region IShowable Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="stringbuilder"></param>
+ /// <param name="rest"></param>
+ /// <param name="formatProvider"></param>
+ /// <returns></returns>
+ public bool Show(System.Text.StringBuilder stringbuilder, ref int rest, IFormatProvider formatProvider)
+ {
+ bool incomplete = true;
+ stringbuilder.Append("(");
+ rest -= 2;
+ try
+ {
+ if (incomplete = !Showing.Show(X1, stringbuilder, ref rest, formatProvider))
+ return false;
+ stringbuilder.Append(", ");
+ rest -= 2;
+ if (incomplete = !Showing.Show(X2, stringbuilder, ref rest, formatProvider))
+ return false;
+ stringbuilder.Append(", ");
+ rest -= 2;
+ if (incomplete = !Showing.Show(X3, stringbuilder, ref rest, formatProvider))
+ return false;
+ }
+ finally
+ {
+ if (incomplete)
+ {
+ stringbuilder.Append("...");
+ rest -= 3;
+ }
+ stringbuilder.Append(")");
+ }
+ return true;
+ }
+ #endregion
+
+ #region IFormattable Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="format"></param>
+ /// <param name="formatProvider"></param>
+ /// <returns></returns>
+ public string ToString(string format, IFormatProvider formatProvider)
+ {
+ return Showing.ShowString(this, format, formatProvider);
+ }
+
+ #endregion
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <typeparam name="T1"></typeparam>
+ /// <typeparam name="T2"></typeparam>
+ /// <typeparam name="T3"></typeparam>
+ /// <typeparam name="T4"></typeparam>
+ public struct Rec<T1, T2, T3, T4> : IEquatable<Rec<T1, T2, T3, T4>>, IShowable
+ {
+ /// <summary>
+ ///
+ /// </summary>
+ public readonly T1 X1;
+ /// <summary>
+ ///
+ /// </summary>
+ public readonly T2 X2;
+ /// <summary>
+ ///
+ /// </summary>
+ public readonly T3 X3;
+ /// <summary>
+ ///
+ /// </summary>
+ public readonly T4 X4;
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="x1"></param>
+ /// <param name="x2"></param>
+ /// <param name="x3"></param>
+ /// <param name="x4"></param>
+ [Tested]
+ public Rec(T1 x1, T2 x2, T3 x3, T4 x4)
+ {
+ this.X1 = x1; this.X2 = x2; this.X3 = x3; this.X4 = x4;
+ }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="other"></param>
+ /// <returns></returns>
+ [Tested]
+ public bool Equals(Rec<T1, T2, T3, T4> other)
+ {
+ return
+ (X1 == null ? other.X1 == null : X1.Equals(other.X1)) &&
+ (X2 == null ? other.X2 == null : X2.Equals(other.X2)) &&
+ (X3 == null ? other.X3 == null : X3.Equals(other.X3)) &&
+ (X4 == null ? other.X4 == null : X4.Equals(other.X4))
+ ;
+ }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="obj"></param>
+ /// <returns></returns>
+ [Tested]
+ public override bool Equals(object obj)
+ {
+ return obj is Rec<T1, T2, T3, T4> ? Equals((Rec<T1, T2, T3, T4>)obj) : false;
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="record1"></param>
+ /// <param name="record2"></param>
+ /// <returns></returns>
+ [Tested]
+ public static bool operator ==(Rec<T1, T2, T3, T4> record1, Rec<T1, T2, T3, T4> record2)
+ {
+ return record1.Equals(record2);
+ }
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="record1"></param>
+ /// <param name="record2"></param>
+ /// <returns></returns>
+ [Tested]
+ public static bool operator !=(Rec<T1, T2, T3, T4> record1, Rec<T1, T2, T3, T4> record2)
+ {
+ return !record1.Equals(record2);
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ [Tested]
+ public override int GetHashCode()
+ {
+ //TODO: don't use 0 as hashcode for null, but something else!
+ int hashcode = X1 == null ? 0 : X1.GetHashCode();
+ hashcode = hashcode * RecConst.HASHFACTOR + (X2 == null ? 0 : X2.GetHashCode());
+ hashcode = hashcode * RecConst.HASHFACTOR + (X3 == null ? 0 : X3.GetHashCode());
+ hashcode = hashcode * RecConst.HASHFACTOR + (X4 == null ? 0 : X4.GetHashCode());
+ return hashcode;
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public override string ToString()
+ {
+ return String.Format("({0}, {1}, {2}, {3})", X1, X2, X3, X4);
+ }
+ #region IShowable Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="stringbuilder"></param>
+ /// <param name="rest"></param>
+ /// <param name="formatProvider"></param>
+ /// <returns></returns>
+ public bool Show(System.Text.StringBuilder stringbuilder, ref int rest, IFormatProvider formatProvider)
+ {
+ bool incomplete = true;
+ stringbuilder.Append("(");
+ rest -= 2;
+ try
+ {
+ if (incomplete = !Showing.Show(X1, stringbuilder, ref rest, formatProvider))
+ return false;
+ stringbuilder.Append(", ");
+ rest -= 2;
+ if (incomplete = !Showing.Show(X2, stringbuilder, ref rest, formatProvider))
+ return false;
+ stringbuilder.Append(", ");
+ rest -= 2;
+ if (incomplete = !Showing.Show(X3, stringbuilder, ref rest, formatProvider))
+ return false;
+ stringbuilder.Append(", ");
+ rest -= 2;
+ if (incomplete = !Showing.Show(X4, stringbuilder, ref rest, formatProvider))
+ return false;
+ }
+ finally
+ {
+ if (incomplete)
+ {
+ stringbuilder.Append("...");
+ rest -= 3;
+ }
+ stringbuilder.Append(")");
+ }
+ return true;
+ }
+ #endregion
+
+ #region IFormattable Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="format"></param>
+ /// <param name="formatProvider"></param>
+ /// <returns></returns>
+ public string ToString(string format, IFormatProvider formatProvider)
+ {
+ return Showing.ShowString(this, format, formatProvider);
+ }
+
+ #endregion
+ }
+}
diff --git a/mcs/class/Mono.C5/C5/Sorting.cs b/mcs/class/Mono.C5/C5/Sorting.cs
new file mode 100644
index 00000000000..d40003dd232
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/Sorting.cs
@@ -0,0 +1,239 @@
+/*
+ Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+using System;
+using System.Diagnostics;
+using SCG = System.Collections.Generic;
+namespace C5
+{
+ /// <summary>
+ /// A utility class with functions for sorting arrays with respect to an IComparer&lt;T&gt;
+ /// </summary>
+ public class Sorting
+ {
+ Sorting() { }
+
+ /// <summary>
+ /// Sort part of array in place using IntroSort
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">If the <code>start</code>
+ /// and <code>count</code> arguments does not describe a valid range.</exception>
+ /// <param name="array">Array to sort</param>
+ /// <param name="start">Index of first position to sort</param>
+ /// <param name="count">Number of elements to sort</param>
+ /// <param name="comparer">IComparer&lt;T&gt; to sort by</param>
+ [Tested]
+ public static void IntroSort<T>(T[] array, int start, int count, SCG.IComparer<T> comparer)
+ {
+ if (start < 0 || count < 0 || start + count > array.Length)
+ throw new ArgumentOutOfRangeException();
+ new Sorter<T>(array, comparer).IntroSort(start, start + count);
+ }
+
+ /// <summary>
+ /// Sort an array in place using IntroSort and default comparer
+ /// </summary>
+ /// <exception cref="NotComparableException">If T is not comparable</exception>
+ /// <param name="array">Array to sort</param>
+ [Tested]
+ public static void IntroSort<T>(T[] array)
+ {
+ new Sorter<T>(array, Comparer<T>.Default).IntroSort(0, array.Length);
+ }
+
+
+ /// <summary>
+ /// Sort part of array in place using Insertion Sort
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">If the <code>start</code>
+ /// and <code>count</code> arguments does not describe a valid range.</exception>
+ /// <param name="array">Array to sort</param>
+ /// <param name="start">Index of first position to sort</param>
+ /// <param name="count">Number of elements to sort</param>
+ /// <param name="comparer">IComparer&lt;T&gt; to sort by</param>
+ [Tested]
+ public static void InsertionSort<T>(T[] array, int start, int count, SCG.IComparer<T> comparer)
+ {
+ if (start < 0 || count < 0 || start + count > array.Length)
+ throw new ArgumentOutOfRangeException();
+ new Sorter<T>(array, comparer).InsertionSort(start, start + count);
+ }
+
+
+ /// <summary>
+ /// Sort part of array in place using Heap Sort
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">If the <code>start</code>
+ /// and <code>count</code> arguments does not describe a valid range.</exception>
+ /// <param name="array">Array to sort</param>
+ /// <param name="start">Index of first position to sort</param>
+ /// <param name="count">Number of elements to sort</param>
+ /// <param name="comparer">IComparer&lt;T&gt; to sort by</param>
+ [Tested]
+ public static void HeapSort<T>(T[] array, int start, int count, SCG.IComparer<T> comparer)
+ {
+ if (start < 0 || count < 0 || start + count > array.Length)
+ throw new ArgumentOutOfRangeException();
+ new Sorter<T>(array, comparer).HeapSort(start, start + count);
+ }
+
+
+ class Sorter<T>
+ {
+ T[] a;
+
+ SCG.IComparer<T> c;
+
+
+ internal Sorter(T[] a, SCG.IComparer<T> c) { this.a = a; this.c = c; }
+
+
+ internal void IntroSort(int f, int b)
+ {
+ if (b - f > 31)
+ {
+ int depth_limit = (int)Math.Floor(2.5 * Math.Log(b - f, 2));
+
+ introSort(f, b, depth_limit);
+ }
+ else
+ InsertionSort(f, b);
+ }
+
+
+ private void introSort(int f, int b, int depth_limit)
+ {
+ const int size_threshold = 14;//24;
+
+ if (depth_limit-- == 0)
+ HeapSort(f, b);
+ else if (b - f <= size_threshold)
+ InsertionSort(f, b);
+ else
+ {
+ int p = partition(f, b);
+
+ introSort(f, p, depth_limit);
+ introSort(p, b, depth_limit);
+ }
+ }
+
+
+ private int compare(T i1, T i2) { return c.Compare(i1, i2); }
+
+
+ private int partition(int f, int b)
+ {
+ int bot = f, mid = (b + f) / 2, top = b - 1;
+ T abot = a[bot], amid = a[mid], atop = a[top];
+
+ if (compare(abot, amid) < 0)
+ {
+ if (compare(atop, abot) < 0)//atop<abot<amid
+ { a[top] = amid; amid = a[mid] = abot; a[bot] = atop; }
+ else if (compare(atop, amid) < 0) //abot<=atop<amid
+ { a[top] = amid; amid = a[mid] = atop; }
+ //else abot<amid<=atop
+ }
+ else
+ {
+ if (compare(amid, atop) > 0) //atop<amid<=abot
+ { a[bot] = atop; a[top] = abot; }
+ else if (compare(abot, atop) > 0) //amid<=atop<abot
+ { a[bot] = amid; amid = a[mid] = atop; a[top] = abot; }
+ else //amid<=abot<=atop
+ { a[bot] = amid; amid = a[mid] = abot; }
+ }
+
+ int i = bot, j = top;
+
+ while (true)
+ {
+ while (compare(a[++i], amid) < 0) ;
+
+ while (compare(amid, a[--j]) < 0) ;
+
+ if (i < j)
+ {
+ T tmp = a[i]; a[i] = a[j]; a[j] = tmp;
+ }
+ else
+ return i;
+ }
+ }
+
+
+ internal void InsertionSort(int f, int b)
+ {
+ for (int j = f + 1; j < b; j++)
+ {
+ T key = a[j], other;
+ int i = j - 1;
+
+ if (c.Compare(other = a[i], key) > 0)
+ {
+ a[j] = other;
+ while (i > f && c.Compare(other = a[i - 1], key) > 0) { a[i--] = other; }
+
+ a[i] = key;
+ }
+ }
+ }
+
+
+ internal void HeapSort(int f, int b)
+ {
+ for (int i = (b + f) / 2; i >= f; i--) heapify(f, b, i);
+
+ for (int i = b - 1; i > f; i--)
+ {
+ T tmp = a[f]; a[f] = a[i]; a[i] = tmp;
+ heapify(f, i, f);
+ }
+ }
+
+
+ private void heapify(int f, int b, int i)
+ {
+ T pv = a[i], lv, rv, max = pv;
+ int j = i, maxpt = j;
+
+ while (true)
+ {
+ int l = 2 * j - f + 1, r = l + 1;
+
+ if (l < b && compare(lv = a[l], max) > 0) { maxpt = l; max = lv; }
+
+ if (r < b && compare(rv = a[r], max) > 0) { maxpt = r; max = rv; }
+
+ if (maxpt == j)
+ break;
+
+ a[j] = max;
+ max = pv;
+ j = maxpt;
+ }
+
+ if (j > i)
+ a[j] = pv;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/C5/ViewSupport.cs b/mcs/class/Mono.C5/C5/ViewSupport.cs
new file mode 100644
index 00000000000..ca2a6d72d30
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/ViewSupport.cs
@@ -0,0 +1,101 @@
+/*
+ Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+using System;
+using System.Diagnostics;
+using SCG = System.Collections.Generic;
+
+namespace C5
+{
+ /// <summary>
+ /// Characterize the mutual position of some view B (other) relative to view A (this)
+ /// </summary>
+ enum MutualViewPosition
+ {
+ /// <summary>
+ /// B contains A(this)
+ /// </summary>
+ Contains,
+ /// <summary>
+ /// B is containd in A(this), but not vice versa
+ /// </summary>
+ ContainedIn,
+ /// <summary>
+ /// A and B does not overlap
+ /// </summary>
+ NonOverlapping,
+ /// <summary>
+ /// A and B overlap, but neither is contained in the other
+ /// </summary>
+ Overlapping
+ }
+
+ #region View List Nested class
+ /// <summary>
+ /// This class is shared between the linked list and array list implementations.
+ /// </summary>
+ /// <typeparam name="V"></typeparam>
+ [Serializable]
+ class WeakViewList<V> where V : class
+ {
+ Node start;
+ [Serializable]
+ internal class Node
+ {
+ internal WeakReference weakview; internal Node prev, next;
+ internal Node(V view) { weakview = new WeakReference(view); }
+ }
+ internal Node Add(V view)
+ {
+ Node newNode = new Node(view);
+ if (start != null) { start.prev = newNode; newNode.next = start; }
+ start = newNode;
+ return newNode;
+ }
+ internal void Remove(Node n)
+ {
+ if (n == start) { start = start.next; if (start != null) start.prev = null; }
+ else { n.prev.next = n.next; if (n.next != null) n.next.prev = n.prev; }
+ }
+ /// <summary>
+ /// Note that it is safe to call views.Remove(view.myWeakReference) if view
+ /// is the currently yielded object
+ /// </summary>
+ /// <returns></returns>
+ public SCG.IEnumerator<V> GetEnumerator()
+ {
+ Node n = start;
+ while (n != null)
+ {
+ //V view = n.weakview.Target as V; //This provokes a bug in the beta1 verifyer
+ object o = n.weakview.Target;
+ V view = o is V ? (V)o : null;
+ if (view == null)
+ Remove(n);
+ else
+ yield return view;
+ n = n.next;
+ }
+ }
+ }
+
+ #endregion
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/C5/WrappedArray.cs b/mcs/class/Mono.C5/C5/WrappedArray.cs
new file mode 100644
index 00000000000..b0aac9e111c
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/WrappedArray.cs
@@ -0,0 +1,871 @@
+/*
+ Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+using System;
+using System.Text;
+using System.Diagnostics;
+using SCG = System.Collections.Generic;
+namespace C5
+{
+ /// <summary>
+ /// An advanced interface to operations on an array. The array is viewed as an
+ /// <see cref="T:C5.IList`1"/> of fixed size, and so all operations that would change the
+ /// size of the array will be invalid (and throw <see cref="T:C5.FixedSizeCollectionException"/>
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ public class WrappedArray<T> : IList<T>
+ {
+ class InnerList : ArrayList<T>
+ {
+ internal InnerList(T[] array) { this.array = array; size = array.Length; }
+ }
+ ArrayList<T> innerlist;
+ //TODO: remember a ref to the wrapped array in WrappedArray to save a little on indexing?
+ WrappedArray<T> underlying;
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="wrappedarray"></param>
+ public WrappedArray(T[] wrappedarray) { innerlist = new InnerList(wrappedarray); }
+
+ //for views
+ WrappedArray(ArrayList<T> arraylist, WrappedArray<T> underlying) { innerlist = arraylist; this.underlying = underlying; }
+
+ #region IList<T> Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public T First { get { return innerlist.First; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public T Last { get { return innerlist.Last; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="index"></param>
+ /// <returns></returns>
+ public T this[int index]
+ {
+ get { return innerlist[index]; }
+ set { innerlist[index] = value; }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="filter"></param>
+ /// <returns></returns>
+ public IList<T> FindAll(Fun<T, bool> filter) { return innerlist.FindAll(filter); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <typeparam name="V"></typeparam>
+ /// <param name="mapper"></param>
+ /// <returns></returns>
+ public IList<V> Map<V>(Fun<T, V> mapper) { return innerlist.Map<V>(mapper); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <typeparam name="V"></typeparam>
+ /// <param name="mapper"></param>
+ /// <param name="equalityComparer"></param>
+ /// <returns></returns>
+ public IList<V> Map<V>(Fun<T, V> mapper, SCG.IEqualityComparer<V> equalityComparer) { return innerlist.Map<V>(mapper, equalityComparer); }
+
+ /// <summary>
+ /// ???? should we throw NotRelevantException
+ /// </summary>
+ /// <value></value>
+ public bool FIFO
+ {
+ get { throw new FixedSizeCollectionException(); }
+ set { throw new FixedSizeCollectionException(); }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ public virtual bool IsFixedSize
+ {
+ get { return true; }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="index"></param>
+ /// <param name="item"></param>
+ public void Insert(int index, T item)
+ {
+ throw new FixedSizeCollectionException();
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="pointer"></param>
+ /// <param name="item"></param>
+ public void Insert(IList<T> pointer, T item)
+ {
+ throw new FixedSizeCollectionException();
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ public void InsertFirst(T item)
+ {
+ throw new FixedSizeCollectionException();
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ public void InsertLast(T item)
+ {
+ throw new FixedSizeCollectionException();
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <typeparam name="U"></typeparam>
+ /// <param name="i"></param>
+ /// <param name="items"></param>
+ public void InsertAll<U>(int i, System.Collections.Generic.IEnumerable<U> items) where U : T
+ {
+ throw new FixedSizeCollectionException();
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public T Remove()
+ {
+ throw new FixedSizeCollectionException();
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public T RemoveFirst()
+ {
+ throw new FixedSizeCollectionException();
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public T RemoveLast()
+ {
+ throw new FixedSizeCollectionException();
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="start"></param>
+ /// <param name="count"></param>
+ /// <returns></returns>
+ public IList<T> View(int start, int count)
+ {
+ return new WrappedArray<T>((ArrayList<T>)innerlist.View(start, count), underlying ?? this);
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public IList<T> ViewOf(T item)
+ {
+ return new WrappedArray<T>((ArrayList<T>)innerlist.ViewOf(item), underlying ?? this);
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public IList<T> LastViewOf(T item)
+ {
+ return new WrappedArray<T>((ArrayList<T>)innerlist.LastViewOf(item), underlying ?? this);
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public IList<T> Underlying { get { return underlying; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public int Offset { get { return innerlist.Offset; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public bool IsValid { get { return innerlist.IsValid; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="offset"></param>
+ /// <returns></returns>
+ public IList<T> Slide(int offset) { return innerlist.Slide(offset); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="offset"></param>
+ /// <param name="size"></param>
+ /// <returns></returns>
+ public IList<T> Slide(int offset, int size) { return innerlist.Slide(offset, size); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="offset"></param>
+ /// <returns></returns>
+ public bool TrySlide(int offset) { return innerlist.TrySlide(offset); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="offset"></param>
+ /// <param name="size"></param>
+ /// <returns></returns>
+ public bool TrySlide(int offset, int size) { return innerlist.TrySlide(offset, size); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="otherView"></param>
+ /// <returns></returns>
+ public IList<T> Span(IList<T> otherView) { return innerlist.Span(((WrappedArray<T>)otherView).innerlist); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ public void Reverse() { innerlist.Reverse(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public bool IsSorted() { return innerlist.IsSorted(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="comparer"></param>
+ /// <returns></returns>
+ public bool IsSorted(SCG.IComparer<T> comparer) { return innerlist.IsSorted(comparer); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ public void Sort() { innerlist.Sort(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="comparer"></param>
+ public void Sort(SCG.IComparer<T> comparer) { innerlist.Sort(comparer); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ public void Shuffle() { innerlist.Shuffle(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="rnd"></param>
+ public void Shuffle(Random rnd) { innerlist.Shuffle(rnd); }
+
+ #endregion
+
+ #region IIndexed<T> Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public Speed IndexingSpeed { get { return Speed.Constant; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="start"></param>
+ /// <param name="count"></param>
+ /// <returns></returns>
+ public IDirectedCollectionValue<T> this[int start, int count] { get { return innerlist[start, count]; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public int IndexOf(T item) { return innerlist.IndexOf(item); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public int LastIndexOf(T item) { return innerlist.LastIndexOf(item); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="predicate"></param>
+ /// <returns></returns>
+ public int FindIndex(Fun<T, bool> predicate) { return innerlist.FindIndex(predicate); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="predicate"></param>
+ /// <returns></returns>
+ public int FindLastIndex(Fun<T, bool> predicate) { return innerlist.FindLastIndex(predicate); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="i"></param>
+ /// <returns></returns>
+ public T RemoveAt(int i) { throw new FixedSizeCollectionException(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="start"></param>
+ /// <param name="count"></param>
+ public void RemoveInterval(int start, int count) { throw new FixedSizeCollectionException(); }
+
+ #endregion
+
+ #region ISequenced<T> Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public int GetSequencedHashCode() { return innerlist.GetSequencedHashCode(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="that"></param>
+ /// <returns></returns>
+ public bool SequencedEquals(ISequenced<T> that) { return innerlist.SequencedEquals(that); }
+
+ #endregion
+
+ #region ICollection<T> Members
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public Speed ContainsSpeed { get { return Speed.Linear; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public int GetUnsequencedHashCode() { return innerlist.GetUnsequencedHashCode(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="that"></param>
+ /// <returns></returns>
+ public bool UnsequencedEquals(ICollection<T> that) { return innerlist.UnsequencedEquals(that); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public bool Contains(T item) { return innerlist.Contains(item); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public int ContainsCount(T item) { return innerlist.ContainsCount(item); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public ICollectionValue<T> UniqueItems() { return innerlist.UniqueItems(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public ICollectionValue<KeyValuePair<T, int>> ItemMultiplicities() { return innerlist.ItemMultiplicities(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <typeparam name="U"></typeparam>
+ /// <param name="items"></param>
+ /// <returns></returns>
+ public bool ContainsAll<U>(System.Collections.Generic.IEnumerable<U> items) where U : T
+ { return innerlist.ContainsAll(items); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public bool Find(ref T item) { return innerlist.Find(ref item); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public bool FindOrAdd(ref T item) { throw new FixedSizeCollectionException(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public bool Update(T item) { throw new FixedSizeCollectionException(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ /// <param name="olditem"></param>
+ /// <returns></returns>
+ public bool Update(T item, out T olditem) { throw new FixedSizeCollectionException(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public bool UpdateOrAdd(T item) { throw new FixedSizeCollectionException(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ /// <param name="olditem"></param>
+ /// <returns></returns>
+ public bool UpdateOrAdd(T item, out T olditem) { throw new FixedSizeCollectionException(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public bool Remove(T item) { throw new FixedSizeCollectionException(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ /// <param name="removeditem"></param>
+ /// <returns></returns>
+ public bool Remove(T item, out T removeditem) { throw new FixedSizeCollectionException(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ public void RemoveAllCopies(T item) { throw new FixedSizeCollectionException(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <typeparam name="U"></typeparam>
+ /// <param name="items"></param>
+ public void RemoveAll<U>(System.Collections.Generic.IEnumerable<U> items) where U : T { throw new FixedSizeCollectionException(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ public void Clear() { throw new FixedSizeCollectionException(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <typeparam name="U"></typeparam>
+ /// <param name="items"></param>
+ public void RetainAll<U>(System.Collections.Generic.IEnumerable<U> items) where U : T { throw new FixedSizeCollectionException(); }
+
+ #endregion
+
+ #region IExtensible<T> Members
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public object SyncRoot { get { return innerlist.SyncRoot; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public bool IsReadOnly { get { return true; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public bool AllowsDuplicates
+ {
+ get { return true; }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public SCG.IEqualityComparer<T> EqualityComparer { get { return innerlist.EqualityComparer; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public bool DuplicatesByCounting
+ {
+ get { return false; }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public bool Add(T item)
+ {
+ throw new FixedSizeCollectionException();
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <typeparam name="U"></typeparam>
+ /// <param name="items"></param>
+ public void AddAll<U>(System.Collections.Generic.IEnumerable<U> items) where U : T
+ {
+ throw new FixedSizeCollectionException();
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public bool Check()
+ {
+ return innerlist.Check() && (underlying == null || underlying.innerlist == innerlist.Underlying);
+ }
+
+ #endregion
+
+ #region ICollectionValue<T> Members
+ /// <summary>
+ /// No listeners may be installed
+ /// </summary>
+ /// <value>0</value>
+ public virtual EventTypeEnum ListenableEvents { get { return 0; } }
+
+ /// <summary>
+ /// No listeners ever installed
+ /// </summary>
+ /// <value>0</value>
+ public virtual EventTypeEnum ActiveEvents { get { return 0; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public event CollectionChangedHandler<T> CollectionChanged
+ {
+ add { throw new UnlistenableEventException(); }
+ remove { throw new UnlistenableEventException(); }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public event CollectionClearedHandler<T> CollectionCleared
+ {
+ add { throw new UnlistenableEventException(); }
+ remove { throw new UnlistenableEventException(); }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public event ItemsAddedHandler<T> ItemsAdded
+ {
+ add { throw new UnlistenableEventException(); }
+ remove { throw new UnlistenableEventException(); }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public event ItemInsertedHandler<T> ItemInserted
+ {
+ add { throw new UnlistenableEventException(); }
+ remove { throw new UnlistenableEventException(); }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public event ItemsRemovedHandler<T> ItemsRemoved
+ {
+ add { throw new UnlistenableEventException(); }
+ remove { throw new UnlistenableEventException(); }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public event ItemRemovedAtHandler<T> ItemRemovedAt
+ {
+ add { throw new UnlistenableEventException(); }
+ remove { throw new UnlistenableEventException(); }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public bool IsEmpty { get { return innerlist.IsEmpty; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public int Count { get { return innerlist.Count; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public Speed CountSpeed { get { return innerlist.CountSpeed; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="array"></param>
+ /// <param name="index"></param>
+ public void CopyTo(T[] array, int index) { innerlist.CopyTo(array, index); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public T[] ToArray() { return innerlist.ToArray(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="action"></param>
+ public void Apply(Act<T> action) { innerlist.Apply(action); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="predicate"></param>
+ /// <returns></returns>
+ public bool Exists(Fun<T, bool> predicate) { return innerlist.Exists(predicate); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="predicate"></param>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public bool Find(Fun<T, bool> predicate, out T item) { return innerlist.Find(predicate, out item); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="predicate"></param>
+ /// <returns></returns>
+ public bool All(Fun<T, bool> predicate) { return innerlist.All(predicate); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public T Choose() { return innerlist.Choose(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="filter"></param>
+ /// <returns></returns>
+ public SCG.IEnumerable<T> Filter(Fun<T, bool> filter) { return innerlist.Filter(filter); }
+
+ #endregion
+
+ #region IEnumerable<T> Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public SCG.IEnumerator<T> GetEnumerator() { return innerlist.GetEnumerator(); }
+ #endregion
+
+ #region IShowable Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="stringbuilder"></param>
+ /// <param name="rest"></param>
+ /// <param name="formatProvider"></param>
+ /// <returns></returns>
+ public bool Show(StringBuilder stringbuilder, ref int rest, IFormatProvider formatProvider)
+ { return innerlist.Show(stringbuilder, ref rest, formatProvider); }
+
+ #endregion
+
+ #region IFormattable Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public override string ToString() { return innerlist.ToString(); }
+
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="format"></param>
+ /// <param name="formatProvider"></param>
+ /// <returns></returns>
+ public virtual string ToString(string format, IFormatProvider formatProvider) { return innerlist.ToString(format, formatProvider); }
+
+ #endregion
+
+ #region IDirectedCollectionValue<T> Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public IDirectedCollectionValue<T> Backwards() { return innerlist.Backwards(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="predicate"></param>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public bool FindLast(Fun<T, bool> predicate, out T item) { return innerlist.FindLast(predicate, out item); }
+
+ #endregion
+
+ #region IDirectedEnumerable<T> Members
+
+ IDirectedEnumerable<T> IDirectedEnumerable<T>.Backwards() { return Backwards(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public EnumerationDirection Direction { get { return EnumerationDirection.Forwards; } }
+
+ #endregion
+
+ #region IDisposable Members
+
+ /// <summary>
+ /// Dispose this if a view else operation is illegal
+ /// </summary>
+ /// <exception cref="FixedSizeCollectionException">If not a view</exception>
+ public void Dispose()
+ {
+ if (underlying == null)
+ throw new FixedSizeCollectionException();
+ else
+ innerlist.Dispose();
+ }
+
+ #endregion
+
+ #region ICloneable Members
+
+ /// <summary>
+ /// Make a shallow copy of this WrappedArray.
+ ///
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public virtual object Clone()
+ {
+ return new WrappedArray<T>(innerlist.ToArray());
+ }
+
+ #endregion
+
+
+
+ #region IEnumerable Members
+
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+ {
+ throw new Exception("The method or operation is not implemented.");
+ }
+
+ #endregion
+ }
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/C5/Wrappers.cs b/mcs/class/Mono.C5/C5/Wrappers.cs
new file mode 100644
index 00000000000..9d594e0b064
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/Wrappers.cs
@@ -0,0 +1,2233 @@
+/*
+ Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+using System;
+using System.Diagnostics;
+using SCG = System.Collections.Generic;
+namespace C5
+{
+ /// <summary>
+ /// A read-only wrapper class for a generic enumerator
+ /// </summary>
+ public class GuardedEnumerator<T> : SCG.IEnumerator<T>
+ {
+ #region Fields
+
+ SCG.IEnumerator<T> enumerator;
+
+ #endregion
+
+ #region Constructor
+
+ /// <summary>
+ /// Create a wrapper around a generic enumerator
+ /// </summary>
+ /// <param name="enumerator">The enumerator to wrap</param>
+ public GuardedEnumerator(SCG.IEnumerator<T> enumerator)
+ { this.enumerator = enumerator; }
+
+ #endregion
+
+ #region IEnumerator<T> Members
+
+ /// <summary>
+ /// Move wrapped enumerator to next item, or the first item if
+ /// this is the first call to MoveNext.
+ /// </summary>
+ /// <returns>True if enumerator is valid now</returns>
+ public bool MoveNext() { return enumerator.MoveNext(); }
+
+
+ /// <summary>
+ /// Undefined if enumerator is not valid (MoveNext hash been called returning true)
+ /// </summary>
+ /// <value>The current item of the wrapped enumerator.</value>
+ public T Current { get { return enumerator.Current; } }
+
+ #endregion
+
+ #region IDisposable Members
+
+ //TODO: consider possible danger of calling through to Dispose.
+ /// <summary>
+ /// Dispose wrapped enumerator.
+ /// </summary>
+ public void Dispose() { enumerator.Dispose(); }
+
+ #endregion
+
+
+ #region IEnumerator Members
+
+ object System.Collections.IEnumerator.Current
+ {
+ get { return enumerator.Current; }
+ }
+
+ void System.Collections.IEnumerator.Reset()
+ {
+ enumerator.Reset();
+ }
+
+ #endregion
+ }
+
+
+
+ /// <summary>
+ /// A read-only wrapper class for a generic enumerable
+ ///
+ /// <i>This is mainly interesting as a base of other guard classes</i>
+ /// </summary>
+ public class GuardedEnumerable<T> : SCG.IEnumerable<T>
+ {
+ #region Fields
+
+ SCG.IEnumerable<T> enumerable;
+
+ #endregion
+
+ #region Constructor
+
+ /// <summary>
+ /// Wrap an enumerable in a read-only wrapper
+ /// </summary>
+ /// <param name="enumerable">The enumerable to wrap</param>
+ public GuardedEnumerable(SCG.IEnumerable<T> enumerable)
+ { this.enumerable = enumerable; }
+
+ #endregion
+
+ #region SCG.IEnumerable<T> Members
+
+ /// <summary>
+ /// Get an enumerator from the wrapped enumerable
+ /// </summary>
+ /// <returns>The enumerator (itself wrapped)</returns>
+ public SCG.IEnumerator<T> GetEnumerator()
+ { return new GuardedEnumerator<T>(enumerable.GetEnumerator()); }
+
+ #endregion
+
+ #region IEnumerable Members
+
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ #endregion
+
+ }
+
+
+
+ /// <summary>
+ /// A read-only wrapper for a generic directed enumerable
+ ///
+ /// <i>This is mainly interesting as a base of other guard classes</i>
+ /// </summary>
+ public class GuardedDirectedEnumerable<T> : GuardedEnumerable<T>, IDirectedEnumerable<T>
+ {
+ #region Fields
+
+ IDirectedEnumerable<T> directedenumerable;
+
+ #endregion
+
+ #region Constructor
+
+ /// <summary>
+ /// Wrap a directed enumerable in a read-only wrapper
+ /// </summary>
+ /// <param name="directedenumerable">the collection to wrap</param>
+ public GuardedDirectedEnumerable(IDirectedEnumerable<T> directedenumerable)
+ : base(directedenumerable)
+ { this.directedenumerable = directedenumerable; }
+
+ #endregion
+
+ #region IDirectedEnumerable<T> Members
+
+ /// <summary>
+ /// Get a enumerable that enumerates the wrapped collection in the opposite direction
+ /// </summary>
+ /// <returns>The mirrored enumerable</returns>
+ public IDirectedEnumerable<T> Backwards()
+ { return new GuardedDirectedEnumerable<T>(directedenumerable.Backwards()); }
+
+
+ /// <summary>
+ /// <code>Forwards</code> if same, else <code>Backwards</code>
+ /// </summary>
+ /// <value>The enumeration direction relative to the original collection.</value>
+ public EnumerationDirection Direction
+ { get { return directedenumerable.Direction; } }
+
+ #endregion
+ }
+
+
+
+ /// <summary>
+ /// A read-only wrapper for an ICollectionValue&lt;T&gt;
+ ///
+ /// <i>This is mainly interesting as a base of other guard classes</i>
+ /// </summary>
+ public class GuardedCollectionValue<T> : GuardedEnumerable<T>, ICollectionValue<T>
+ {
+ #region Events
+ /// <summary>
+ /// The ListenableEvents value of the wrapped collection
+ /// </summary>
+ /// <value></value>
+ public virtual EventTypeEnum ListenableEvents { get { return collectionvalue.ListenableEvents; } }
+
+ /// <summary>
+ /// The ActiveEvents value of the wrapped collection
+ /// </summary>
+ /// <value></value>
+ public virtual EventTypeEnum ActiveEvents { get { return collectionvalue.ActiveEvents; } }
+
+ ProxyEventBlock<T> eventBlock;
+ /// <summary>
+ /// The change event. Will be raised for every change operation on the collection.
+ /// </summary>
+ public event CollectionChangedHandler<T> CollectionChanged
+ {
+ add { (eventBlock ?? (eventBlock = new ProxyEventBlock<T>(this, collectionvalue))).CollectionChanged += value; }
+ remove { if (eventBlock != null) eventBlock.CollectionChanged -= value; }
+ }
+
+ /// <summary>
+ /// The change event. Will be raised for every change operation on the collection.
+ /// </summary>
+ public event CollectionClearedHandler<T> CollectionCleared
+ {
+ add { (eventBlock ?? (eventBlock = new ProxyEventBlock<T>(this, collectionvalue))).CollectionCleared += value; }
+ remove { if (eventBlock != null) eventBlock.CollectionCleared -= value; }
+ }
+
+ /// <summary>
+ /// The item added event. Will be raised for every individual addition to the collection.
+ /// </summary>
+ public event ItemsAddedHandler<T> ItemsAdded
+ {
+ add { (eventBlock ?? (eventBlock = new ProxyEventBlock<T>(this, collectionvalue))).ItemsAdded += value; }
+ remove { if (eventBlock != null) eventBlock.ItemsAdded -= value; }
+ }
+
+ /// <summary>
+ /// The item added event. Will be raised for every individual addition to the collection.
+ /// </summary>
+ public event ItemInsertedHandler<T> ItemInserted
+ {
+ add { (eventBlock ?? (eventBlock = new ProxyEventBlock<T>(this, collectionvalue))).ItemInserted += value; }
+ remove { if (eventBlock != null) eventBlock.ItemInserted -= value; }
+ }
+
+ /// <summary>
+ /// The item removed event. Will be raised for every individual removal from the collection.
+ /// </summary>
+ public event ItemsRemovedHandler<T> ItemsRemoved
+ {
+ add { (eventBlock ?? (eventBlock = new ProxyEventBlock<T>(this, collectionvalue))).ItemsRemoved += value; }
+ remove { if (eventBlock != null) eventBlock.ItemsRemoved -= value; }
+ }
+
+ /// <summary>
+ /// The item removed event. Will be raised for every individual removal from the collection.
+ /// </summary>
+ public event ItemRemovedAtHandler<T> ItemRemovedAt
+ {
+ add { (eventBlock ?? (eventBlock = new ProxyEventBlock<T>(this, collectionvalue))).ItemRemovedAt += value; }
+ remove { if (eventBlock != null) eventBlock.ItemRemovedAt -= value; }
+ }
+ #endregion
+
+ #region Fields
+
+ ICollectionValue<T> collectionvalue;
+
+ #endregion
+
+ #region Constructor
+
+ /// <summary>
+ /// Wrap a ICollectionValue&lt;T&gt; in a read-only wrapper
+ /// </summary>
+ /// <param name="collectionvalue">the collection to wrap</param>
+ public GuardedCollectionValue(ICollectionValue<T> collectionvalue)
+ : base(collectionvalue)
+ { this.collectionvalue = collectionvalue; }
+
+ #endregion
+
+ #region ICollection<T> Members
+
+ /// <summary>
+ /// Get the size of the wrapped collection
+ /// </summary>
+ /// <value>The size</value>
+ public virtual bool IsEmpty { get { return collectionvalue.IsEmpty; } }
+
+ /// <summary>
+ /// Get the size of the wrapped collection
+ /// </summary>
+ /// <value>The size</value>
+ public virtual int Count { get { return collectionvalue.Count; } }
+
+ /// <summary>
+ /// The value is symbolic indicating the type of asymptotic complexity
+ /// in terms of the size of this collection (worst-case or amortized as
+ /// relevant).
+ /// </summary>
+ /// <value>A characterization of the speed of the
+ /// <code>Count</code> property in this collection.</value>
+ public virtual Speed CountSpeed { get { return collectionvalue.CountSpeed; } }
+
+ /// <summary>
+ /// Copy the items of the wrapped collection to an array
+ /// </summary>
+ /// <param name="a">The array</param>
+ /// <param name="i">Starting offset</param>
+ public virtual void CopyTo(T[] a, int i) { collectionvalue.CopyTo(a, i); }
+
+ /// <summary>
+ /// Create an array from the items of the wrapped collection
+ /// </summary>
+ /// <returns>The array</returns>
+ public virtual T[] ToArray() { return collectionvalue.ToArray(); }
+
+ /// <summary>
+ /// Apply a delegate to all items of the wrapped enumerable.
+ /// </summary>
+ /// <param name="a">The delegate to apply</param>
+ //TODO: change this to throw an exception?
+ public virtual void Apply(Act<T> a) { collectionvalue.Apply(a); }
+
+
+ /// <summary>
+ /// Check if there exists an item that satisfies a
+ /// specific predicate in the wrapped enumerable.
+ /// </summary>
+ /// <param name="filter">A filter delegate
+ /// (<see cref="T:C5.Filter`1"/>) defining the predicate</param>
+ /// <returns>True is such an item exists</returns>
+ public virtual bool Exists(Fun<T, bool> filter) { return collectionvalue.Exists(filter); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="filter"></param>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public virtual bool Find(Fun<T, bool> filter, out T item) { return collectionvalue.Find(filter, out item); }
+
+ /// <summary>
+ /// Check if all items in the wrapped enumerable satisfies a specific predicate.
+ /// </summary>
+ /// <param name="filter">A filter delegate
+ /// (<see cref="T:C5.Filter`1"/>) defining the predicate</param>
+ /// <returns>True if all items satisfies the predicate</returns>
+ public virtual bool All(Fun<T, bool> filter) { return collectionvalue.All(filter); }
+
+ /// <summary>
+ /// Create an enumerable, enumerating the items of this collection that satisfies
+ /// a certain condition.
+ /// </summary>
+ /// <param name="filter">The T->bool filter delegate defining the condition</param>
+ /// <returns>The filtered enumerable</returns>
+ public virtual SCG.IEnumerable<T> Filter(Fun<T, bool> filter) { return collectionvalue.Filter(filter); }
+
+ /// <summary>
+ /// Choose some item of this collection.
+ /// </summary>
+ /// <exception cref="NoSuchItemException">if collection is empty.</exception>
+ /// <returns></returns>
+ public virtual T Choose() { return collectionvalue.Choose(); }
+
+ #endregion
+
+ #region IShowable Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="stringbuilder"></param>
+ /// <param name="formatProvider"></param>
+ /// <param name="rest"></param>
+ /// <returns></returns>
+ public bool Show(System.Text.StringBuilder stringbuilder, ref int rest, IFormatProvider formatProvider)
+ {
+ return collectionvalue.Show(stringbuilder, ref rest, formatProvider);
+ }
+ #endregion
+
+ #region IFormattable Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="format"></param>
+ /// <param name="formatProvider"></param>
+ /// <returns></returns>
+ public string ToString(string format, IFormatProvider formatProvider)
+ {
+ return collectionvalue.ToString(format, formatProvider);
+ }
+
+ #endregion
+ }
+
+
+
+ /// <summary>
+ /// A read-only wrapper for a directed collection
+ ///
+ /// <i>This is mainly interesting as a base of other guard classes</i>
+ /// </summary>
+ public class GuardedDirectedCollectionValue<T> : GuardedCollectionValue<T>, IDirectedCollectionValue<T>
+ {
+ #region Fields
+
+ IDirectedCollectionValue<T> directedcollection;
+
+ #endregion
+
+ #region Constructor
+
+ /// <summary>
+ /// Wrap a directed collection in a read-only wrapper
+ /// </summary>
+ /// <param name="directedcollection">the collection to wrap</param>
+ public GuardedDirectedCollectionValue(IDirectedCollectionValue<T> directedcollection)
+ :
+ base(directedcollection)
+ { this.directedcollection = directedcollection; }
+
+ #endregion
+
+ #region IDirectedCollection<T> Members
+
+ /// <summary>
+ /// Get a collection that enumerates the wrapped collection in the opposite direction
+ /// </summary>
+ /// <returns>The mirrored collection</returns>
+ public virtual IDirectedCollectionValue<T> Backwards()
+ { return new GuardedDirectedCollectionValue<T>(directedcollection.Backwards()); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="predicate"></param>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public virtual bool FindLast(Fun<T, bool> predicate, out T item) { return directedcollection.FindLast(predicate, out item); }
+
+ #endregion
+
+ #region IDirectedEnumerable<T> Members
+
+ IDirectedEnumerable<T> IDirectedEnumerable<T>.Backwards()
+ { return Backwards(); }
+
+
+ /// <summary>
+ /// <code>Forwards</code> if same, else <code>Backwards</code>
+ /// </summary>
+ /// <value>The enumeration direction relative to the original collection.</value>
+ public EnumerationDirection Direction
+ { get { return directedcollection.Direction; } }
+
+ #endregion
+ }
+
+
+
+ /// <summary>
+ /// A read-only wrapper for an <see cref="T:C5.ICollection`1"/>,
+ /// <para>
+ /// <i>Suitable for wrapping hash tables, <see cref="T:C5.HashSet`1"/>
+ /// and <see cref="T:C5.HashBag`1"/> </i></para>
+ /// </summary>
+ public class GuardedCollection<T> : GuardedCollectionValue<T>, ICollection<T>
+ {
+ #region Fields
+
+ ICollection<T> collection;
+
+ #endregion
+
+ #region Constructor
+
+ /// <summary>
+ /// Wrap an ICollection&lt;T&gt; in a read-only wrapper
+ /// </summary>
+ /// <param name="collection">the collection to wrap</param>
+ public GuardedCollection(ICollection<T> collection)
+ : base(collection)
+ {
+ this.collection = collection;
+ }
+
+ #endregion
+
+ #region ICollection<T> Members
+
+ /// <summary>
+ /// (This is a read-only wrapper)
+ /// </summary>
+ /// <value>True</value>
+ public virtual bool IsReadOnly { get { return true; } }
+
+
+ /// <summary> </summary>
+ /// <value>Speed of wrapped collection</value>
+ public virtual Speed ContainsSpeed { get { return collection.ContainsSpeed; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public virtual int GetUnsequencedHashCode()
+ { return collection.GetUnsequencedHashCode(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="that"></param>
+ /// <returns></returns>
+ public virtual bool UnsequencedEquals(ICollection<T> that)
+ { return collection.UnsequencedEquals(that); }
+
+
+ /// <summary>
+ /// Check if an item is in the wrapped collection
+ /// </summary>
+ /// <param name="item">The item</param>
+ /// <returns>True if found</returns>
+ public virtual bool Contains(T item) { return collection.Contains(item); }
+
+
+ /// <summary>
+ /// Count the number of times an item appears in the wrapped collection
+ /// </summary>
+ /// <param name="item">The item</param>
+ /// <returns>The number of copies</returns>
+ public virtual int ContainsCount(T item) { return collection.ContainsCount(item); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public virtual ICollectionValue<T> UniqueItems() { return new GuardedCollectionValue<T>(collection.UniqueItems()); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public virtual ICollectionValue<KeyValuePair<T, int>> ItemMultiplicities() { return new GuardedCollectionValue<KeyValuePair<T, int>>(collection.ItemMultiplicities()); }
+
+ /// <summary>
+ /// Check if all items in the argument is in the wrapped collection
+ /// </summary>
+ /// <param name="items">The items</param>
+ /// <typeparam name="U"></typeparam>
+ /// <returns>True if so</returns>
+ public virtual bool ContainsAll<U>(SCG.IEnumerable<U> items) where U : T { return collection.ContainsAll(items); }
+
+ /// <summary>
+ /// Search for an item in the wrapped collection
+ /// </summary>
+ /// <param name="item">On entry the item to look for, on exit the equivalent item found (if any)</param>
+ /// <returns></returns>
+ public virtual bool Find(ref T item) { return collection.Find(ref item); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public virtual bool FindOrAdd(ref T item)
+ { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public virtual bool Update(T item)
+ { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="item"></param>
+ /// <param name="olditem"></param>
+ /// <returns></returns>
+ public virtual bool Update(T item, out T olditem)
+ { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public virtual bool UpdateOrAdd(T item)
+ { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="item"></param>
+ /// <param name="olditem"></param>
+ /// <returns></returns>
+ public virtual bool UpdateOrAdd(T item, out T olditem)
+ { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public virtual bool Remove(T item)
+ { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="item">The value to remove.</param>
+ /// <param name="removeditem">The removed value.</param>
+ /// <returns></returns>
+ public virtual bool Remove(T item, out T removeditem)
+ { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="item"></param>
+ public virtual void RemoveAllCopies(T item)
+ { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <typeparam name="U"></typeparam>
+ /// <param name="items"></param>
+ public virtual void RemoveAll<U>(SCG.IEnumerable<U> items) where U : T
+ { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ public virtual void Clear()
+ { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <typeparam name="U"></typeparam>
+ /// <param name="items"></param>
+ public virtual void RetainAll<U>(SCG.IEnumerable<U> items) where U : T
+ { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
+
+ /// <summary>
+ /// Check wrapped collection for internal consistency
+ /// </summary>
+ /// <returns>True if check passed</returns>
+ public virtual bool Check() { return collection.Check(); }
+
+ #endregion
+
+ #region IExtensible<T> Members
+
+ /// <summary> </summary>
+ /// <value>False if wrapped collection has set semantics</value>
+ public virtual bool AllowsDuplicates { get { return collection.AllowsDuplicates; } }
+
+ //TODO: the equalityComparer should be guarded
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public virtual SCG.IEqualityComparer<T> EqualityComparer { get { return collection.EqualityComparer; } }
+
+ /// <summary>
+ /// By convention this is true for any collection with set semantics.
+ /// </summary>
+ /// <value>True if only one representative of a group of equal items
+ /// is kept in the collection together with the total count.</value>
+ public virtual bool DuplicatesByCounting { get { return collection.DuplicatesByCounting; } }
+
+
+ /// <summary> </summary>
+ /// <value>True if wrapped collection is empty</value>
+ public override bool IsEmpty { get { return collection.IsEmpty; } }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public virtual bool Add(T item)
+ { throw new ReadOnlyCollectionException(); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <typeparam name="U"></typeparam>
+ /// <param name="items"></param>
+ public virtual void AddAll<U>(SCG.IEnumerable<U> items) where U : T
+ { throw new ReadOnlyCollectionException(); }
+
+ #endregion
+
+ #region ICloneable Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public virtual object Clone()
+ {
+ return new GuardedCollection<T>((ICollection<T>)(collection.Clone()));
+ }
+
+ #endregion
+
+ }
+
+
+ /// <summary>
+ /// A read-only wrapper for a sequenced collection
+ ///
+ /// <i>This is mainly interesting as a base of other guard classes</i>
+ /// </summary>
+ public class GuardedSequenced<T> : GuardedCollection<T>, ISequenced<T>
+ {
+ #region Fields
+
+ ISequenced<T> sequenced;
+
+ #endregion
+
+ #region Constructor
+
+ /// <summary>
+ /// Wrap a sequenced collection in a read-only wrapper
+ /// </summary>
+ /// <param name="sorted"></param>
+ public GuardedSequenced(ISequenced<T> sorted) : base(sorted) { this.sequenced = sorted; }
+
+ #endregion
+
+ /// <summary>
+ /// Check if there exists an item that satisfies a
+ /// specific predicate in this collection and return the index of the first one.
+ /// </summary>
+ /// <param name="predicate">A delegate
+ /// (<see cref="T:C5.Fun`2"/> with <code>R == bool</code>) defining the predicate</param>
+ /// <returns>the index, if found, a negative value else</returns>
+ public int FindIndex(Fun<T, bool> predicate)
+ {
+ IIndexed<T> indexed = sequenced as IIndexed<T>;
+ if (indexed != null)
+ return indexed.FindIndex(predicate);
+ int index = 0;
+ foreach (T item in this)
+ {
+ if (predicate(item))
+ return index;
+ index++;
+ }
+ return -1;
+ }
+
+ /// <summary>
+ /// Check if there exists an item that satisfies a
+ /// specific predicate in this collection and return the index of the last one.
+ /// </summary>
+ /// <param name="predicate">A delegate
+ /// (<see cref="T:C5.Fun`2"/> with <code>R == bool</code>) defining the predicate</param>
+ /// <returns>the index, if found, a negative value else</returns>
+ public int FindLastIndex(Fun<T, bool> predicate)
+ {
+ IIndexed<T> indexed = sequenced as IIndexed<T>;
+ if (indexed != null)
+ return indexed.FindLastIndex(predicate);
+ int index = Count - 1;
+ foreach (T item in Backwards())
+ {
+ if (predicate(item))
+ return index;
+ index--;
+ }
+ return -1;
+ }
+
+
+
+ #region ISequenced<T> Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public int GetSequencedHashCode()
+ { return sequenced.GetSequencedHashCode(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="that"></param>
+ /// <returns></returns>
+ public bool SequencedEquals(ISequenced<T> that)
+ { return sequenced.SequencedEquals(that); }
+
+ #endregion
+
+ #region IDirectedCollection<T> Members
+
+ /// <summary>
+ /// Get a collection that enumerates the wrapped collection in the opposite direction
+ /// </summary>
+ /// <returns>The mirrored collection</returns>
+ public virtual IDirectedCollectionValue<T> Backwards()
+ { return new GuardedDirectedCollectionValue<T>(sequenced.Backwards()); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="predicate"></param>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public virtual bool FindLast(Fun<T, bool> predicate, out T item) { return sequenced.FindLast(predicate, out item); }
+
+ #endregion
+
+ #region IDirectedEnumerable<T> Members
+
+ IDirectedEnumerable<T> IDirectedEnumerable<T>.Backwards()
+ { return Backwards(); }
+
+
+
+ /// <summary>
+ /// <code>Forwards</code> if same, else <code>Backwards</code>
+ /// </summary>
+ /// <value>The enumeration direction relative to the original collection.</value>
+ public EnumerationDirection Direction
+ { get { return EnumerationDirection.Forwards; } }
+
+ #endregion
+
+ #region ICloneable Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public override object Clone()
+ {
+ return new GuardedCollection<T>((ISequenced<T>)(sequenced.Clone()));
+ }
+
+ #endregion
+
+ }
+
+
+ /// <summary>
+ /// A read-only wrapper for a sorted collection
+ ///
+ /// <i>This is mainly interesting as a base of other guard classes</i>
+ /// </summary>
+ public class GuardedSorted<T> : GuardedSequenced<T>, ISorted<T>
+ {
+ #region Fields
+
+ ISorted<T> sorted;
+
+ #endregion
+
+ #region Constructor
+
+ /// <summary>
+ /// Wrap a sorted collection in a read-only wrapper
+ /// </summary>
+ /// <param name="sorted"></param>
+ public GuardedSorted(ISorted<T> sorted) : base(sorted) { this.sorted = sorted; }
+
+ #endregion
+
+ #region ISorted<T> Members
+
+ /// <summary>
+ /// Find the predecessor of the item in the wrapped sorted collection
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if no such element exists </exception>
+ /// <param name="item">The item</param>
+ /// <returns>The predecessor</returns>
+ public T Predecessor(T item) { return sorted.Predecessor(item); }
+
+
+ /// <summary>
+ /// Find the Successor of the item in the wrapped sorted collection
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if no such element exists </exception>
+ /// <param name="item">The item</param>
+ /// <returns>The Successor</returns>
+ public T Successor(T item) { return sorted.Successor(item); }
+
+
+ /// <summary>
+ /// Find the weak predecessor of the item in the wrapped sorted collection
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if no such element exists </exception>
+ /// <param name="item">The item</param>
+ /// <returns>The weak predecessor</returns>
+ public T WeakPredecessor(T item) { return sorted.WeakPredecessor(item); }
+
+
+ /// <summary>
+ /// Find the weak Successor of the item in the wrapped sorted collection
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if no such element exists </exception>
+ /// <param name="item">The item</param>
+ /// <returns>The weak Successor</returns>
+ public T WeakSuccessor(T item) { return sorted.WeakSuccessor(item); }
+
+
+ /// <summary>
+ /// Run Cut on the wrapped sorted collection
+ /// </summary>
+ /// <param name="c"></param>
+ /// <param name="low"></param>
+ /// <param name="lval"></param>
+ /// <param name="high"></param>
+ /// <param name="hval"></param>
+ /// <returns></returns>
+ public bool Cut(IComparable<T> c, out T low, out bool lval, out T high, out bool hval)
+ { return sorted.Cut(c, out low, out lval, out high, out hval); }
+
+
+ /// <summary>
+ /// Get the specified range from the wrapped collection.
+ /// (The current implementation erroneously does not wrap the result.)
+ /// </summary>
+ /// <param name="bot"></param>
+ /// <returns></returns>
+ public IDirectedEnumerable<T> RangeFrom(T bot) { return sorted.RangeFrom(bot); }
+
+
+ /// <summary>
+ /// Get the specified range from the wrapped collection.
+ /// (The current implementation erroneously does not wrap the result.)
+ /// </summary>
+ /// <param name="bot"></param>
+ /// <param name="top"></param>
+ /// <returns></returns>
+ public IDirectedEnumerable<T> RangeFromTo(T bot, T top)
+ { return sorted.RangeFromTo(bot, top); }
+
+
+ /// <summary>
+ /// Get the specified range from the wrapped collection.
+ /// (The current implementation erroneously does not wrap the result.)
+ /// </summary>
+ /// <param name="top"></param>
+ /// <returns></returns>
+ public IDirectedEnumerable<T> RangeTo(T top) { return sorted.RangeTo(top); }
+
+
+ /// <summary>
+ /// Get the specified range from the wrapped collection.
+ /// (The current implementation erroneously does not wrap the result.)
+ /// </summary>
+ /// <returns></returns>
+ public IDirectedCollectionValue<T> RangeAll() { return sorted.RangeAll(); }
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="items"></param>
+ /// <typeparam name="U"></typeparam>
+ public void AddSorted<U>(SCG.IEnumerable<U> items) where U : T
+ { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="low"></param>
+ public void RemoveRangeFrom(T low)
+ { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="low"></param>
+ /// <param name="hi"></param>
+ public void RemoveRangeFromTo(T low, T hi)
+ { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="hi"></param>
+ public void RemoveRangeTo(T hi)
+ { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
+
+ #endregion
+
+ #region IPriorityQueue<T> Members
+
+ /// <summary>
+ /// Find the minimum of the wrapped collection
+ /// </summary>
+ /// <returns>The minimum</returns>
+ public T FindMin() { return sorted.FindMin(); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <returns></returns>
+ public T DeleteMin()
+ { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
+
+
+ /// <summary>
+ /// Find the maximum of the wrapped collection
+ /// </summary>
+ /// <returns>The maximum</returns>
+ public T FindMax() { return sorted.FindMax(); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <returns></returns>
+ public T DeleteMax()
+ { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
+
+ //TODO: we should guard the comparer!
+ /// <summary>
+ /// The comparer object supplied at creation time for the underlying collection
+ /// </summary>
+ /// <value>The comparer</value>
+ public SCG.IComparer<T> Comparer { get { return sorted.Comparer; } }
+ #endregion
+
+ #region IDirectedEnumerable<T> Members
+
+ IDirectedEnumerable<T> IDirectedEnumerable<T>.Backwards()
+ { return Backwards(); }
+
+ #endregion
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public override object Clone()
+ {
+ return new GuardedSorted<T>((ISorted<T>)(sorted.Clone()));
+ }
+
+ }
+
+
+
+ /// <summary>
+ /// Read-only wrapper for indexed sorted collections
+ ///
+ /// <i>Suitable for wrapping TreeSet, TreeBag and SortedArray</i>
+ /// </summary>
+ public class GuardedIndexedSorted<T> : GuardedSorted<T>, IIndexedSorted<T>
+ {
+ #region Fields
+
+ IIndexedSorted<T> indexedsorted;
+
+ #endregion
+
+ #region Constructor
+
+ /// <summary>
+ /// Wrap an indexed sorted collection in a read-only wrapper
+ /// </summary>
+ /// <param name="list">the indexed sorted collection</param>
+ public GuardedIndexedSorted(IIndexedSorted<T> list)
+ : base(list)
+ { this.indexedsorted = list; }
+
+ #endregion
+
+ #region IIndexedSorted<T> Members
+
+ /// <summary>
+ /// Get the specified range from the wrapped collection.
+ /// (The current implementation erroneously does not wrap the result.)
+ /// </summary>
+ /// <param name="bot"></param>
+ /// <returns></returns>
+ public new IDirectedCollectionValue<T> RangeFrom(T bot)
+ { return indexedsorted.RangeFrom(bot); }
+
+
+ /// <summary>
+ /// Get the specified range from the wrapped collection.
+ /// (The current implementation erroneously does not wrap the result.)
+ /// </summary>
+ /// <param name="bot"></param>
+ /// <param name="top"></param>
+ /// <returns></returns>
+ public new IDirectedCollectionValue<T> RangeFromTo(T bot, T top)
+ { return indexedsorted.RangeFromTo(bot, top); }
+
+
+ /// <summary>
+ /// Get the specified range from the wrapped collection.
+ /// (The current implementation erroneously does not wrap the result.)
+ /// </summary>
+ /// <param name="top"></param>
+ /// <returns></returns>
+ public new IDirectedCollectionValue<T> RangeTo(T top)
+ { return indexedsorted.RangeTo(top); }
+
+
+ /// <summary>
+ /// Report the number of items in the specified range of the wrapped collection
+ /// </summary>
+ /// <param name="bot"></param>
+ /// <returns></returns>
+ public int CountFrom(T bot) { return indexedsorted.CountFrom(bot); }
+
+
+ /// <summary>
+ /// Report the number of items in the specified range of the wrapped collection
+ /// </summary>
+ /// <param name="bot"></param>
+ /// <param name="top"></param>
+ /// <returns></returns>
+ public int CountFromTo(T bot, T top) { return indexedsorted.CountFromTo(bot, top); }
+
+
+ /// <summary>
+ /// Report the number of items in the specified range of the wrapped collection
+ /// </summary>
+ /// <param name="top"></param>
+ /// <returns></returns>
+ public int CountTo(T top) { return indexedsorted.CountTo(top); }
+
+
+ /// <summary>
+ /// Run FindAll on the wrapped collection with the indicated filter.
+ /// The result will <b>not</b> be read-only.
+ /// </summary>
+ /// <param name="f"></param>
+ /// <returns></returns>
+ public IIndexedSorted<T> FindAll(Fun<T, bool> f)
+ { return indexedsorted.FindAll(f); }
+
+
+ /// <summary>
+ /// Run Map on the wrapped collection with the indicated mapper.
+ /// The result will <b>not</b> be read-only.
+ /// </summary>
+ /// <param name="m"></param>
+ /// <param name="c">The comparer to use in the result</param>
+ /// <returns></returns>
+ public IIndexedSorted<V> Map<V>(Fun<T, V> m, SCG.IComparer<V> c)
+ { return indexedsorted.Map(m, c); }
+
+ #endregion
+
+ #region IIndexed<T> Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>The i'th item of the wrapped sorted collection</value>
+ public T this[int i] { get { return indexedsorted[i]; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public virtual Speed IndexingSpeed { get { return indexedsorted.IndexingSpeed; } }
+
+ /// <summary> </summary>
+ /// <value>A directed collection of the items in the indicated interval of the wrapped collection</value>
+ public IDirectedCollectionValue<T> this[int start, int end]
+ { get { return new GuardedDirectedCollectionValue<T>(indexedsorted[start, end]); } }
+
+
+ /// <summary>
+ /// Find the (first) index of an item in the wrapped collection
+ /// </summary>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public int IndexOf(T item) { return indexedsorted.IndexOf(item); }
+
+
+ /// <summary>
+ /// Find the last index of an item in the wrapped collection
+ /// </summary>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public int LastIndexOf(T item) { return indexedsorted.LastIndexOf(item); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="i"></param>
+ /// <returns></returns>
+ public T RemoveAt(int i)
+ { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="start"></param>
+ /// <param name="count"></param>
+ public void RemoveInterval(int start, int count)
+ { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
+
+ #endregion
+
+ #region IDirectedEnumerable<T> Members
+
+ IDirectedEnumerable<T> IDirectedEnumerable<T>.Backwards()
+ { return Backwards(); }
+
+ #endregion
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public override object Clone()
+ {
+ return new GuardedIndexedSorted<T>((IIndexedSorted<T>)(indexedsorted.Clone()));
+ }
+
+ }
+
+
+
+ /// <summary>
+ /// A read-only wrapper for a generic list collection
+ /// <i>Suitable as a wrapper for LinkedList, HashedLinkedList, ArrayList and HashedArray.
+ /// <see cref="T:C5.LinkedList`1"/>,
+ /// <see cref="T:C5.HashedLinkedList`1"/>,
+ /// <see cref="T:C5.ArrayList`1"/> or
+ /// <see cref="T:C5.HashedArray`1"/>.
+ /// </i>
+ /// </summary>
+ public class GuardedList<T> : GuardedSequenced<T>, IList<T>
+ {
+ #region Fields
+
+ IList<T> innerlist;
+ GuardedList<T> underlying;
+ bool slidableView = false;
+
+ #endregion
+
+ #region Constructor
+
+ /// <summary>
+ /// Wrap a list in a read-only wrapper
+ /// </summary>
+ /// <param name="list">The list</param>
+ public GuardedList(IList<T> list)
+ : base(list)
+ {
+ this.innerlist = list;
+ if (list.Underlying != null)
+ underlying = new GuardedList<T>(list.Underlying, null, false);
+ }
+
+ GuardedList(IList<T> list, GuardedList<T> underlying, bool slidableView)
+ : base(list)
+ {
+ this.innerlist = list; this.underlying = underlying; this.slidableView = slidableView;
+ }
+ #endregion
+
+ #region IList<T> Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>The first item of the wrapped list</value>
+ public T First { get { return innerlist.First; } }
+
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>The last item of the wrapped list</value>
+ public T Last { get { return innerlist.Last; } }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> if used as setter</exception>
+ /// <value>True if wrapped list has FIFO semantics for the Add(T item) and Remove() methods</value>
+ public bool FIFO
+ {
+ get { return innerlist.FIFO; }
+ set { throw new ReadOnlyCollectionException("List is read only"); }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ public virtual bool IsFixedSize
+ {
+ get { return true; }
+ }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> if used as setter</exception>
+ /// <value>The i'th item of the wrapped list</value>
+ public T this[int i]
+ {
+ get { return innerlist[i]; }
+ set { throw new ReadOnlyCollectionException("List is read only"); }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public virtual Speed IndexingSpeed { get { return innerlist.IndexingSpeed; } }
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="i"></param>
+ /// <param name="item"></param>
+ public void Insert(int i, T item)
+ { throw new ReadOnlyCollectionException(); }
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="pointer"></param>
+ /// <param name="item"></param>
+ public void Insert(IList<T> pointer, T item)
+ { throw new ReadOnlyCollectionException(); }
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="item"></param>
+ public void InsertFirst(T item)
+ { throw new ReadOnlyCollectionException("List is read only"); }
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="item"></param>
+ public void InsertLast(T item)
+ { throw new ReadOnlyCollectionException("List is read only"); }
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="item"></param>
+ /// <param name="target"></param>
+ public void InsertBefore(T item, T target)
+ { throw new ReadOnlyCollectionException("List is read only"); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="item"></param>
+ /// <param name="target"></param>
+ public void InsertAfter(T item, T target)
+ { throw new ReadOnlyCollectionException("List is read only"); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="i"></param>
+ /// <param name="items"></param>
+ public void InsertAll<U>(int i, SCG.IEnumerable<U> items) where U : T
+ { throw new ReadOnlyCollectionException("List is read only"); }
+
+
+ /// <summary>
+ /// Perform FindAll on the wrapped list. The result is <b>not</b> necessarily read-only.
+ /// </summary>
+ /// <param name="filter">The filter to use</param>
+ /// <returns></returns>
+ public IList<T> FindAll(Fun<T, bool> filter) { return innerlist.FindAll(filter); }
+
+
+ /// <summary>
+ /// Perform Map on the wrapped list. The result is <b>not</b> necessarily read-only.
+ /// </summary>
+ /// <typeparam name="V">The type of items of the new list</typeparam>
+ /// <param name="mapper">The mapper to use.</param>
+ /// <returns>The mapped list</returns>
+ public IList<V> Map<V>(Fun<T, V> mapper) { return innerlist.Map(mapper); }
+
+ /// <summary>
+ /// Perform Map on the wrapped list. The result is <b>not</b> necessarily read-only.
+ /// </summary>
+ /// <typeparam name="V">The type of items of the new list</typeparam>
+ /// <param name="mapper">The delegate defining the map.</param>
+ /// <param name="itemequalityComparer">The itemequalityComparer to use for the new list</param>
+ /// <returns>The new list.</returns>
+ public IList<V> Map<V>(Fun<T, V> mapper, SCG.IEqualityComparer<V> itemequalityComparer) { return innerlist.Map(mapper, itemequalityComparer); }
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <returns></returns>
+ public T Remove() { throw new ReadOnlyCollectionException("List is read only"); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <returns></returns>
+ public T RemoveFirst() { throw new ReadOnlyCollectionException("List is read only"); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <returns></returns>
+ public T RemoveLast() { throw new ReadOnlyCollectionException("List is read only"); }
+
+
+ /// <summary>
+ /// Create the indicated view on the wrapped list and wrap it read-only.
+ /// </summary>
+ /// <param name="start"></param>
+ /// <param name="count"></param>
+ /// <returns></returns>
+ public IList<T> View(int start, int count)
+ {
+ IList<T> view = innerlist.View(start, count);
+ return view == null ? null : new GuardedList<T>(view, underlying ?? this, true);
+ }
+
+ /// <summary>
+ /// Create the indicated view on the wrapped list and wrap it read-only.
+ /// </summary>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public IList<T> ViewOf(T item)
+ {
+ IList<T> view = innerlist.ViewOf(item);
+ return view == null ? null : new GuardedList<T>(view, underlying ?? this, true);
+ }
+
+ /// <summary>
+ /// Create the indicated view on the wrapped list and wrap it read-only.
+ /// </summary>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public IList<T> LastViewOf(T item)
+ {
+ IList<T> view = innerlist.LastViewOf(item);
+ return view == null ? null : new GuardedList<T>(view, underlying ?? this, true);
+ }
+
+
+ /// <summary>
+ /// </summary>
+ /// <value>The wrapped underlying list of the wrapped view </value>
+ public IList<T> Underlying { get { return underlying; } }
+
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>The offset of the wrapped list as a view.</value>
+ public int Offset { get { return innerlist.Offset; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public virtual bool IsValid { get { return innerlist.IsValid; } }
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> if this is a wrapped view and not a view that was made on a wrapper</exception>
+ /// <param name="offset"></param>
+ public IList<T> Slide(int offset)
+ {
+ if (slidableView)
+ {
+ innerlist.Slide(offset);
+ return this;
+ }
+ else
+ throw new ReadOnlyCollectionException("List is read only");
+ }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="offset"></param>
+ /// <param name="size"></param>
+ public IList<T> Slide(int offset, int size)
+ {
+ if (slidableView)
+ {
+ innerlist.Slide(offset, size);
+ return this;
+ }
+ else
+ throw new ReadOnlyCollectionException("List is read only");
+ }
+
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="offset"></param>
+ /// <returns></returns>
+ public bool TrySlide(int offset)
+ {
+ if (slidableView)
+ return innerlist.TrySlide(offset);
+ else
+ throw new ReadOnlyCollectionException("List is read only");
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="offset"></param>
+ /// <param name="size"></param>
+ /// <returns></returns>
+ public bool TrySlide(int offset, int size)
+ {
+ if (slidableView)
+ return innerlist.TrySlide(offset, size);
+ else
+ throw new ReadOnlyCollectionException("List is read only");
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="otherView"></param>
+ /// <returns></returns>
+ public IList<T> Span(IList<T> otherView)
+ {
+ GuardedList<T> otherGuardedList = otherView as GuardedList<T>;
+ if (otherGuardedList == null)
+ throw new IncompatibleViewException();
+ IList<T> span = innerlist.Span(otherGuardedList.innerlist);
+ if (span == null)
+ return null;
+ return new GuardedList<T>(span, underlying ?? otherGuardedList.underlying ?? this, true);
+ }
+
+ /// <summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// </summary>
+ public void Reverse() { throw new ReadOnlyCollectionException("List is read only"); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="start"></param>
+ /// <param name="count"></param>
+ public void Reverse(int start, int count)
+ { throw new ReadOnlyCollectionException("List is read only"); }
+
+
+ /// <summary>
+ /// Check if wrapped list is sorted according to the default sorting order
+ /// for the item type T, as defined by the <see cref="T:C5.Comparer`1"/> class
+ /// </summary>
+ /// <exception cref="NotComparableException">if T is not comparable</exception>
+ /// <returns>True if the list is sorted, else false.</returns>
+ public bool IsSorted() { return innerlist.IsSorted(Comparer<T>.Default); }
+
+ /// <summary>
+ /// Check if wrapped list is sorted
+ /// </summary>
+ /// <param name="c">The sorting order to use</param>
+ /// <returns>True if sorted</returns>
+ public bool IsSorted(SCG.IComparer<T> c) { return innerlist.IsSorted(c); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ public void Sort()
+ { throw new ReadOnlyCollectionException("List is read only"); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="c"></param>
+ public void Sort(SCG.IComparer<T> c)
+ { throw new ReadOnlyCollectionException("List is read only"); }
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ public void Shuffle()
+ { throw new ReadOnlyCollectionException("List is read only"); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="rnd"></param>
+ public void Shuffle(Random rnd)
+ { throw new ReadOnlyCollectionException("List is read only"); }
+
+ #endregion
+
+ #region IIndexed<T> Members
+
+ /// <summary> </summary>
+ /// <value>A directed collection of the items in the indicated interval of the wrapped collection</value>
+ public IDirectedCollectionValue<T> this[int start, int end]
+ { get { return new GuardedDirectedCollectionValue<T>(innerlist[start, end]); } }
+
+
+ /// <summary>
+ /// Find the (first) index of an item in the wrapped collection
+ /// </summary>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public int IndexOf(T item) { return innerlist.IndexOf(item); }
+
+
+ /// <summary>
+ /// Find the last index of an item in the wrapped collection
+ /// </summary>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public int LastIndexOf(T item) { return innerlist.LastIndexOf(item); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="i"></param>
+ /// <returns></returns>
+ public T RemoveAt(int i)
+ { throw new ReadOnlyCollectionException("List is read only"); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="start"></param>
+ /// <param name="count"></param>
+ public void RemoveInterval(int start, int count)
+ { throw new ReadOnlyCollectionException("List is read only"); }
+
+ #endregion
+
+ #region IDirectedEnumerable<T> Members
+
+ IDirectedEnumerable<T> IDirectedEnumerable<T>.Backwards()
+ { return Backwards(); }
+
+ #endregion
+
+ #region IStack<T> Members
+
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <returns>-</returns>
+ public void Push(T item)
+ { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <returns>-</returns>
+ public T Pop()
+ { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
+
+ #endregion
+
+ #region IQueue<T> Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <returns>-</returns>
+ public void Enqueue(T item)
+ { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <returns>-</returns>
+ public T Dequeue()
+ { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
+
+ #endregion
+
+ #region IDisposable Members
+
+ /// <summary>
+ /// Ignore: this may be called by a foreach or using statement.
+ /// </summary>
+ public void Dispose() { }
+
+ #endregion
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public override object Clone()
+ {
+ return new GuardedList<T>((IList<T>)(innerlist.Clone()));
+ }
+
+ }
+
+ /// <summary>
+ /// A read-only wrapper for a generic indexable queue (allows indexing).
+ ///
+ /// <para>Suitable for wrapping a <see cref="T:C5.CircularQueue`1"/></para>
+ /// </summary>
+ /// <typeparam name="T">The item type.</typeparam>
+ public class GuardedQueue<T> : GuardedDirectedCollectionValue<T>, IQueue<T>
+ {
+ #region Fields
+
+ IQueue<T> queue;
+
+ #endregion
+
+ #region Constructor
+
+ /// <summary>
+ /// Wrap a queue in a read-only wrapper
+ /// </summary>
+ /// <param name="queue">The queue</param>
+ public GuardedQueue(IQueue<T> queue) : base(queue) { this.queue = queue; }
+
+ #endregion
+
+ #region IQueue<T> Members
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public bool AllowsDuplicates { get { return queue.AllowsDuplicates; } }
+
+ /// <summary>
+ /// Index into the wrapped queue
+ /// </summary>
+ /// <param name="i"></param>
+ /// <returns></returns>
+ public T this[int i] { get { return queue[i]; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <returns>-</returns>
+ public void Enqueue(T item)
+ { throw new ReadOnlyCollectionException("Queue cannot be modified through this guard object"); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <returns>-</returns>
+ public T Dequeue()
+ { throw new ReadOnlyCollectionException("Queue cannot be modified through this guard object"); }
+
+ #endregion
+ }
+
+ /// <summary>
+ /// A read-only wrapper for a dictionary.
+ ///
+ /// <i>Suitable for wrapping a HashDictionary. <see cref="T:C5.HashDictionary`2"/></i>
+ /// </summary>
+ public class GuardedDictionary<K, V> : GuardedCollectionValue<KeyValuePair<K, V>>, IDictionary<K, V>
+ {
+ #region Fields
+
+ IDictionary<K, V> dict;
+
+ #endregion
+
+ #region Constructor
+
+ /// <summary>
+ /// Wrap a dictionary in a read-only wrapper
+ /// </summary>
+ /// <param name="dict">the dictionary</param>
+ public GuardedDictionary(IDictionary<K, V> dict) : base(dict) { this.dict = dict; }
+
+ #endregion
+
+ #region IDictionary<K,V> Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public SCG.IEqualityComparer<K> EqualityComparer { get { return dict.EqualityComparer; } }
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a
+ /// read-only wrappper if used as a setter</exception>
+ /// <value>Get the value corresponding to a key in the wrapped dictionary</value>
+ public V this[K key]
+ {
+ get { return dict[key]; }
+ set { throw new ReadOnlyCollectionException(); }
+ }
+
+ /// <summary>
+ /// (This is a read-only wrapper)
+ /// </summary>
+ /// <value>True</value>
+ public bool IsReadOnly { get { return true; } }
+
+
+ //TODO: guard with a read-only wrapper? Probably so!
+ /// <summary> </summary>
+ /// <value>The collection of keys of the wrapped dictionary</value>
+ public ICollectionValue<K> Keys
+ { get { return dict.Keys; } }
+
+
+ /// <summary> </summary>
+ /// <value>The collection of values of the wrapped dictionary</value>
+ public ICollectionValue<V> Values { get { return dict.Values; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ public virtual Fun<K, V> Fun { get { return delegate(K k) { return this[k]; }; } }
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="key"></param>
+ /// <param name="val"></param>
+ public void Add(K key, V val)
+ { throw new ReadOnlyCollectionException(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="items"></param>
+ public void AddAll<L, W>(SCG.IEnumerable<KeyValuePair<L, W>> items)
+ where L : K
+ where W : V
+ { throw new ReadOnlyCollectionException(); }
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="key"></param>
+ /// <returns></returns>
+ public bool Remove(K key)
+ { throw new ReadOnlyCollectionException(); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="key"></param>
+ /// <param name="val"></param>
+ /// <returns></returns>
+ public bool Remove(K key, out V val)
+ { throw new ReadOnlyCollectionException(); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ public void Clear()
+ { throw new ReadOnlyCollectionException(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public Speed ContainsSpeed { get { return dict.ContainsSpeed; } }
+
+ /// <summary>
+ /// Check if the wrapped dictionary contains a specific key
+ /// </summary>
+ /// <param name="key">The key</param>
+ /// <returns>True if it does</returns>
+ public bool Contains(K key) { return dict.Contains(key); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="keys"></param>
+ /// <returns></returns>
+ public bool ContainsAll<H>(SCG.IEnumerable<H> keys) where H : K { return dict.ContainsAll(keys); }
+
+ /// <summary>
+ /// Search for a key in the wrapped dictionary, reporting the value if found
+ /// </summary>
+ /// <param name="key">The key</param>
+ /// <param name="val">On exit: the value if found</param>
+ /// <returns>True if found</returns>
+ public bool Find(K key, out V val) { return dict.Find(key, out val); }
+
+ /// <summary>
+ /// Search for a key in the wrapped dictionary, reporting the value if found
+ /// </summary>
+ /// <param name="key">The key</param>
+ /// <param name="val">On exit: the value if found</param>
+ /// <returns>True if found</returns>
+ public bool Find(ref K key, out V val) { return dict.Find(ref key, out val); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="key"></param>
+ /// <param name="val"></param>
+ /// <returns></returns>
+ public bool Update(K key, V val)
+ { throw new ReadOnlyCollectionException(); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="key"></param>
+ /// <param name="val"></param>
+ /// <param name="oldval"></param>
+ /// <returns></returns>
+ public bool Update(K key, V val, out V oldval)
+ { throw new ReadOnlyCollectionException(); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="key"></param>
+ /// <param name="val"></param>
+ /// <returns></returns>
+ public bool FindOrAdd(K key, ref V val)
+ { throw new ReadOnlyCollectionException(); }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="key"></param>
+ /// <param name="val"></param>
+ /// <returns></returns>
+ public bool UpdateOrAdd(K key, V val)
+ { throw new ReadOnlyCollectionException(); }
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="key"></param>
+ /// <param name="val"></param>
+ /// <param name="oldval"></param>
+ /// <returns></returns>
+ public bool UpdateOrAdd(K key, V val, out V oldval)
+ { throw new ReadOnlyCollectionException(); }
+
+
+ /// <summary>
+ /// Check the internal consistency of the wrapped dictionary
+ /// </summary>
+ /// <returns>True if check passed</returns>
+ public bool Check() { return dict.Check(); }
+
+ #endregion
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public virtual object Clone()
+ {
+ return new GuardedDictionary<K, V>((IDictionary<K, V>)(dict.Clone()));
+ }
+ }
+
+
+
+ /// <summary>
+ /// A read-only wrapper for a sorted dictionary.
+ ///
+ /// <i>Suitable for wrapping a Dictionary. <see cref="T:C5.Dictionary`2"/></i>
+ /// </summary>
+ public class GuardedSortedDictionary<K, V> : GuardedDictionary<K, V>, ISortedDictionary<K, V>
+ {
+ #region Fields
+
+ ISortedDictionary<K, V> sorteddict;
+
+ #endregion
+
+ #region Constructor
+
+ /// <summary>
+ /// Wrap a sorted dictionary in a read-only wrapper
+ /// </summary>
+ /// <param name="sorteddict">the dictionary</param>
+ public GuardedSortedDictionary(ISortedDictionary<K, V> sorteddict)
+ : base(sorteddict)
+ { this.sorteddict = sorteddict; }
+
+ #endregion
+
+ #region ISortedDictionary<K,V> Members
+
+ /// <summary>
+ /// The key comparer used by this dictionary.
+ /// </summary>
+ /// <value></value>
+ public SCG.IComparer<K> Comparer { get { return sorteddict.Comparer; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public new ISorted<K> Keys { get { return null; } }
+
+ /// <summary>
+ /// Get the entry in the wrapped dictionary whose key is the
+ /// predecessor of a specified key.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if no such entry exists </exception>
+ /// <param name="key">The key</param>
+ /// <returns>The entry</returns>
+ public KeyValuePair<K, V> Predecessor(K key)
+ { return sorteddict.Predecessor(key); }
+
+
+ /// <summary>
+ /// Get the entry in the wrapped dictionary whose key is the
+ /// successor of a specified key.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if no such entry exists </exception>
+ /// <param name="key">The key</param>
+ /// <returns>The entry</returns>
+ public KeyValuePair<K, V> Successor(K key)
+ { return sorteddict.Successor(key); }
+
+
+ /// <summary>
+ /// Get the entry in the wrapped dictionary whose key is the
+ /// weak predecessor of a specified key.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if no such entry exists </exception>
+ /// <param name="key">The key</param>
+ /// <returns>The entry</returns>
+ public KeyValuePair<K, V> WeakPredecessor(K key)
+ { return sorteddict.WeakPredecessor(key); }
+
+
+ /// <summary>
+ /// Get the entry in the wrapped dictionary whose key is the
+ /// weak successor of a specified key.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if no such entry exists </exception>
+ /// <param name="key">The key</param>
+ /// <returns>The entry</returns>
+ public KeyValuePair<K, V> WeakSuccessor(K key)
+ { return sorteddict.WeakSuccessor(key); }
+
+ #endregion
+
+ #region ISortedDictionary<K,V> Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public KeyValuePair<K, V> FindMin()
+ {
+ return sorteddict.FindMin();
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <returns></returns>
+ public KeyValuePair<K, V> DeleteMin()
+ { throw new ReadOnlyCollectionException(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public KeyValuePair<K, V> FindMax()
+ {
+ return sorteddict.FindMax();
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <returns></returns>
+ public KeyValuePair<K, V> DeleteMax()
+ { throw new ReadOnlyCollectionException(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="c"></param>
+ /// <param name="lowEntry"></param>
+ /// <param name="lowIsValid"></param>
+ /// <param name="highEntry"></param>
+ /// <param name="highIsValid"></param>
+ /// <returns></returns>
+ public bool Cut(IComparable<K> c, out KeyValuePair<K, V> lowEntry, out bool lowIsValid, out KeyValuePair<K, V> highEntry, out bool highIsValid)
+ {
+ return sorteddict.Cut(c, out lowEntry, out lowIsValid, out highEntry, out highIsValid); ;
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="bot"></param>
+ /// <returns></returns>
+ public IDirectedEnumerable<KeyValuePair<K, V>> RangeFrom(K bot)
+ {
+ return new GuardedDirectedEnumerable<KeyValuePair<K, V>>(sorteddict.RangeFrom(bot));
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="bot"></param>
+ /// <param name="top"></param>
+ /// <returns></returns>
+ public IDirectedEnumerable<KeyValuePair<K, V>> RangeFromTo(K bot, K top)
+ {
+ return new GuardedDirectedEnumerable<KeyValuePair<K, V>>(sorteddict.RangeFromTo(bot, top));
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="top"></param>
+ /// <returns></returns>
+ public IDirectedEnumerable<KeyValuePair<K, V>> RangeTo(K top)
+ {
+ return new GuardedDirectedEnumerable<KeyValuePair<K, V>>(sorteddict.RangeTo(top));
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public IDirectedCollectionValue<KeyValuePair<K, V>> RangeAll()
+ {
+ return new GuardedDirectedCollectionValue<KeyValuePair<K, V>>(sorteddict.RangeAll());
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="items"></param>
+ public void AddSorted(System.Collections.Generic.IEnumerable<KeyValuePair<K, V>> items)
+ { throw new ReadOnlyCollectionException(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="low"></param>
+ public void RemoveRangeFrom(K low)
+ { throw new ReadOnlyCollectionException(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="low"></param>
+ /// <param name="hi"></param>
+ public void RemoveRangeFromTo(K low, K hi)
+ { throw new ReadOnlyCollectionException(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
+ /// <param name="hi"></param>
+ public void RemoveRangeTo(K hi)
+ { throw new ReadOnlyCollectionException(); }
+
+ #endregion
+ }
+
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/C5/arrays/ArrayList.cs b/mcs/class/Mono.C5/C5/arrays/ArrayList.cs
new file mode 100644
index 00000000000..4ff7084ebc1
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/arrays/ArrayList.cs
@@ -0,0 +1,2536 @@
+
+/*
+ Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+#define HASHINDEXnot
+
+using System;
+using System.Diagnostics;
+using SCG = System.Collections.Generic;
+namespace C5
+{
+ /// <summary>
+ /// A list collection based on a plain dynamic array data structure.
+ /// Expansion of the internal array is performed by doubling on demand.
+ /// The internal array is only shrinked by the Clear method.
+ ///
+ /// <i>When the FIFO property is set to false this class works fine as a stack of T.
+ /// When the FIFO property is set to true the class will function as a (FIFO) queue
+ /// but very inefficiently, use a LinkedList (<see cref="T:C5.LinkedList`1"/>) instead.</i>
+ /// </summary>
+ [Serializable]
+ public class ArrayList<T> : ArrayBase<T>, IList<T> //, System.Runtime.Serialization.ISerializable
+#if HASHINDEX
+#else
+, IStack<T>, IQueue<T>
+#endif
+ {
+ #region Fields
+
+ /// <summary>
+ /// Has this list or view not been invalidated by some operation (by someone calling Dispose())
+ /// </summary>
+ bool isValid = true;
+
+ //TODO: wonder if we should save some memory on none-view situations by
+ // putting these three fields into a single ref field?
+ /// <summary>
+ /// The underlying list if we are a view, null else.
+ /// </summary>
+ ArrayList<T> underlying;
+ WeakViewList<ArrayList<T>> views;
+ WeakViewList<ArrayList<T>>.Node myWeakReference;
+
+ /// <summary>
+ /// The size of the underlying list.
+ /// </summary>
+ int underlyingsize { get { return (underlying ?? this).size; } }
+
+ /// <summary>
+ /// The underlying field of the FIFO property
+ /// </summary>
+ bool fIFO = false;
+
+#if HASHINDEX
+ HashSet<KeyValuePair<T, int>> itemIndex;
+#endif
+ #endregion
+ #region Events
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public override EventTypeEnum ListenableEvents { get { return underlying == null ? EventTypeEnum.All : EventTypeEnum.None; } }
+
+/*
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public override event CollectionChangedHandler<T> CollectionChanged
+ {
+ add
+ {
+ if (underlying == null)
+ base.CollectionChanged += value;
+ else
+ throw new UnlistenableEventException("Can't listen to a view");
+ }
+ remove
+ {
+ if (underlying == null)
+ base.CollectionChanged -= value;
+ else
+ throw new UnlistenableEventException("Can't listen to a view");
+ }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public override event CollectionClearedHandler<T> CollectionCleared
+ {
+ add
+ {
+ if (underlying == null)
+ base.CollectionCleared += value;
+ else
+ throw new UnlistenableEventException("Can't listen to a view");
+ }
+ remove
+ {
+ if (underlying == null)
+ base.CollectionCleared -= value;
+ else
+ throw new UnlistenableEventException("Can't listen to a view");
+ }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public override event ItemsAddedHandler<T> ItemsAdded
+ {
+ add
+ {
+ if (underlying == null)
+ base.ItemsAdded += value;
+ else
+ throw new UnlistenableEventException("Can't listen to a view");
+ }
+ remove
+ {
+ if (underlying == null)
+ base.ItemsAdded -= value;
+ else
+ throw new UnlistenableEventException("Can't listen to a view");
+ }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public override event ItemInsertedHandler<T> ItemInserted
+ {
+ add
+ {
+ if (underlying == null)
+ base.ItemInserted += value;
+ else
+ throw new UnlistenableEventException("Can't listen to a view");
+ }
+ remove
+ {
+ if (underlying == null)
+ base.ItemInserted -= value;
+ else
+ throw new UnlistenableEventException("Can't listen to a view");
+ }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public override event ItemsRemovedHandler<T> ItemsRemoved
+ {
+ add
+ {
+ if (underlying == null)
+ base.ItemsRemoved += value;
+ else
+ throw new UnlistenableEventException("Can't listen to a view");
+ }
+ remove
+ {
+ if (underlying == null)
+ base.ItemsRemoved -= value;
+ else
+ throw new UnlistenableEventException("Can't listen to a view");
+ }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public override event ItemRemovedAtHandler<T> ItemRemovedAt
+ {
+ add
+ {
+ if (underlying == null)
+ base.ItemRemovedAt += value;
+ else
+ throw new UnlistenableEventException("Can't listen to a view");
+ }
+ remove
+ {
+ if (underlying == null)
+ base.ItemRemovedAt -= value;
+ else
+ throw new UnlistenableEventException("Can't listen to a view");
+ }
+ }
+
+ */
+
+ #endregion
+ #region Util
+
+ bool equals(T i1, T i2) { return itemequalityComparer.Equals(i1, i2); }
+
+ /// <summary>
+ /// Increment or decrement the private size fields
+ /// </summary>
+ /// <param name="delta">Increment (with sign)</param>
+ void addtosize(int delta)
+ {
+ size += delta;
+ if (underlying != null)
+ underlying.size += delta;
+ }
+
+ #region Array handling
+ /// <summary>
+ /// Double the size of the internal array.
+ /// </summary>
+ protected override void expand()
+ { expand(2 * array.Length, underlyingsize); }
+
+
+ /// <summary>
+ /// Expand the internal array, resetting the index of the first unused element.
+ /// </summary>
+ /// <param name="newcapacity">The new capacity (will be rouded upwards to a power of 2).</param>
+ /// <param name="newsize">The new count of </param>
+ protected override void expand(int newcapacity, int newsize)
+ {
+ base.expand(newcapacity, newsize);
+ if (underlying != null)
+ underlying.array = array;
+ }
+
+ #endregion
+
+ #region Checks
+ /// <summary>
+ /// Check if it is valid to perform updates and increment stamp if so.
+ /// </summary>
+ /// <exception cref="ViewDisposedException"> If check fails by this list being a disposed view.</exception>
+ /// <exception cref="ReadOnlyCollectionException"> If check fails by this being a read only list.</exception>
+ protected override void updatecheck()
+ {
+ validitycheck();
+ base.updatecheck();
+ if (underlying != null)
+ underlying.stamp++;
+ }
+
+
+ /// <summary>
+ /// Check if we are a view that the underlying list has only been updated through us.
+ /// <para>This method should be called from enumerators etc to guard against
+ /// modification of the base collection.</para>
+ /// </summary>
+ /// <exception cref="ViewDisposedException"> if check fails.</exception>
+ void validitycheck()
+ {
+ if (!isValid)
+ throw new ViewDisposedException();
+ }
+
+
+ /// <summary>
+ /// Check that the list has not been updated since a particular time.
+ /// <para>To be used by enumerators and range </para>
+ /// </summary>
+ /// <exception cref="ViewDisposedException"> If check fails by this list being a disposed view.</exception>
+ /// <exception cref="CollectionModifiedException">If the list *has* beeen updated since that time..</exception>
+ /// <param name="stamp">The stamp indicating the time.</param>
+ protected override void modifycheck(int stamp)
+ {
+ validitycheck();
+ if (this.stamp != stamp)
+ throw new CollectionModifiedException();
+ }
+
+ #endregion
+
+ #region Searching
+
+ /// <summary>
+ /// Internal version of IndexOf without modification checks.
+ /// </summary>
+ /// <param name="item">Item to look for</param>
+ /// <returns>The index of first occurrence</returns>
+ int indexOf(T item)
+ {
+#if HASHINDEX
+ KeyValuePair<T, int> p = new KeyValuePair<T, int>(item);
+ if (itemIndex.Find(ref p) && p.Value >= offset && p.Value < offset + size)
+ return p.Value - offset;
+#else
+ for (int i = 0; i < size; i++)
+ if (equals(item, array[offset + i]))
+ return i;
+#endif
+ return ~size;
+ }
+
+ /// <summary>
+ /// Internal version of LastIndexOf without modification checks.
+ /// </summary>
+ /// <param name="item">Item to look for</param>
+ /// <returns>The index of last occurrence</returns>
+ int lastIndexOf(T item)
+ {
+#if HASHINDEX
+ return indexOf(item);
+#else
+ for (int i = size - 1; i >= 0; i--)
+ if (equals(item, array[offset + i]))
+ return i;
+ return ~size;
+#endif
+ }
+ #endregion
+
+ #region Inserting
+
+#if HASHINDEX
+ /// <summary>
+ /// Internal version of Insert with no modification checks.
+ /// </summary>
+ /// <exception cref="DuplicateNotAllowedException"> if item already in list.</exception>
+ /// <param name="i">Index to insert at</param>
+ /// <param name="item">Item to insert</param>
+#else
+ /// <summary>
+ /// Internal version of Insert with no modification checks.
+ /// </summary>
+ /// <param name="i">Index to insert at</param>
+ /// <param name="item">Item to insert</param>
+#endif
+ protected override void insert(int i, T item)
+ {
+#if HASHINDEX
+ KeyValuePair<T, int> p = new KeyValuePair<T, int>(item, offset + i);
+ if (itemIndex.FindOrAdd(ref p))
+ throw new DuplicateNotAllowedException("Item already in indexed list: " + item);
+#endif
+ baseinsert(i, item);
+#if HASHINDEX
+ reindex(i + offset + 1);
+#endif
+ }
+
+ private void baseinsert(int i, T item)
+ {
+ if (underlyingsize == array.Length)
+ expand();
+ i += offset;
+ if (i < underlyingsize)
+ Array.Copy(array, i, array, i + 1, underlyingsize - i);
+ array[i] = item;
+ addtosize(1);
+ fixViewsAfterInsert(1, i);
+ }
+ #endregion
+
+ #region Removing
+
+ /// <summary>
+ /// Internal version of RemoveAt with no modification checks.
+ /// </summary>
+ /// <param name="i">Index to remove at</param>
+ /// <returns>The removed item</returns>
+ T removeAt(int i)
+ {
+ i += offset;
+ fixViewsBeforeSingleRemove(i);
+ T retval = array[i];
+ addtosize(-1);
+ if (underlyingsize > i)
+ Array.Copy(array, i + 1, array, i, underlyingsize - i);
+ array[underlyingsize] = default(T);
+#if HASHINDEX
+ itemIndex.Remove(new KeyValuePair<T, int>(retval));
+ reindex(i);
+#endif
+ return retval;
+ }
+ #endregion
+
+ #region Indexing
+
+#if HASHINDEX
+ private void reindex(int start) { reindex(start, underlyingsize); }
+
+ private void reindex(int start, int end)
+ {
+ for (int j = start; j < end; j++)
+ itemIndex.UpdateOrAdd(new KeyValuePair<T, int>(array[j], j));
+ }
+#endif
+ #endregion
+
+ #region fixView utilities
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="added">The actual number of inserted nodes</param>
+ /// <param name="realInsertionIndex"></param>
+ void fixViewsAfterInsert(int added, int realInsertionIndex)
+ {
+ if (views != null)
+ foreach (ArrayList<T> view in views)
+ {
+ if (view != this)
+ {
+ if (view.offset < realInsertionIndex && view.offset + view.size > realInsertionIndex)
+ view.size += added;
+ if (view.offset > realInsertionIndex || (view.offset == realInsertionIndex && view.size > 0))
+ view.offset += added;
+ }
+ }
+ }
+
+ void fixViewsBeforeSingleRemove(int realRemovalIndex)
+ {
+ if (views != null)
+ foreach (ArrayList<T> view in views)
+ {
+ if (view != this)
+ {
+ if (view.offset <= realRemovalIndex && view.offset + view.size > realRemovalIndex)
+ view.size--;
+ if (view.offset > realRemovalIndex)
+ view.offset--;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Fix offsets and sizes of other views before removing an interval from this
+ /// </summary>
+ /// <param name="start">the start of the interval relative to the array/underlying</param>
+ /// <param name="count"></param>
+ void fixViewsBeforeRemove(int start, int count)
+ {
+ int clearend = start + count - 1;
+ if (views != null)
+ foreach (ArrayList<T> view in views)
+ {
+ if (view == this)
+ continue;
+ int viewoffset = view.offset, viewend = viewoffset + view.size - 1;
+ if (start < viewoffset)
+ {
+ if (clearend < viewoffset)
+ view.offset = viewoffset - count;
+ else
+ {
+ view.offset = start;
+ view.size = clearend < viewend ? viewend - clearend : 0;
+ }
+ }
+ else if (start <= viewend)
+ view.size = clearend <= viewend ? view.size - count : start - viewoffset;
+ }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="otherOffset"></param>
+ /// <param name="otherSize"></param>
+ /// <returns>The position of View(otherOffset, otherSize) wrt. this view</returns>
+ MutualViewPosition viewPosition(int otherOffset, int otherSize)
+ {
+ int end = offset + size, otherEnd = otherOffset + otherSize;
+ if (otherOffset >= end || otherEnd <= offset)
+ return MutualViewPosition.NonOverlapping;
+ if (size == 0 || (otherOffset <= offset && end <= otherEnd))
+ return MutualViewPosition.Contains;
+ if (otherSize == 0 || (offset <= otherOffset && otherEnd <= end))
+ return MutualViewPosition.ContainedIn;
+ return MutualViewPosition.Overlapping;
+ }
+
+ //TODO: make version that fits the new, more forgiving rules for disposing
+ void disposeOverlappingViews(bool reverse)
+ {
+ if (views != null)
+ foreach (ArrayList<T> view in views)
+ {
+ if (view != this)
+ {
+ switch (viewPosition(view.offset, view.size))
+ {
+ case MutualViewPosition.ContainedIn:
+ if (reverse)
+ view.offset = 2 * offset + size - view.size - view.offset;
+ else
+ view.Dispose();
+ break;
+ case MutualViewPosition.Overlapping:
+ view.Dispose();
+ break;
+ case MutualViewPosition.Contains:
+ case MutualViewPosition.NonOverlapping:
+ break;
+ }
+ }
+ }
+ }
+ #endregion
+
+ #endregion
+
+ #region Position, PositionComparer and ViewHandler nested types
+ class PositionComparer : SCG.IComparer<Position>
+ {
+ public int Compare(Position a, Position b)
+ {
+ return a.index.CompareTo(b.index);
+ }
+ }
+ /// <summary>
+ /// During RemoveAll, we need to cache the original endpoint indices of views (??? also for ArrayList?)
+ /// </summary>
+ struct Position
+ {
+ public readonly ArrayList<T> view;
+ public readonly int index;
+ public Position(ArrayList<T> view, bool left)
+ {
+ this.view = view;
+ index = left ? view.offset : view.offset + view.size - 1;
+ }
+ public Position(int index) { this.index = index; view = null; }
+ }
+
+ /// <summary>
+ /// Handle the update of (other) views during a multi-remove operation.
+ /// </summary>
+ struct ViewHandler
+ {
+ ArrayList<Position> leftEnds;
+ ArrayList<Position> rightEnds;
+ int leftEndIndex, rightEndIndex;
+ internal readonly int viewCount;
+ internal ViewHandler(ArrayList<T> list)
+ {
+ leftEndIndex = rightEndIndex = viewCount = 0;
+ leftEnds = rightEnds = null;
+ if (list.views != null)
+ foreach (ArrayList<T> v in list.views)
+ if (v != list)
+ {
+ if (leftEnds == null)
+ {
+ leftEnds = new ArrayList<Position>();
+ rightEnds = new ArrayList<Position>();
+ }
+ leftEnds.Add(new Position(v, true));
+ rightEnds.Add(new Position(v, false));
+ }
+ if (leftEnds == null)
+ return;
+ viewCount = leftEnds.Count;
+ leftEnds.Sort(new PositionComparer());
+ rightEnds.Sort(new PositionComparer());
+ }
+ /// <summary>
+ /// This is to be called with realindex pointing to the first node to be removed after a (stretch of) node that was not removed
+ /// </summary>
+ /// <param name="removed"></param>
+ /// <param name="realindex"></param>
+ internal void skipEndpoints(int removed, int realindex)
+ {
+ if (viewCount > 0)
+ {
+ Position endpoint;
+ while (leftEndIndex < viewCount && (endpoint = leftEnds[leftEndIndex]).index <= realindex)
+ {
+ ArrayList<T> view = endpoint.view;
+ view.offset = view.offset - removed;
+ view.size += removed;
+ leftEndIndex++;
+ }
+ while (rightEndIndex < viewCount && (endpoint = rightEnds[rightEndIndex]).index < realindex)
+ {
+ endpoint.view.size -= removed;
+ rightEndIndex++;
+ }
+ }
+ }
+ internal void updateViewSizesAndCounts(int removed, int realindex)
+ {
+ if (viewCount > 0)
+ {
+ Position endpoint;
+ while (leftEndIndex < viewCount && (endpoint = leftEnds[leftEndIndex]).index <= realindex)
+ {
+ ArrayList<T> view = endpoint.view;
+ view.offset = view.Offset - removed;
+ view.size += removed;
+ leftEndIndex++;
+ }
+ while (rightEndIndex < viewCount && (endpoint = rightEnds[rightEndIndex]).index < realindex)
+ {
+ endpoint.view.size -= removed;
+ rightEndIndex++;
+ }
+ }
+ }
+ }
+ #endregion
+
+ #region Constructors
+ /// <summary>
+ /// Create an array list with default item equalityComparer and initial capacity 8 items.
+ /// </summary>
+ public ArrayList() : this(8) { }
+
+
+ /// <summary>
+ /// Create an array list with external item equalityComparer and initial capacity 8 items.
+ /// </summary>
+ /// <param name="itemequalityComparer">The external item equalityComparer</param>
+ public ArrayList(SCG.IEqualityComparer<T> itemequalityComparer) : this(8,itemequalityComparer) { }
+
+
+ /// <summary>
+ /// Create an array list with default item equalityComparer and prescribed initial capacity.
+ /// </summary>
+ /// <param name="capacity">The prescribed capacity</param>
+ public ArrayList(int capacity) : this(capacity,EqualityComparer<T>.Default) { }
+
+
+ /// <summary>
+ /// Create an array list with external item equalityComparer and prescribed initial capacity.
+ /// </summary>
+ /// <param name="capacity">The prescribed capacity</param>
+ /// <param name="itemequalityComparer">The external item equalityComparer</param>
+ public ArrayList(int capacity, SCG.IEqualityComparer<T> itemequalityComparer) : base(capacity,itemequalityComparer)
+ {
+#if HASHINDEX
+ itemIndex = new HashSet<KeyValuePair<T, int>>(new KeyValuePairEqualityComparer<T, int>(itemequalityComparer));
+#endif
+ }
+
+ #endregion
+
+ #region IList<T> Members
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if this list is empty.</exception>
+ /// <value>The first item in this list.</value>
+ [Tested]
+ public virtual T First
+ {
+ [Tested]
+ get
+ {
+ validitycheck();
+ if (size == 0)
+ throw new NoSuchItemException();
+
+ return array[offset];
+ }
+ }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if this list is empty.</exception>
+ /// <value>The last item in this list.</value>
+ [Tested]
+ public virtual T Last
+ {
+ [Tested]
+ get
+ {
+ validitycheck();
+ if (size == 0)
+ throw new NoSuchItemException();
+
+ return array[offset + size - 1];
+ }
+ }
+
+
+ /// <summary>
+ /// Since <code>Add(T item)</code> always add at the end of the list,
+ /// this describes if list has FIFO or LIFO semantics.
+ /// </summary>
+ /// <value>True if the <code>Remove()</code> operation removes from the
+ /// start of the list, false if it removes from the end. The default for a new array list is false.</value>
+ [Tested]
+ public virtual bool FIFO
+ {
+ [Tested]
+ get { validitycheck(); return fIFO; }
+ [Tested]
+ set { updatecheck(); fIFO = value; }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ public virtual bool IsFixedSize
+ {
+ get { validitycheck(); return false; }
+ }
+
+
+#if HASHINDEX
+ /// <summary>
+ /// On this list, this indexer is read/write.
+ /// </summary>
+ /// <exception cref="IndexOutOfRangeException"> if index is negative or
+ /// &gt;= the size of the collection.</exception>
+ /// <exception cref="DuplicateNotAllowedException"> By the get operation
+ /// if the item already is present somewhere else in the list.</exception>
+ /// <value>The index'th item of this list.</value>
+ /// <param name="index">The index of the item to fetch or store.</param>
+#else
+ /// <summary>
+ /// On this list, this indexer is read/write.
+ /// </summary>
+ /// <exception cref="IndexOutOfRangeException"> if index is negative or
+ /// &gt;= the size of the collection.</exception>
+ /// <value>The index'th item of this list.</value>
+ /// <param name="index">The index of the item to fetch or store.</param>
+#endif
+ [Tested]
+ public virtual T this[int index]
+ {
+ [Tested]
+ get
+ {
+ validitycheck();
+ if (index < 0 || index >= size)
+ throw new IndexOutOfRangeException();
+
+ return array[offset + index];
+ }
+ [Tested]
+ set
+ {
+ updatecheck();
+ if (index < 0 || index >= size)
+ throw new IndexOutOfRangeException();
+ index += offset;
+ T item = array[index];
+#if HASHINDEX
+ KeyValuePair<T, int> p = new KeyValuePair<T, int>(value, index);
+ if (itemequalityComparer.Equals(value, item))
+ {
+ array[index] = value;
+ itemIndex.Update(p);
+ }
+ else if (!itemIndex.FindOrAdd(ref p))
+ {
+ itemIndex.Remove(new KeyValuePair<T, int>(item));
+ array[index] = value;
+ }
+ else
+ throw new DuplicateNotAllowedException("Item already in indexed list");
+#else
+ array[index] = value;
+#endif
+ (underlying ?? this).raiseForSetThis(index, value, item);
+ }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public virtual Speed IndexingSpeed { get { return Speed.Constant; } }
+
+#if HASHINDEX
+ /// <summary>
+ /// Insert an item at a specific index location in this list.
+ ///</summary>
+ /// <exception cref="IndexOutOfRangeException"> if index is negative or
+ /// &gt; the size of the collection. </exception>
+ /// <exception cref="DuplicateNotAllowedException">
+ /// If the item is already present in the list.</exception>
+ /// <param name="index">The index at which to insert.</param>
+ /// <param name="item">The item to insert.</param>
+#else
+ /// <summary>
+ /// Insert an item at a specific index location in this list.
+ ///</summary>
+ /// <exception cref="IndexOutOfRangeException"> if i is negative or
+ /// &gt; the size of the collection. </exception>
+ /// <param name="index">The index at which to insert.</param>
+ /// <param name="item">The item to insert.</param>
+#endif
+ [Tested]
+ public virtual void Insert(int index, T item)
+ {
+ updatecheck();
+ if (index < 0 || index > size)
+ throw new IndexOutOfRangeException();
+
+ insert(index, item);
+ (underlying ?? this).raiseForInsert(index + offset, item);
+ }
+
+ /// <summary>
+ /// Insert an item at the end of a compatible view, used as a pointer.
+ /// <para>The <code>pointer</code> must be a view on the same list as
+ /// <code>this</code> and the endpoitn of <code>pointer</code> must be
+ /// a valid insertion point of <code>this</code></para>
+ /// </summary>
+ /// <exception cref="IncompatibleViewException">If <code>pointer</code>
+ /// is not a view on or the same list as <code>this</code></exception>
+ /// <exception cref="IndexOutOfRangeException"><b>??????</b> if the endpoint of
+ /// <code>pointer</code> is not inside <code>this</code></exception>
+ /// <exception cref="DuplicateNotAllowedException"> if the list has
+ /// <code>AllowsDuplicates==false</code> and the item is
+ /// already in the list.</exception>
+ /// <param name="pointer"></param>
+ /// <param name="item"></param>
+ public void Insert(IList<T> pointer, T item)
+ {
+ if ((pointer == null) || ((pointer.Underlying ?? pointer) != (underlying ?? this)))
+ throw new IncompatibleViewException();
+ Insert(pointer.Offset + pointer.Count - Offset, item);
+ }
+
+#if HASHINDEX
+ /// <summary>
+ /// Insert into this list all items from an enumerable collection starting
+ /// at a particular index.
+ /// </summary>
+ /// <exception cref="IndexOutOfRangeException"> if index is negative or
+ /// &gt; the size of the collection.</exception>
+ /// <exception cref="DuplicateNotAllowedException"> If <code>items</code>
+ /// contains duplicates or some item already present in the list.</exception>
+ /// <param name="index">Index to start inserting at</param>
+ /// <param name="items">Items to insert</param>
+#else
+ /// <summary>
+ /// Insert into this list all items from an enumerable collection starting
+ /// at a particular index.
+ /// </summary>
+ /// <exception cref="IndexOutOfRangeException"> if index is negative or
+ /// &gt; the size of the collection.</exception>
+ /// <param name="index">Index to start inserting at</param>
+ /// <param name="items">Items to insert</param>
+ /// <typeparam name="U"></typeparam>
+#endif
+ [Tested]
+ public virtual void InsertAll<U>(int index, SCG.IEnumerable<U> items) where U : T
+ {
+ updatecheck();
+ if (index < 0 || index > size)
+ throw new IndexOutOfRangeException();
+ index += offset;
+ int toadd = EnumerableBase<U>.countItems(items);
+ if (toadd == 0)
+ return;
+ if (toadd + underlyingsize > array.Length)
+ expand(toadd + underlyingsize, underlyingsize);
+ if (underlyingsize > index)
+ Array.Copy(array, index, array, index + toadd, underlyingsize - index);
+ int i = index;
+ try
+ {
+
+ foreach (T item in items)
+ {
+#if HASHINDEX
+ KeyValuePair<T, int> p = new KeyValuePair<T, int>(item, i);
+ if (itemIndex.FindOrAdd(ref p))
+ throw new DuplicateNotAllowedException("Item already in indexed list");
+#endif
+ array[i++] = item;
+ }
+ }
+ finally
+ {
+ int added = i - index;
+ if (added < toadd)
+ {
+ Array.Copy(array, index + toadd, array, i, underlyingsize - index);
+ Array.Clear(array, underlyingsize + added, toadd - added);
+ }
+ if (added > 0)
+ {
+ addtosize(added);
+#if HASHINDEX
+ reindex(i);
+#endif
+ fixViewsAfterInsert(added, index);
+ (underlying ?? this).raiseForInsertAll(index, added);
+ }
+ }
+ }
+ private void raiseForInsertAll(int index, int added)
+ {
+ if (ActiveEvents != 0)
+ {
+ if ((ActiveEvents & (EventTypeEnum.Added | EventTypeEnum.Inserted)) != 0)
+ for (int j = index; j < index + added; j++)
+ {
+ raiseItemInserted(array[j], j);
+ raiseItemsAdded(array[j], 1);
+ }
+ raiseCollectionChanged();
+ }
+ }
+
+#if HASHINDEX
+ /// <summary>
+ /// Insert an item at the front of this list;
+ /// </summary>
+ /// <exception cref="DuplicateNotAllowedException">If the item is already in the list</exception>
+ /// <param name="item">The item to insert.</param>
+#else
+ /// <summary>
+ /// Insert an item at the front of this list;
+ /// </summary>
+ /// <param name="item">The item to insert.</param>
+#endif
+ [Tested]
+ public virtual void InsertFirst(T item)
+ {
+ updatecheck();
+ insert(0, item);
+ (underlying ?? this).raiseForInsert(offset, item);
+ }
+
+
+#if HASHINDEX
+ /// <summary>
+ /// Insert an item at the back of this list.
+ /// </summary>
+ /// <exception cref="DuplicateNotAllowedException">If the item is already in the list</exception>
+ /// <param name="item">The item to insert.</param>
+#else
+ /// <summary>
+ /// Insert an item at the back of this list.
+ /// </summary>
+ /// <param name="item">The item to insert.</param>
+#endif
+ [Tested]
+ public virtual void InsertLast(T item)
+ {
+ updatecheck();
+ insert(size, item);
+ (underlying ?? this).raiseForInsert(size - 1 + offset, item);
+ }
+
+
+ //NOTE: if the filter throws an exception, no result will be returned.
+ /// <summary>
+ /// Create a new list consisting of the items of this list satisfying a
+ /// certain predicate.
+ /// <para>The new list will be of type ArrayList</para>
+ /// </summary>
+ /// <param name="filter">The filter delegate defining the predicate.</param>
+ /// <returns>The new list.</returns>
+ [Tested]
+ public virtual IList<T> FindAll(Fun<T, bool> filter)
+ {
+ validitycheck();
+ int stamp = this.stamp;
+ ArrayList<T> res = new ArrayList<T>(itemequalityComparer);
+ int j = 0, rescap = res.array.Length;
+ for (int i = 0; i < size; i++)
+ {
+ T a = array[offset + i];
+ bool found = filter(a);
+ modifycheck(stamp);
+ if (found)
+ {
+ if (j == rescap) res.expand(rescap = 2 * rescap, j);
+ res.array[j++] = a;
+ }
+ }
+ res.size = j;
+#if HASHINDEX
+ res.reindex(0);
+#endif
+ return res;
+ }
+
+
+#if HASHINDEX
+ /// <summary>
+ /// Create a new list consisting of the results of mapping all items of this
+ /// list. The new list will use the default item equalityComparer for the item type V.
+ /// <para>The new list will be of type ArrayList</para>
+ /// </summary>
+ /// <exception cref="DuplicateNotAllowedException">If <code>mapper</code>
+ /// creates duplicates</exception>
+ /// <typeparam name="V">The type of items of the new list</typeparam>
+ /// <param name="mapper">The delegate defining the map.</param>
+ /// <returns>The new list.</returns>
+#else
+ /// <summary>
+ /// Create a new list consisting of the results of mapping all items of this
+ /// list. The new list will use the default item equalityComparer for the item type V.
+ /// <para>The new list will be of type ArrayList</para>
+ /// </summary>
+ /// <typeparam name="V">The type of items of the new list</typeparam>
+ /// <param name="mapper">The delegate defining the map.</param>
+ /// <returns>The new list.</returns>
+#endif
+ [Tested]
+ public virtual IList<V> Map<V>(Fun<T, V> mapper)
+ {
+ validitycheck();
+
+ ArrayList<V> res = new ArrayList<V>(size);
+
+ return map<V>(mapper, res);
+ }
+
+#if HASHINDEX
+ /// <summary>
+ /// Create a new list consisting of the results of mapping all items of this
+ /// list. The new list will use a specified item equalityComparer for the item type.
+ /// <para>The new list will be of type ArrayList</para>
+ /// </summary>
+ /// <exception cref="DuplicateNotAllowedException">If <code>mapper</code>
+ /// creates duplicates</exception>
+ /// <typeparam name="V">The type of items of the new list</typeparam>
+ /// <param name="mapper">The delegate defining the map.</param>
+ /// <param name="itemequalityComparer">The item equalityComparer to use for the new list</param>
+ /// <returns>The new list.</returns>
+#else
+ /// <summary>
+ /// Create a new list consisting of the results of mapping all items of this
+ /// list. The new list will use a specified item equalityComparer for the item type.
+ /// <para>The new list will be of type ArrayList</para>
+ /// </summary>
+ /// <typeparam name="V">The type of items of the new list</typeparam>
+ /// <param name="mapper">The delegate defining the map.</param>
+ /// <param name="itemequalityComparer">The item equalityComparer to use for the new list</param>
+ /// <returns>The new list.</returns>
+#endif
+ public virtual IList<V> Map<V>(Fun<T, V> mapper, SCG.IEqualityComparer<V> itemequalityComparer)
+ {
+ validitycheck();
+
+ ArrayList<V> res = new ArrayList<V>(size, itemequalityComparer);
+
+ return map<V>(mapper, res);
+ }
+
+ private IList<V> map<V>(Fun<T, V> mapper, ArrayList<V> res)
+ {
+ int stamp = this.stamp;
+ if (size > 0)
+ for (int i = 0; i < size; i++)
+ {
+ V mappeditem = mapper(array[offset + i]);
+ modifycheck(stamp);
+#if HASHINDEX
+ KeyValuePair<V, int> p = new KeyValuePair<V, int>(mappeditem, i);
+ if (res.itemIndex.FindOrAdd(ref p))
+ throw new ArgumentException("Mapped item already in indexed list");
+#endif
+ res.array[i] = mappeditem;
+ }
+ res.size = size;
+ return res;
+ }
+
+ /// <summary>
+ /// Remove one item from the list: from the front if <code>FIFO</code>
+ /// is true, else from the back.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if this list is empty.</exception>
+ /// <returns>The removed item.</returns>
+ [Tested]
+ public virtual T Remove()
+ {
+ updatecheck();
+ if (size == 0)
+ throw new NoSuchItemException("List is empty");
+
+ T item = removeAt(fIFO ? 0 : size - 1);
+ (underlying ?? this).raiseForRemove(item);
+ return item;
+ }
+
+ /// <summary>
+ /// Remove one item from the fromnt of the list.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if this list is empty.</exception>
+ /// <returns>The removed item.</returns>
+ [Tested]
+ public virtual T RemoveFirst()
+ {
+ updatecheck();
+ if (size == 0)
+ throw new NoSuchItemException("List is empty");
+
+ T item = removeAt(0);
+ (underlying ?? this).raiseForRemoveAt(offset, item);
+ return item;
+ }
+
+
+ /// <summary>
+ /// Remove one item from the back of the list.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if this list is empty.</exception>
+ /// <returns>The removed item.</returns>
+ [Tested]
+ public virtual T RemoveLast()
+ {
+ updatecheck();
+ if (size == 0)
+ throw new NoSuchItemException("List is empty");
+
+ T item = removeAt(size - 1);
+ (underlying ?? this).raiseForRemoveAt(size + offset, item);
+ return item;
+ }
+
+ /// <summary>
+ /// Create a list view on this list.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException"> if the start or count is negative
+ /// or the range does not fit within list.</exception>
+ /// <param name="start">The index in this list of the start of the view.</param>
+ /// <param name="count">The size of the view.</param>
+ /// <returns>The new list view.</returns>
+ [Tested]
+ public virtual IList<T> View(int start, int count)
+ {
+ validitycheck();
+ checkRange(start, count);
+ if (views == null)
+ views = new WeakViewList<ArrayList<T>>();
+ ArrayList<T> retval = (ArrayList<T>)MemberwiseClone();
+
+
+ retval.underlying = underlying != null ? underlying : this;
+ retval.offset = start + offset;
+ retval.size = count;
+ retval.myWeakReference = views.Add(retval);
+ return retval;
+ }
+
+ /// <summary>
+ /// Create a list view on this list containing the (first) occurrence of a particular item.
+ /// <para>Returns <code>null</code> if the item is not in this list.</para>
+ /// </summary>
+ /// <param name="item">The item to find.</param>
+ /// <returns>The new list view.</returns>
+ [Tested]
+ public virtual IList<T> ViewOf(T item)
+ {
+ int index = indexOf(item);
+ if (index < 0)
+ return null;
+ return View(index, 1);
+ }
+
+
+ /// <summary>
+ /// Create a list view on this list containing the last occurrence of a particular item.
+ /// <para>Returns <code>null</code> if the item is not in this list.</para>
+ /// </summary>
+ /// <param name="item">The item to find.</param>
+ /// <returns>The new list view.</returns>
+ [Tested]
+ public virtual IList<T> LastViewOf(T item)
+ {
+ int index = lastIndexOf(item);
+ if (index < 0)
+ return null;
+ return View(index, 1);
+ }
+
+ /// <summary>
+ /// Null if this list is not a view.
+ /// </summary>
+ /// <value>Underlying list for view.</value>
+ [Tested]
+ public virtual IList<T> Underlying { [Tested]get { return underlying; } }
+
+
+ /// <summary>
+ /// </summary>
+ /// <value>Offset for this list view or 0 for an underlying list.</value>
+ [Tested]
+ public virtual int Offset { [Tested]get { return offset; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public virtual bool IsValid { get { return isValid; } }
+
+ /// <summary>
+ /// Slide this list view along the underlying list.
+ /// </summary>
+ /// <exception cref="NotAViewException"> if this list is not a view.</exception>
+ /// <exception cref="ArgumentOutOfRangeException"> if the operation
+ /// would bring either end of the view outside the underlying list.</exception>
+ /// <param name="offset">The signed amount to slide: positive to slide
+ /// towards the end.</param>
+ [Tested]
+ public virtual IList<T> Slide(int offset)
+ {
+ if (!TrySlide(offset, size))
+ throw new ArgumentOutOfRangeException();
+ return this;
+ }
+
+
+ /// <summary>
+ /// Slide this list view along the underlying list, changing its size.
+ /// </summary>
+ /// <exception cref="NotAViewException"> if this list is not a view.</exception>
+ /// <exception cref="ArgumentOutOfRangeException"> if the operation
+ /// would bring either end of the view outside the underlying list.</exception>
+ /// <param name="offset">The signed amount to slide: positive to slide
+ /// towards the end.</param>
+ /// <param name="size">The new size of the view.</param>
+ [Tested]
+ public virtual IList<T> Slide(int offset, int size)
+ {
+ if (!TrySlide(offset, size))
+ throw new ArgumentOutOfRangeException();
+ return this;
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <exception cref="NotAViewException"> if this list is not a view.</exception>
+ /// <param name="offset"></param>
+ /// <returns></returns>
+ [Tested]
+ public virtual bool TrySlide(int offset)
+ {
+ return TrySlide(offset, size);
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <exception cref="NotAViewException"> if this list is not a view.</exception>
+ /// <param name="offset"></param>
+ /// <param name="size"></param>
+ /// <returns></returns>
+ [Tested]
+ public virtual bool TrySlide(int offset, int size)
+ {
+ updatecheck();
+ if (underlying == null)
+ throw new NotAViewException("Not a view");
+
+ int newoffset = this.offset + offset;
+ int newsize = size;
+
+ if (newoffset < 0 || newsize < 0 || newoffset + newsize > underlyingsize)
+ return false;
+
+ this.offset = newoffset;
+ this.size = newsize;
+ return true;
+ }
+
+ /// <summary>
+ ///
+ /// <para>Returns null if <code>otherView</code> is strictly to the left of this view</para>
+ /// </summary>
+ /// <param name="otherView"></param>
+ /// <exception cref="IncompatibleViewException">If otherView does not have the same underlying list as this</exception>
+ /// <returns></returns>
+ public virtual IList<T> Span(IList<T> otherView)
+ {
+ if ((otherView == null) || ((otherView.Underlying ?? otherView) != (underlying ?? this)))
+ throw new IncompatibleViewException();
+ if (otherView.Offset + otherView.Count - Offset < 0)
+ return null;
+ return (underlying ?? this).View(Offset, otherView.Offset + otherView.Count - Offset);
+ }
+
+ /// <summary>
+ /// Reverst the list so the items are in the opposite sequence order.
+ /// </summary>
+ [Tested]
+ public virtual void Reverse()
+ {
+ updatecheck();
+ if (size == 0)
+ return;
+ for (int i = 0, length = size / 2, end = offset + size - 1; i < length; i++)
+ {
+ T swap = array[offset + i];
+
+ array[offset + i] = array[end - i];
+ array[end - i] = swap;
+ }
+#if HASHINDEX
+ reindex(offset, offset + size);
+#endif
+ //TODO: be more forgiving wrt. disposing
+ disposeOverlappingViews(true);
+ (underlying ?? this).raiseCollectionChanged();
+ }
+
+ /// <summary>
+ /// Check if this list is sorted according to the default sorting order
+ /// for the item type T, as defined by the <see cref="T:C5.Comparer`1"/> class
+ /// </summary>
+ /// <exception cref="NotComparableException">if T is not comparable</exception>
+ /// <returns>True if the list is sorted, else false.</returns>
+ [Tested]
+ public bool IsSorted() { return IsSorted(Comparer<T>.Default); }
+
+ /// <summary>
+ /// Check if this list is sorted according to a specific sorting order.
+ /// </summary>
+ /// <param name="c">The comparer defining the sorting order.</param>
+ /// <returns>True if the list is sorted, else false.</returns>
+ [Tested]
+ public virtual bool IsSorted(SCG.IComparer<T> c)
+ {
+ validitycheck();
+ for (int i = offset + 1, end = offset + size; i < end; i++)
+ if (c.Compare(array[i - 1], array[i]) > 0)
+ return false;
+
+ return true;
+ }
+
+ /// <summary>
+ /// Sort the items of the list according to the default sorting order
+ /// for the item type T, as defined by the Comparer[T] class
+ /// (<see cref="T:C5.Comparer`1"/>).
+ /// </summary>
+ /// <exception cref="InvalidOperationException">if T is not comparable</exception>
+ public virtual void Sort()
+ {
+ Sort(Comparer<T>.Default);
+ }
+
+
+ /// <summary>
+ /// Sort the items of the list according to a specific sorting order.
+ /// </summary>
+ /// <param name="comparer">The comparer defining the sorting order.</param>
+ [Tested]
+ public virtual void Sort(SCG.IComparer<T> comparer)
+ {
+ updatecheck();
+ if (size == 0)
+ return;
+ Sorting.IntroSort<T>(array, offset, size, comparer);
+ disposeOverlappingViews(false);
+#if HASHINDEX
+ reindex(offset, offset + size);
+#endif
+ (underlying ?? this).raiseCollectionChanged();
+ }
+
+
+ /// <summary>
+ /// Randomly shuffle the items of this list.
+ /// </summary>
+ public virtual void Shuffle() { Shuffle(new C5Random()); }
+
+
+ /// <summary>
+ /// Shuffle the items of this list according to a specific random source.
+ /// </summary>
+ /// <param name="rnd">The random source.</param>
+ public virtual void Shuffle(Random rnd)
+ {
+ updatecheck();
+ if (size == 0)
+ return;
+ for (int i = offset, top = offset + size, end = top - 1; i < end; i++)
+ {
+ int j = rnd.Next(i, top);
+ if (j != i)
+ {
+ T tmp = array[i];
+ array[i] = array[j];
+ array[j] = tmp;
+ }
+ }
+ disposeOverlappingViews(false);
+#if HASHINDEX
+ reindex(offset, offset + size);
+#endif
+ (underlying ?? this).raiseCollectionChanged();
+ }
+ #endregion
+
+ #region IIndexed<T> Members
+
+ /// <summary>
+ /// Search for an item in the list going forwrds from the start.
+ /// </summary>
+ /// <param name="item">Item to search for.</param>
+ /// <returns>Index of item from start.</returns>
+ [Tested]
+ public virtual int IndexOf(T item) { validitycheck(); return indexOf(item); }
+
+
+ /// <summary>
+ /// Search for an item in the list going backwords from the end.
+ /// </summary>
+ /// <param name="item">Item to search for.</param>
+ /// <returns>Index of item from the end.</returns>
+ [Tested]
+ public virtual int LastIndexOf(T item) { validitycheck(); return lastIndexOf(item); }
+
+
+ /// <summary>
+ /// Remove the item at a specific position of the list.
+ /// </summary>
+ /// <exception cref="IndexOutOfRangeException"> if index is negative or
+ /// &gt;= the size of the collection.</exception>
+ /// <param name="index">The index of the item to remove.</param>
+ /// <returns>The removed item.</returns>
+ [Tested]
+ public virtual T RemoveAt(int index)
+ {
+ updatecheck();
+ if (index < 0 || index >= size)
+ throw new IndexOutOfRangeException("Index out of range for sequenced collection");
+
+ T item = removeAt(index);
+ (underlying ?? this).raiseForRemoveAt(offset + index, item);
+ return item;
+ }
+
+
+ /// <summary>
+ /// Remove all items in an index interval.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">If <code>start</code>
+ /// and <code>count</code> does not describe a valid interval in the list</exception>
+ /// <param name="start">The index of the first item to remove.</param>
+ /// <param name="count">The number of items to remove.</param>
+ [Tested]
+ public virtual void RemoveInterval(int start, int count)
+ {
+ updatecheck();
+ if (count == 0)
+ return;
+ checkRange(start, count);
+ start += offset;
+ fixViewsBeforeRemove(start, count);
+#if HASHINDEX
+ KeyValuePair<T, int> p = new KeyValuePair<T, int>();
+ for (int i = start, end = start + count; i < end; i++)
+ {
+ p.Key = array[i];
+ itemIndex.Remove(p);
+ }
+#endif
+ Array.Copy(array, start + count, array, start, underlyingsize - start - count);
+ addtosize(-count);
+ Array.Clear(array, underlyingsize, count);
+#if HASHINDEX
+ reindex(start);
+#endif
+ (underlying ?? this).raiseForRemoveInterval(start, count);
+ }
+ void raiseForRemoveInterval(int start, int count)
+ {
+ if (ActiveEvents != 0)
+ {
+ raiseCollectionCleared(size == 0, count, start);
+ raiseCollectionChanged();
+ }
+ }
+#endregion
+
+ #region ICollection<T> Members
+
+ /// <summary>
+ /// The value is symbolic indicating the type of asymptotic complexity
+ /// in terms of the size of this collection (worst-case or amortized as
+ /// relevant).
+ /// </summary>
+ /// <value>Speed.Linear</value>
+ [Tested]
+ public virtual Speed ContainsSpeed
+ {
+ [Tested]
+ get
+ {
+#if HASHINDEX
+ return Speed.Constant;
+#else
+ return Speed.Linear;
+#endif
+ }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ [Tested]
+ public override int GetUnsequencedHashCode()
+ { validitycheck(); return base.GetUnsequencedHashCode(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="that"></param>
+ /// <returns></returns>
+ [Tested]
+ public override bool UnsequencedEquals(ICollection<T> that)
+ { validitycheck(); return base.UnsequencedEquals(that); }
+
+ /// <summary>
+ /// Check if this collection contains (an item equivalent to according to the
+ /// itemequalityComparer) a particular value.
+ /// </summary>
+ /// <param name="item">The value to check for.</param>
+ /// <returns>True if the items is in this collection.</returns>
+ [Tested]
+ public virtual bool Contains(T item)
+ { validitycheck(); return indexOf(item) >= 0; }
+
+
+ /// <summary>
+ /// Check if this collection contains an item equivalent according to the
+ /// itemequalityComparer to a particular value. If so, return in the ref argument (a
+ /// binary copy of) the actual value found.
+ /// </summary>
+ /// <param name="item">The value to look for.</param>
+ /// <returns>True if the items is in this collection.</returns>
+ [Tested]
+ public virtual bool Find(ref T item)
+ {
+ validitycheck();
+
+ int i;
+
+ if ((i = indexOf(item)) >= 0)
+ {
+ item = array[offset + i];
+ return true;
+ }
+
+ return false;
+ }
+
+
+ /// <summary>
+ /// Check if this collection contains an item equivalent according to the
+ /// itemequalityComparer to a particular value. If so, update the item in the collection
+ /// to with a binary copy of the supplied value. This will only update the first
+ /// mathching item.
+ /// </summary>
+ /// <param name="item">Value to update.</param>
+ /// <returns>True if the item was found and hence updated.</returns>
+ [Tested]
+ public virtual bool Update(T item)
+ {
+ T olditem;
+ return Update(item, out olditem);
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ /// <param name="olditem"></param>
+ /// <returns></returns>
+ public virtual bool Update(T item, out T olditem)
+ {
+ updatecheck();
+ int i;
+
+ if ((i = indexOf(item)) >= 0)
+ {
+ olditem = array[offset + i];
+ array[offset + i] = item;
+#if HASHINDEX
+ itemIndex.Update(new KeyValuePair<T, int>(item, offset + i));
+#endif
+ (underlying ?? this).raiseForUpdate(item, olditem);
+ return true;
+ }
+
+ olditem = default(T);
+ return false;
+ }
+
+ /// <summary>
+ /// Check if this collection contains an item equivalent according to the
+ /// itemequalityComparer to a particular value. If so, return in the ref argument (a
+ /// binary copy of) the actual value found. Else, add the item to the collection.
+ /// </summary>
+ /// <param name="item">The value to look for.</param>
+ /// <returns>True if the item was found (hence not added).</returns>
+ [Tested]
+ public virtual bool FindOrAdd(ref T item)
+ {
+ updatecheck();
+ if (Find(ref item))
+ return true;
+
+ Add(item);
+ return false;
+ }
+
+
+ /// <summary>
+ /// Check if this collection contains an item equivalent according to the
+ /// itemequalityComparer to a particular value. If so, update the item in the collection
+ /// to with a binary copy of the supplied value. This will only update the first
+ /// mathching item.
+ /// </summary>
+ /// <param name="item">Value to update.</param>
+ /// <returns>True if the item was found and hence updated.</returns>
+ [Tested]
+ public virtual bool UpdateOrAdd(T item)
+ {
+ updatecheck();
+ if (Update(item))
+ return true;
+
+ Add(item);
+ return false;
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ /// <param name="olditem"></param>
+ /// <returns></returns>
+ public virtual bool UpdateOrAdd(T item, out T olditem)
+ {
+ updatecheck();
+ if (Update(item, out olditem))
+ return true;
+
+ Add(item);
+ olditem = default(T);
+ return false;
+ }
+
+ /// <summary>
+ /// Remove a particular item from this list. The item will be searched
+ /// for from the end of the list if <code>FIFO == false</code> (the default),
+ /// else from the start.
+ /// </summary>
+ /// <param name="item">The value to remove.</param>
+ /// <returns>True if the item was found (and removed).</returns>
+ [Tested]
+ public virtual bool Remove(T item)
+ {
+ updatecheck();
+
+ int i = fIFO ? indexOf(item) : lastIndexOf(item);
+
+ if (i < 0)
+ return false;
+
+ T removeditem = removeAt(i);
+ (underlying ?? this).raiseForRemove(removeditem);
+ return true;
+ }
+
+
+ /// <summary>
+ /// Remove the first copy of a particular item from this collection if found.
+ /// If an item was removed, report a binary copy of the actual item removed in
+ /// the argument. The item will be searched
+ /// for from the end of the list if <code>FIFO == false</code> (the default),
+ /// else from the start.
+ /// </summary>
+ /// <param name="item">The value to remove.</param>
+ /// <param name="removeditem">The removed value.</param>
+ /// <returns>True if the item was found (and removed).</returns>
+ [Tested]
+ public virtual bool Remove(T item, out T removeditem)
+ {
+ updatecheck();
+
+ int i = fIFO ? indexOf(item) : lastIndexOf(item);
+
+ if (i < 0)
+ {
+ removeditem = default(T);
+ return false;
+ }
+
+ removeditem = removeAt(i);
+ (underlying ?? this).raiseForRemove(removeditem);
+ return true;
+ }
+
+
+ //TODO: remove from end or according to FIFO?
+ /// <summary>
+ /// Remove all items in another collection from this one, taking multiplicities into account.
+ /// Matching items will be removed from the front. Current implementation is not optimal.
+ /// </summary>
+ /// <typeparam name="U"></typeparam>
+ /// <param name="items">The items to remove.</param>
+ [Tested]
+ public virtual void RemoveAll<U>(SCG.IEnumerable<U> items) where U : T
+ {
+ updatecheck();
+ if (size == 0)
+ return;
+ //TODO: reactivate the old code for small sizes
+ HashBag<T> toremove = new HashBag<T>(itemequalityComparer);
+ toremove.AddAll(items);
+ if (toremove.Count == 0)
+ return;
+ RaiseForRemoveAllHandler raiseHandler = new RaiseForRemoveAllHandler(underlying ?? this);
+ bool mustFire = raiseHandler.MustFire;
+ ViewHandler viewHandler = new ViewHandler(this);
+ int j = offset;
+ int removed = 0;
+ int i = offset, end = offset + size;
+#if HASHINDEX
+ KeyValuePair<T, int> p = new KeyValuePair<T, int>();
+#endif
+ while (i < end)
+ {
+ T item;
+ //pass by a stretch of nodes
+ while (i < end && !toremove.Contains(item = array[i]))
+ {
+#if HASHINDEX
+ if (j < i)
+ {
+ p.Key = item;
+ p.Value = j;
+ itemIndex.Update(p);
+ }
+#endif
+ //if (j<i)
+ array[j] = item;
+ i++; j++;
+ }
+ viewHandler.skipEndpoints(removed, i);
+ //Remove a stretch of nodes
+ while (i < end && toremove.Remove(item = array[i]))
+ {
+#if HASHINDEX
+ p.Key = item;
+ itemIndex.Remove(p);
+#endif
+ if (mustFire)
+ raiseHandler.Remove(item);
+ removed++;
+ i++;
+ viewHandler.updateViewSizesAndCounts(removed, i);
+ }
+ }
+ if (removed == 0)
+ return;
+ viewHandler.updateViewSizesAndCounts(removed, underlyingsize);
+ Array.Copy(array, offset + size, array, j, underlyingsize - offset - size);
+ addtosize(-removed);
+ Array.Clear(array, underlyingsize, removed);
+#if HASHINDEX
+ reindex(j);
+#endif
+ if (mustFire)
+ raiseHandler.Raise();
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="predicate"></param>
+ void RemoveAll(Fun<T,bool> predicate)
+ {
+ updatecheck();
+ if (size == 0)
+ return;
+ RaiseForRemoveAllHandler raiseHandler = new RaiseForRemoveAllHandler(underlying ?? this);
+ bool mustFire = raiseHandler.MustFire;
+ ViewHandler viewHandler = new ViewHandler(this);
+ int j = offset;
+ int removed = 0;
+ int i = offset, end = offset + size;
+#if HASHINDEX
+ KeyValuePair<T, int> p = new KeyValuePair<T, int>();
+#endif
+ while (i < end)
+ {
+ T item;
+ //pass by a stretch of nodes
+ while (i < end && !predicate(item = array[i]))
+ {
+ updatecheck();
+#if HASHINDEX
+ if (j < i)
+ {
+ p.Key = item;
+ p.Value = j;
+ itemIndex.Update(p);
+ }
+#endif
+ //if (j<i)
+ array[j] = item;
+ i++; j++;
+ }
+ updatecheck();
+ viewHandler.skipEndpoints(removed, i);
+ //Remove a stretch of nodes
+ while (i < end && predicate(item = array[i]))
+ {
+ updatecheck();
+#if HASHINDEX
+ p.Key = item;
+ itemIndex.Remove(p);
+#endif
+ if (mustFire)
+ raiseHandler.Remove(item);
+ removed++;
+ i++;
+ viewHandler.updateViewSizesAndCounts(removed, i);
+ }
+ updatecheck();
+ }
+ if (removed == 0)
+ return;
+ viewHandler.updateViewSizesAndCounts(removed, underlyingsize);
+ Array.Copy(array, offset + size, array, j, underlyingsize - offset - size);
+ addtosize(-removed);
+ Array.Clear(array, underlyingsize, removed);
+#if HASHINDEX
+ reindex(j);
+#endif
+ if (mustFire)
+ raiseHandler.Raise();
+ }
+
+ /// <summary>
+ /// Remove all items from this collection, resetting internal array size.
+ /// </summary>
+ [Tested]
+ public override void Clear()
+ {
+ if (underlying == null)
+ {
+ updatecheck();
+ if (size == 0)
+ return;
+ int oldsize = size;
+ fixViewsBeforeRemove(0, size);
+#if HASHINDEX
+ itemIndex.Clear();
+#endif
+ array = new T[8];
+ size = 0;
+ (underlying ?? this).raiseForRemoveInterval(offset, oldsize);
+ }
+ else
+ RemoveInterval(0, size);
+ }
+
+ /// <summary>
+ /// Remove all items not in some other collection from this one, taking multiplicities into account.
+ /// Items are retained front first.
+ /// </summary>
+ /// <typeparam name="U"></typeparam>
+ /// <param name="items">The items to retain.</param>
+ [Tested]
+ public virtual void RetainAll<U>(SCG.IEnumerable<U> items) where U : T
+ {
+ updatecheck();
+ if (size == 0)
+ return;
+ HashBag<T> toretain = new HashBag<T>(itemequalityComparer);
+ toretain.AddAll(items);
+ if (toretain.Count == 0)
+ {
+ Clear();
+ return;
+ }
+ RaiseForRemoveAllHandler raiseHandler = new RaiseForRemoveAllHandler(underlying ?? this);
+ bool mustFire = raiseHandler.MustFire;
+ ViewHandler viewHandler = new ViewHandler(this);
+ int j = offset;
+ int removed = 0;
+ int i = offset, end = offset + size;
+#if HASHINDEX
+ KeyValuePair<T, int> p = new KeyValuePair<T, int>();
+#endif
+ while (i < end)
+ {
+ T item;
+ //pass by a stretch of nodes
+ while (i < end && toretain.Remove(item = array[i]))
+ {
+#if HASHINDEX
+ if (j < i)
+ {
+ p.Key = item;
+ p.Value = j;
+ itemIndex.Update(p);
+ }
+#endif
+ //if (j<i)
+ array[j] = item;
+ i++; j++;
+ }
+ viewHandler.skipEndpoints(removed, i);
+ //Remove a stretch of nodes
+ while (i < end && !toretain.Contains(item = array[i]))
+ {
+#if HASHINDEX
+ p.Key = item;
+ itemIndex.Remove(p);
+#endif
+ if (mustFire)
+ raiseHandler.Remove(item);
+ removed++;
+ i++;
+ viewHandler.updateViewSizesAndCounts(removed, i);
+ }
+ }
+ if (removed == 0)
+ return;
+ viewHandler.updateViewSizesAndCounts(removed, underlyingsize);
+ Array.Copy(array, offset + size, array, j, underlyingsize - offset - size);
+ addtosize(-removed);
+ Array.Clear(array, underlyingsize, removed);
+#if HASHINDEX
+ reindex(j);
+#endif
+ raiseHandler.Raise();
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="predicate"></param>
+ void RetainAll(Fun<T, bool> predicate)
+ {
+ updatecheck();
+ if (size == 0)
+ return;
+ RaiseForRemoveAllHandler raiseHandler = new RaiseForRemoveAllHandler(underlying ?? this);
+ bool mustFire = raiseHandler.MustFire;
+ ViewHandler viewHandler = new ViewHandler(this);
+ int j = offset;
+ int removed = 0;
+ int i = offset, end = offset + size;
+#if HASHINDEX
+ KeyValuePair<T, int> p = new KeyValuePair<T, int>();
+#endif
+ while (i < end)
+ {
+ T item;
+ //pass by a stretch of nodes
+ while (i < end && predicate(item = array[i]))
+ {
+ updatecheck();
+#if HASHINDEX
+ if (j < i)
+ {
+ p.Key = item;
+ p.Value = j;
+ itemIndex.Update(p);
+ }
+#endif
+ //if (j<i)
+ array[j] = item;
+ i++; j++;
+ }
+ updatecheck();
+ viewHandler.skipEndpoints(removed, i);
+ //Remove a stretch of nodes
+ while (i < end && !predicate(item = array[i]))
+ {
+ updatecheck();
+#if HASHINDEX
+ p.Key = item;
+ itemIndex.Remove(p);
+#endif
+ if (mustFire)
+ raiseHandler.Remove(item);
+ removed++;
+ i++;
+ viewHandler.updateViewSizesAndCounts(removed, i);
+ }
+ updatecheck();
+ }
+ if (removed == 0)
+ return;
+ viewHandler.updateViewSizesAndCounts(removed, underlyingsize);
+ Array.Copy(array, offset + size, array, j, underlyingsize - offset - size);
+ addtosize(-removed);
+ Array.Clear(array, underlyingsize, removed);
+#if HASHINDEX
+ reindex(j);
+#endif
+ raiseHandler.Raise();
+ }
+
+
+ /// <summary>
+ /// Check if this collection contains all the values in another collection,
+ /// taking multiplicities into account.
+ /// Current implementation is not optimal.
+ /// </summary>
+ /// <param name="items">The </param>
+ /// <typeparam name="U"></typeparam>
+ /// <returns>True if all values in <code>items</code>is in this collection.</returns>
+ [Tested]
+ public virtual bool ContainsAll<U>(SCG.IEnumerable<U> items) where U : T
+ {
+ validitycheck();
+#if HASHINDEX
+ foreach (T item in items)
+ if (indexOf(item) < 0)
+ return false;
+
+ return true;
+#else
+ //TODO: use aux hash bag to obtain linear time procedure
+ HashBag<T> tomatch = new HashBag<T>(itemequalityComparer);
+ tomatch.AddAll(items);
+ if (tomatch.Count == 0)
+ return true;
+ for (int i = offset, end = offset + size; i < end; i++)
+ {
+ tomatch.Remove(array[i]);
+ if (tomatch.Count == 0)
+ return true;
+ }
+ return false;
+#endif
+ }
+
+
+ /// <summary>
+ /// Count the number of items of the collection equal to a particular value.
+ /// Returns 0 if and only if the value is not in the collection.
+ /// </summary>
+ /// <param name="item">The value to count.</param>
+ /// <returns>The number of copies found.</returns>
+ [Tested]
+ public virtual int ContainsCount(T item)
+ {
+ validitycheck();
+#if HASHINDEX
+ return indexOf(item) >= 0 ? 1 : 0;
+#else
+ int count = 0;
+ for (int i = 0; i < size; i++)
+ if (equals(item, array[offset + i]))
+ count++;
+ return count;
+#endif
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public virtual ICollectionValue<T> UniqueItems()
+ {
+#if HASHINDEX
+ return this;
+#else
+ HashBag<T> hashbag = new HashBag<T>(itemequalityComparer);
+ hashbag.AddAll(this);
+ return hashbag.UniqueItems();
+#endif
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public virtual ICollectionValue<KeyValuePair<T, int>> ItemMultiplicities()
+ {
+#if HASHINDEX
+ return new MultiplicityOne<T>(this);
+#else
+ HashBag<T> hashbag = new HashBag<T>(itemequalityComparer);
+ hashbag.AddAll(this);
+ return hashbag.ItemMultiplicities();
+#endif
+ }
+
+
+
+
+
+ /// <summary>
+ /// Remove all items equal to a given one.
+ /// </summary>
+ /// <param name="item">The value to remove.</param>
+ [Tested]
+ public virtual void RemoveAllCopies(T item)
+ {
+#if HASHINDEX
+ Remove(item);
+#else
+ updatecheck();
+ if (size == 0)
+ return;
+ RaiseForRemoveAllHandler raiseHandler = new RaiseForRemoveAllHandler(underlying ?? this);
+ bool mustFire = raiseHandler.MustFire;
+ ViewHandler viewHandler = new ViewHandler(this);
+ int j = offset;
+ int removed = 0;
+ int i = offset, end = offset + size;
+ while (i < end)
+ {
+ //pass by a stretch of nodes
+ while (i < end && !equals(item, array[i]))
+ array[j++] = array[i++];
+ viewHandler.skipEndpoints(removed, i);
+ //Remove a stretch of nodes
+ while (i < end && equals(item, array[i]))
+ {
+ if (mustFire)
+ raiseHandler.Remove(array[i]);
+ removed++;
+ i++;
+ viewHandler.updateViewSizesAndCounts(removed, i);
+ }
+ }
+ if (removed == 0)
+ return;
+ viewHandler.updateViewSizesAndCounts(removed, underlyingsize);
+ Array.Copy(array, offset + size, array, j, underlyingsize - offset - size);
+ addtosize(-removed);
+ Array.Clear(array, underlyingsize, removed);
+ raiseHandler.Raise();
+#endif
+ }
+
+
+ //TODO: check views
+ /// <summary>
+ /// Check the integrity of the internal data structures of this array list.
+ /// </summary>
+ /// <returns>True if check does not fail.</returns>
+ [Tested]
+ public override bool Check()
+ {
+ bool retval = true;
+
+ if (underlyingsize > array.Length)
+ {
+ Console.WriteLine("underlyingsize ({0}) > array.Length ({1})", size, array.Length);
+ return false;
+ }
+
+ if (offset + size > underlyingsize)
+ {
+ Console.WriteLine("offset({0})+size({1}) > underlyingsize ({2})", offset, size, underlyingsize);
+ return false;
+ }
+
+ if (offset < 0)
+ {
+ Console.WriteLine("offset({0}) < 0", offset);
+ return false;
+ }
+
+ for (int i = 0; i < underlyingsize; i++)
+ {
+ if ((object)(array[i]) == null)
+ {
+ Console.WriteLine("Bad element: null at (base)index {0}", i);
+ retval = false;
+ }
+ }
+
+ for (int i = underlyingsize, length = array.Length; i < length; i++)
+ {
+ if (!equals(array[i], default(T)))
+ {
+ Console.WriteLine("Bad element: != default(T) at (base)index {0}", i);
+ retval = false;
+ }
+ }
+
+#if HASHINDEX
+ if (underlyingsize != itemIndex.Count)
+ {
+ Console.WriteLine("size ({0})!= index.Count ({1})", size, itemIndex.Count);
+ retval = false;
+ }
+
+ for (int i = 0; i < underlyingsize; i++)
+ {
+ KeyValuePair<T, int> p = new KeyValuePair<T, int>(array[i]);
+
+ if (!itemIndex.Find(ref p))
+ {
+ Console.WriteLine("Item {1} at {0} not in hashindex", i, array[i]);
+ retval = false;
+ }
+
+ if (p.Value != i)
+ {
+ Console.WriteLine("Item {1} at {0} has hashindex {2}", i, array[i], p.Value);
+ retval = false;
+ }
+ }
+#endif
+ return retval;
+ }
+
+ #endregion
+
+ #region IExtensible<T> Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>True, indicating array list has bag semantics.</value>
+ [Tested]
+ public virtual bool AllowsDuplicates
+ {
+ [Tested]
+ get
+ {
+#if HASHINDEX
+ return false;
+#else
+ return true;
+#endif
+ }
+ }
+
+ /// <summary>
+ /// By convention this is true for any collection with set semantics.
+ /// </summary>
+ /// <value>True if only one representative of a group of equal items
+ /// is kept in the collection together with the total count.</value>
+ public virtual bool DuplicatesByCounting
+ {
+ get
+ {
+#if HASHINDEX
+ return true;
+#else
+ return false;
+#endif
+ }
+ }
+
+ /// <summary>
+ /// Add an item to end of this list.
+ /// </summary>
+ /// <param name="item">The item to add.</param>
+ /// <returns>True</returns>
+ [Tested]
+ public virtual bool Add(T item)
+ {
+ updatecheck();
+#if HASHINDEX
+ KeyValuePair<T, int> p = new KeyValuePair<T, int>(item, size + offset);
+ if (itemIndex.FindOrAdd(ref p))
+ return false;
+#endif
+ baseinsert(size, item);
+#if HASHINDEX
+ reindex(size + offset);
+#endif
+ (underlying ?? this).raiseForAdd(item);
+ return true;
+ }
+
+
+ /// <summary>
+ /// Add the elements from another collection to this collection.
+ /// </summary>
+ /// <typeparam name="U"></typeparam>
+ /// <param name="items"></param>
+ [Tested]
+ public virtual void AddAll<U>(SCG.IEnumerable<U> items) where U : T
+ {
+ updatecheck();
+ int toadd = EnumerableBase<U>.countItems(items);
+ if (toadd == 0)
+ return;
+
+ if (toadd + underlyingsize > array.Length)
+ expand(toadd + underlyingsize, underlyingsize);
+
+ int i = size + offset;
+ if (underlyingsize > i)
+ Array.Copy(array, i, array, i + toadd, underlyingsize - i);
+ try
+ {
+ foreach (T item in items)
+ {
+#if HASHINDEX
+ KeyValuePair<T, int> p = new KeyValuePair<T, int>(item, i);
+ if (itemIndex.FindOrAdd(ref p))
+ continue;
+#endif
+ array[i++] = item;
+ }
+ }
+ finally
+ {
+ int added = i - size - offset;
+ if (added < toadd)
+ {
+ Array.Copy(array, size + offset + toadd, array, i, underlyingsize - size - offset);
+ Array.Clear(array, underlyingsize + added, toadd - added);
+ }
+ if (added > 0)
+ {
+ addtosize(added);
+#if HASHINDEX
+ reindex(i);
+#endif
+ fixViewsAfterInsert(added, i - added);
+ (underlying ?? this).raiseForAddAll(i - added, added);
+ }
+ }
+ }
+ private void raiseForAddAll(int start, int added)
+ {
+ if ((ActiveEvents & EventTypeEnum.Added) != 0)
+ for (int i = start, end = start + added; i < end; i++)
+ raiseItemsAdded(array[i], 1);
+ raiseCollectionChanged();
+ }
+
+ #endregion
+
+ #region IDirectedEnumerable<T> Members
+
+ /// <summary>
+ /// Create a collection containing the same items as this collection, but
+ /// whose enumerator will enumerate the items backwards. The new collection
+ /// will become invalid if the original is modified. Method typicaly used as in
+ /// <code>foreach (T x in coll.Backwards()) {...}</code>
+ /// </summary>
+ /// <returns>The backwards collection.</returns>
+ [Tested]
+ IDirectedEnumerable<T> IDirectedEnumerable<T>.Backwards() { return Backwards(); }
+
+ #endregion
+
+ #region ICollectionValue<T> Members
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>The number of items in this collection</value>
+ [Tested]
+ public override int Count { [Tested]get { validitycheck(); return size; } }
+ #endregion
+
+ #region IEnumerable<T> Members
+ //TODO: make tests of all calls on a disposed view throws the right exception! (Which should be C5.InvalidListViewException)
+ /// <summary>
+ /// Create an enumerator for the collection
+ /// </summary>
+ /// <returns>The enumerator</returns>
+ [Tested]
+ public override SCG.IEnumerator<T> GetEnumerator()
+ {
+ validitycheck();
+ return base.GetEnumerator();
+ }
+ #endregion
+
+#if HASHINDEX
+#else
+ #region IStack<T> Members
+
+ /// <summary>
+ /// Push an item to the top of the stack.
+ /// </summary>
+ /// <param name="item">The item</param>
+ [Tested]
+ public virtual void Push(T item)
+ {
+ InsertLast(item);
+ }
+
+ /// <summary>
+ /// Pop the item at the top of the stack from the stack.
+ /// </summary>
+ /// <returns>The popped item.</returns>
+ [Tested]
+ public virtual T Pop()
+ {
+ return RemoveLast();
+ }
+
+ #endregion
+
+ #region IQueue<T> Members
+
+ /// <summary>
+ /// Enqueue an item at the back of the queue.
+ /// </summary>
+ /// <param name="item">The item</param>
+ [Tested]
+ public virtual void Enqueue(T item)
+ {
+ InsertLast(item);
+ }
+
+ /// <summary>
+ /// Dequeue an item from the front of the queue.
+ /// </summary>
+ /// <returns>The item</returns>
+ [Tested]
+ public virtual T Dequeue()
+ {
+ return RemoveFirst();
+ }
+
+ #endregion
+#endif
+ #region IDisposable Members
+
+ /// <summary>
+ /// Invalidate this list. If a view, just invalidate the view.
+ /// If not a view, invalidate the list and all views on it.
+ /// </summary>
+ public virtual void Dispose()
+ {
+ Dispose(false);
+ }
+
+ void Dispose(bool disposingUnderlying)
+ {
+ if (isValid)
+ {
+ if (underlying != null)
+ {
+ isValid = false;
+ if (!disposingUnderlying)
+ views.Remove(myWeakReference);
+ underlying = null;
+ views = null;
+ myWeakReference = null;
+ }
+ else
+ {
+ //isValid = false;
+ foreach (ArrayList<T> view in views)
+ view.Dispose(true);
+ Clear();
+ }
+ }
+ }
+
+ #endregion
+
+ #region ICloneable Members
+
+ /// <summary>
+ /// Make a shallow copy of this ArrayList.
+ /// </summary>
+ /// <returns></returns>
+ public virtual object Clone()
+ {
+ ArrayList<T> clone = new ArrayList<T>(size, itemequalityComparer);
+ clone.AddAll(this);
+ return clone;
+ }
+
+ #endregion
+
+ #region ISerializable Members
+/*
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="info"></param>
+ /// <param name="context"></param>
+ public ArrayList(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) :
+ this(info.GetInt32("sz"),(SCG.IEqualityComparer<T>)(info.GetValue("eq",typeof(SCG.IEqualityComparer<T>))))
+ {
+ size = info.GetInt32("sz");
+ for (int i = 0; i < size; i++)
+ {
+ array[i] = (T)(info.GetValue("elem" + i,typeof(T)));
+ }
+#if HASHINDEX
+ reindex(0);
+#endif
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="info"></param>
+ /// <param name="context"></param>
+ public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
+ {
+ info.AddValue("sz", size);
+ info.AddValue("eq", EqualityComparer);
+ for (int i = 0; i < size; i++)
+ {
+ info.AddValue("elem" + i, array[i + offset]);
+ }
+ }
+*/
+#endregion
+ }
+}
diff --git a/mcs/class/Mono.C5/C5/arrays/CircularQueue.cs b/mcs/class/Mono.C5/C5/arrays/CircularQueue.cs
new file mode 100644
index 00000000000..05fe2163d4d
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/arrays/CircularQueue.cs
@@ -0,0 +1,334 @@
+/*
+ Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+using System;
+using System.Diagnostics;
+using SCG = System.Collections.Generic;
+namespace C5
+{
+ /// <summary>
+ ///
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ public class CircularQueue<T> : SequencedBase<T>, IQueue<T>, IStack<T>
+ {
+ #region Fields
+ /*
+ Invariant: the itemes in the queue ar the elements from front upwards,
+ possibly wrapping around at the end of array, to back.
+
+ if front<=back then size = back - front + 1;
+ else size = array.Length + back - front + 1;
+
+ */
+ int front, back;
+ /// <summary>
+ /// The internal container array is doubled when necessary, but never shrinked.
+ /// </summary>
+ T[] array;
+ bool forwards = true, original = true;
+ #endregion
+
+ #region Events
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public override EventTypeEnum ListenableEvents { get { return EventTypeEnum.Basic; } }
+
+ #endregion
+
+ #region Util
+ void expand()
+ {
+ int newlength = 2 * array.Length;
+ T[] newarray = new T[newlength];
+
+ if (front <= back)
+ Array.Copy(array, front, newarray, 0, size);
+ else
+ {
+ int half = array.Length - front;
+ Array.Copy(array, front, newarray, 0, half);
+ Array.Copy(array, 0, newarray, half, size - half);
+ }
+
+ front = 0;
+ back = size;
+ array = newarray;
+ }
+
+ #endregion
+
+ #region Constructors
+
+ /// <summary>
+ ///
+ /// </summary>
+ public CircularQueue() : this(8) { }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="capacity"></param>
+ public CircularQueue(int capacity)
+ : base(EqualityComparer<T>.Default)
+ {
+ int newlength = 8;
+ while (newlength < capacity) newlength *= 2;
+ array = new T[newlength];
+ }
+
+ #endregion
+
+ #region IQueue<T> Members
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public virtual bool AllowsDuplicates { get { return true; } }
+
+ /// <summary>
+ /// Get the i'th item in the queue. The front of the queue is at index 0.
+ /// </summary>
+ /// <param name="i"></param>
+ /// <returns></returns>
+ public virtual T this[int i]
+ {
+ get
+ {
+ if (i < 0 || i >= size)
+ throw new IndexOutOfRangeException();
+ i = i + front;
+ return array[i >= size ? i - size : i];
+ }
+ }
+
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ [Tested]
+ public virtual void Enqueue(T item)
+ {
+ if (!original)
+ throw new ReadOnlyCollectionException();
+ stamp++;
+ if (size == array.Length - 1) expand();
+ size++;
+ int oldback = back++;
+ if (back == array.Length) back = 0;
+ array[oldback] = item;
+ if (ActiveEvents != 0)
+ raiseForAdd(item);
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ [Tested]
+ public virtual T Dequeue()
+ {
+ if (!original)
+ throw new ReadOnlyCollectionException("Object is a non-updatable clone");
+ stamp++;
+ if (size == 0)
+ throw new NoSuchItemException();
+ size--;
+ int oldfront = front++;
+ if (front == array.Length) front = 0;
+ T retval = array[oldfront];
+ array[oldfront] = default(T);
+ if (ActiveEvents != 0)
+ raiseForRemove(retval);
+ return retval;
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ public void Push(T item) //== Enqueue
+ {
+ if (!original)
+ throw new ReadOnlyCollectionException();
+ stamp++;
+ if (size == array.Length - 1) expand();
+ size++;
+ int oldback = back++;
+ if (back == array.Length) back = 0;
+ array[oldback] = item;
+ if (ActiveEvents != 0)
+ raiseForAdd(item);
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public T Pop()
+ {
+ if (!original)
+ throw new ReadOnlyCollectionException("Object is a non-updatable clone");
+ stamp++;
+ if (size == 0)
+ throw new NoSuchItemException();
+ size--;
+ back--;
+ if (back == -1) back = array.Length - 1;
+ T retval = array[back];
+ array[back] = default(T);
+ if (ActiveEvents != 0)
+ raiseForRemove(retval);
+ return retval;
+ }
+ #endregion
+
+ #region ICollectionValue<T> Members
+
+ //TODO: implement these with Array.Copy instead of relying on XxxBase:
+ /*
+ public void CopyTo(T[] a, int i)
+ {
+ }
+
+ public T[] ToArray()
+ {
+ }*/
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ [Tested]
+ public override T Choose()
+ {
+ if (size == 0)
+ throw new NoSuchItemException();
+ return array[front];
+ }
+
+ #endregion
+
+ #region IEnumerable<T> Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public override SCG.IEnumerator<T> GetEnumerator()
+ {
+ int stamp = this.stamp;
+ if (forwards)
+ {
+ int position = front;
+ int end = front <= back ? back : array.Length;
+ while (position < end)
+ {
+ if (stamp != this.stamp)
+ throw new CollectionModifiedException();
+ yield return array[position++];
+ }
+ if (front > back)
+ {
+ position = 0;
+ while (position < back)
+ {
+ if (stamp != this.stamp)
+ throw new CollectionModifiedException();
+ yield return array[position++];
+ }
+ }
+ }
+ else
+ {
+ int position = back - 1;
+ int end = front <= back ? front : 0;
+ while (position >= end)
+ {
+ if (stamp != this.stamp)
+ throw new CollectionModifiedException();
+ yield return array[position--];
+ }
+ if (front > back)
+ {
+ position = array.Length - 1;
+ while (position >= front)
+ {
+ if (stamp != this.stamp)
+ throw new CollectionModifiedException();
+ yield return array[position--];
+ }
+ }
+ }
+ }
+
+ #endregion
+
+ #region IDirectedCollectionValue<T> Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public override IDirectedCollectionValue<T> Backwards()
+ {
+ CircularQueue<T> retval = (CircularQueue<T>)MemberwiseClone();
+ retval.original = false;
+ retval.forwards = !forwards;
+ return retval;
+ }
+
+ #endregion
+
+ #region IDirectedEnumerable<T> Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ IDirectedEnumerable<T> IDirectedEnumerable<T>.Backwards()
+ {
+ return Backwards();
+ }
+
+ #endregion
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public virtual bool Check()
+ {
+ if (front < 0 || front >= array.Length || back < 0 || back >= array.Length ||
+ (front <= back && size != back - front) || (front > back && size != array.Length + back - front))
+ {
+ Console.WriteLine("Bad combination of (front,back,size,array.Length): ({0},{1},{2},{3})",
+ front, back, size, array.Length);
+ return false;
+ }
+ return true;
+ }
+ }
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/C5/arrays/SortedArray.cs b/mcs/class/Mono.C5/C5/arrays/SortedArray.cs
new file mode 100644
index 00000000000..b7bc75339c5
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/arrays/SortedArray.cs
@@ -0,0 +1,1266 @@
+/*
+ Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+using System;
+using System.Diagnostics;
+using SCG = System.Collections.Generic;
+namespace C5
+{
+ /// <summary>
+ /// A collection class implementing a sorted dynamic array data structure.
+ /// </summary>
+ [Serializable]
+ public class SortedArray<T> : ArrayBase<T>, IIndexedSorted<T>
+ {
+ #region Features
+ /// <summary>
+ /// A debugging artifact. To be removed.
+ /// </summary>
+ [Flags]
+ public enum Feature : short
+ {
+ /// <summary>
+ /// A debugging artifact. To be removed.
+ /// </summary>
+ Standard = 0
+ }
+
+
+ static Feature features = Feature.Standard;
+
+
+ /// <summary>
+ /// A debugging artifact. To be removed.
+ /// </summary>
+ /// <value></value>
+ public static Feature Features { get { return features; } }
+
+ #endregion
+
+ #region Fields
+
+ SCG.IComparer<T> comparer;
+
+ #endregion
+
+ #region Util
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item">The item to search for</param>
+ /// <param name="mid">The least index, mid, for which array[mid] >= item</param>
+ /// <returns>True if item found</returns>
+ private bool binarySearch(T item, out int mid)
+ {
+ int bot = 0, top = size;
+
+ mid = top / 2;
+ while (top > bot)
+ {
+ int c;
+
+ if ((c = comparer.Compare(array[mid], item)) == 0)
+ return true;
+
+ if (c > 0)
+ { top = mid; }
+ else
+ { bot = mid + 1; }
+
+ mid = (bot + top) / 2;
+ }
+
+ return false;
+ }
+
+ private int indexOf(T item)
+ {
+ int ind;
+
+ if (binarySearch(item, out ind))
+ return ind;
+
+ return ~ind;
+ }
+
+ #endregion
+
+ #region Constructors
+
+ /// <summary>
+ /// Create a dynamic sorted array with a natural comparer
+ /// (and item equalityComparer, assumed compatible)
+ /// </summary>
+ /// <exception cref="NotComparableException">If <code>T</code> is not comparable.
+ /// </exception>
+ public SortedArray() : this(8) { }
+
+
+ /// <summary>
+ /// Create a dynamic sorted array with a natural comparer
+ /// (and item equalityComparer, assumed compatible)
+ /// and prescribed initial capacity.
+ /// </summary>
+ /// <exception cref="NotComparableException">If <code>T</code> is not comparable.
+ /// </exception>
+ /// <param name="capacity">The capacity</param>
+ public SortedArray(int capacity)
+ : this(capacity, Comparer<T>.Default, EqualityComparer<T>.Default) { }
+
+
+ /// <summary>
+ /// Create a dynamic sorted array with an external comparer.
+ /// <para>The itemequalityComparer will be compatible
+ /// <see cref="T:C5.ComparerZeroHashCodeEqualityComparer`1"/> since the
+ /// default equalityComparer for T (<see cref="P:C5.EqualityComparer`1.Default"/>)
+ /// is unlikely to be compatible with the external comparer. This makes the
+ /// array inadequate for use as item in a collection of unsequenced or sequenced sets or bags
+ /// (<see cref="T:C5.ICollection`1"/> and <see cref="T:C5.ISequenced`1"/>)
+ /// </para>
+ /// </summary>
+ /// <param name="comparer">The comparer</param>
+ public SortedArray(SCG.IComparer<T> comparer)
+ : this(8, comparer) { }
+
+ /// <summary>
+ /// Create a dynamic sorted array with an external comparer
+ /// and prescribed initial capacity.
+ /// <para>The itemequalityComparer will be a compatible
+ /// <see cref="T:C5.ComparerZeroHashCodeEqualityComparer`1"/> since the
+ /// default equalityComparer for T (<see cref="P:C5.EqualityComparer`1.Default"/>)
+ /// is unlikely to be compatible with the external comparer. This makes the
+ /// sorted array inadequate for use as item in a collection of unsequenced or sequenced sets or bags
+ /// (<see cref="T:C5.ICollection`1"/> and <see cref="T:C5.ISequenced`1"/>)
+ /// </para>
+ /// </summary>
+ /// <param name="capacity">The capacity</param>
+ /// <param name="comparer">The comparer</param>
+ public SortedArray(int capacity, SCG.IComparer<T> comparer)
+ : this(capacity, comparer, new ComparerZeroHashCodeEqualityComparer<T>(comparer)) { }
+
+ /// <summary>
+ /// Create a dynamic sorted array with an external comparer, an external item equalityComparer
+ /// and prescribed initial capacity. This is the constructor to use if the collection
+ /// will be used as item in a hash table based collection.
+ /// </summary>
+ /// <param name="capacity">The capacity</param>
+ /// <param name="comparer">The item comparer</param>
+ /// <param name="equalityComparer">The item equalityComparer (assumed compatible)</param>
+ public SortedArray(int capacity, SCG.IComparer<T> comparer, SCG.IEqualityComparer<T> equalityComparer)
+ : base(capacity, equalityComparer)
+ {
+ if (comparer == null)
+ throw new NullReferenceException("Comparer cannot be null");
+ this.comparer = comparer;
+ }
+
+ #endregion
+
+ #region IIndexedSorted<T> Members
+
+ /// <summary>
+ /// Determine the number of items at or above a supplied threshold.
+ /// </summary>
+ /// <param name="bot">The lower bound (inclusive)</param>
+ /// <returns>The number of matcing items.</returns>
+ [Tested]
+ public int CountFrom(T bot)
+ {
+ int lo;
+
+ binarySearch(bot, out lo);
+ return size - lo;
+ }
+
+
+ /// <summary>
+ /// Determine the number of items between two supplied thresholds.
+ /// </summary>
+ /// <param name="bot">The lower bound (inclusive)</param>
+ /// <param name="top">The upper bound (exclusive)</param>
+ /// <returns>The number of matcing items.</returns>
+ [Tested]
+ public int CountFromTo(T bot, T top)
+ {
+ int lo, hi;
+
+ binarySearch(bot, out lo);
+ binarySearch(top, out hi);
+ return hi > lo ? hi - lo : 0;
+ }
+
+
+ /// <summary>
+ /// Determine the number of items below a supplied threshold.
+ /// </summary>
+ /// <param name="top">The upper bound (exclusive)</param>
+ /// <returns>The number of matcing items.</returns>
+ [Tested]
+ public int CountTo(T top)
+ {
+ int hi;
+
+ binarySearch(top, out hi);
+ return hi;
+ }
+
+
+ /// <summary>
+ /// Query this sorted collection for items greater than or equal to a supplied value.
+ /// </summary>
+ /// <param name="bot">The lower bound (inclusive).</param>
+ /// <returns>The result directed collection.</returns>
+ [Tested]
+ public IDirectedCollectionValue<T> RangeFrom(T bot)
+ {
+ int lo;
+
+ binarySearch(bot, out lo);
+ return new Range(this, lo, size - lo, true);
+ }
+
+
+ /// <summary>
+ /// Query this sorted collection for items between two supplied values.
+ /// </summary>
+ /// <param name="bot">The lower bound (inclusive).</param>
+ /// <param name="top">The upper bound (exclusive).</param>
+ /// <returns>The result directed collection.</returns>
+ [Tested]
+ public IDirectedCollectionValue<T> RangeFromTo(T bot, T top)
+ {
+ int lo, hi;
+
+ binarySearch(bot, out lo);
+ binarySearch(top, out hi);
+
+ int sz = hi - lo;
+
+ return new Range(this, lo, sz, true);
+ }
+
+
+ /// <summary>
+ /// Query this sorted collection for items less than a supplied value.
+ /// </summary>
+ /// <param name="top">The upper bound (exclusive).</param>
+ /// <returns>The result directed collection.</returns>
+ [Tested]
+ public IDirectedCollectionValue<T> RangeTo(T top)
+ {
+ int hi;
+
+ binarySearch(top, out hi);
+ return new Range(this, 0, hi, true);
+ }
+
+
+ /// <summary>
+ /// Create a new indexed sorted collection consisting of the items of this
+ /// indexed sorted collection satisfying a certain predicate.
+ /// </summary>
+ /// <param name="f">The filter delegate defining the predicate.</param>
+ /// <returns>The new indexed sorted collection.</returns>
+ [Tested]
+ public IIndexedSorted<T> FindAll(Fun<T, bool> f)
+ {
+ SortedArray<T> res = new SortedArray<T>(comparer);
+ int j = 0, rescap = res.array.Length;
+
+ for (int i = 0; i < size; i++)
+ {
+ T a = array[i];
+
+ if (f(a))
+ {
+ if (j == rescap) res.expand(rescap = 2 * rescap, j);
+
+ res.array[j++] = a;
+ }
+ }
+
+ res.size = j;
+ return res;
+ }
+
+
+ /// <summary>
+ /// Create a new indexed sorted collection consisting of the results of
+ /// mapping all items of this list.
+ /// <exception cref="ArgumentException"/> if the map is not increasing over
+ /// the items of this collection (with respect to the two given comparison
+ /// relations).
+ /// </summary>
+ /// <param name="m">The delegate definging the map.</param>
+ /// <param name="c">The comparion relation to use for the result.</param>
+ /// <returns>The new sorted collection.</returns>
+ [Tested]
+ public IIndexedSorted<V> Map<V>(Fun<T, V> m, SCG.IComparer<V> c)
+ {
+ SortedArray<V> res = new SortedArray<V>(size, c);
+
+ if (size > 0)
+ {
+ V oldv = res.array[0] = m(array[0]), newv;
+
+ for (int i = 1; i < size; i++)
+ {
+ if (c.Compare(oldv, newv = res.array[i] = m(array[i])) >= 0)
+ throw new ArgumentException("mapper not monotonic");
+
+ oldv = newv;
+ }
+ }
+
+ res.size = size;
+ return res;
+ }
+
+ #endregion
+
+ #region ISorted<T> Members
+
+ /// <summary>
+ /// Find the strict predecessor in the sorted collection of a particular value,
+ /// i.e. the largest item in the collection less than the supplied value.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if no such element exists (the
+ /// supplied value is less than or equal to the minimum of this collection.)</exception>
+ /// <param name="item">The item to find the predecessor for.</param>
+ /// <returns>The predecessor.</returns>
+ [Tested]
+ public T Predecessor(T item)
+ {
+ int lo;
+
+ binarySearch(item, out lo);
+ if (lo == 0)
+ throw new NoSuchItemException();
+
+ return array[lo - 1];
+ }
+
+
+ /// <summary>
+ /// Find the strict successor in the sorted collection of a particular value,
+ /// i.e. the least item in the collection greater than the supplied value.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if no such element exists (the
+ /// supplied value is greater than or equal to the maximum of this collection.)</exception>
+ /// <param name="item">The item to find the successor for.</param>
+ /// <returns>The successor.</returns>
+ [Tested]
+ public T Successor(T item)
+ {
+ int hi;
+
+ if (binarySearch(item, out hi)) hi++;
+
+ if (hi >= size)
+ throw new NoSuchItemException();
+
+ return array[hi];
+ }
+
+
+ /// <summary>
+ /// Find the weak predecessor in the sorted collection of a particular value,
+ /// i.e. the largest item in the collection less than or equal to the supplied value.
+ /// <exception cref="NoSuchItemException"/> if no such element exists (the
+ /// supplied value is less than the minimum of this collection.)
+ /// </summary>
+ /// <param name="item">The item to find the weak predecessor for.</param>
+ /// <returns>The weak predecessor.</returns>
+ [Tested]
+ public T WeakPredecessor(T item)
+ {
+ int lo;
+
+ if (!binarySearch(item, out lo)) lo--;
+
+ if (lo < 0)
+ throw new NoSuchItemException();
+
+ return array[lo];
+ }
+
+
+ /// <summary>
+ /// Find the weak successor in the sorted collection of a particular value,
+ /// i.e. the least item in the collection greater than or equal to the supplied value.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if no such element exists (the
+ /// supplied value is greater than the maximum of this collection.)</exception>
+ /// <param name="item">The item to find the weak successor for.</param>
+ /// <returns>The weak successor.</returns>
+ [Tested]
+ public T WeakSuccessor(T item)
+ {
+ int hi;
+
+ binarySearch(item, out hi);
+ if (hi >= size)
+ throw new NoSuchItemException();
+
+ return array[hi];
+ }
+
+
+ /// <summary>
+ /// Perform a search in the sorted collection for the ranges in which a
+ /// non-increasing (i.e. weakly decrerasing) function from the item type to
+ /// <code>int</code> is
+ /// negative, zero respectively positive. If the supplied cut function is
+ /// not non-increasing, the result of this call is undefined.
+ /// </summary>
+ /// <param name="c">The cut function <code>T</code> to <code>int</code>, given
+ /// as an <code>IComparable&lt;T&gt;</code> object, where the cut function is
+ /// the <code>c.CompareTo(T that)</code> method.</param>
+ /// <param name="low">Returns the largest item in the collection, where the
+ /// cut function is positive (if any).</param>
+ /// <param name="lowIsValid">True if the cut function is positive somewhere
+ /// on this collection.</param>
+ /// <param name="high">Returns the least item in the collection, where the
+ /// cut function is negative (if any).</param>
+ /// <param name="highIsValid">True if the cut function is negative somewhere
+ /// on this collection.</param>
+ /// <returns></returns>
+ [Tested]
+ public bool Cut(IComparable<T> c, out T low, out bool lowIsValid, out T high, out bool highIsValid)
+ {
+ int lbest = -1, rbest = size;
+
+ low = default(T);
+ lowIsValid = false;
+ high = default(T);
+ highIsValid = false;
+
+ int bot = 0, top = size, mid, comp = -1, sol;
+
+ mid = top / 2;
+ while (top > bot)
+ {
+ if ((comp = c.CompareTo(array[mid])) == 0)
+ break;
+
+ if (comp < 0)
+ { rbest = top = mid; }
+ else
+ { lbest = mid; bot = mid + 1; }
+
+ mid = (bot + top) / 2;
+ }
+
+ if (comp != 0)
+ {
+ if (lbest >= 0) { lowIsValid = true; low = array[lbest]; }
+
+ if (rbest < size) { highIsValid = true; high = array[rbest]; }
+
+ return false;
+ }
+
+ sol = mid;
+ bot = sol - 1;
+
+ //Invariant: c.Compare(array[x]) < 0 when rbest <= x < size
+ // c.Compare(array[x]) >= 0 when x < bot)
+ //(Assuming c.Compare monotonic)
+ while (rbest > bot)
+ {
+ mid = (bot + rbest) / 2;
+ if (c.CompareTo(array[mid]) < 0)
+ { rbest = mid; }
+ else
+ { bot = mid + 1; }
+ }
+
+ if (rbest < size) { highIsValid = true; high = array[rbest]; }
+
+ top = sol + 1;
+
+ //Invariant: c.Compare(array[x]) > 0 when 0 <= x <= lbest
+ // c.Compare(array[x]) <= 0 when x>top)
+ //(Assuming c.Compare monotonic)
+ while (top > lbest)
+ {
+ mid = (lbest + top + 1) / 2;
+ if (c.CompareTo(array[mid]) > 0)
+ { lbest = mid; }
+ else
+ { top = mid - 1; }
+ }
+
+ if (lbest >= 0) { lowIsValid = true; low = array[lbest]; }
+
+ return true;
+ }
+
+
+ IDirectedEnumerable<T> ISorted<T>.RangeFrom(T bot)
+ { return RangeFrom(bot); }
+
+
+ IDirectedEnumerable<T> ISorted<T>.RangeFromTo(T bot, T top)
+ { return RangeFromTo(bot, top); }
+
+
+ IDirectedEnumerable<T> ISorted<T>.RangeTo(T top)
+ { return RangeTo(top); }
+
+
+ /// <summary>
+ /// Create a directed collection with the same items as this collection.
+ /// </summary>
+ /// <returns>The result directed collection.</returns>
+ [Tested]
+ public IDirectedCollectionValue<T> RangeAll()
+ { return new Range(this, 0, size, true); }
+
+
+ /// <summary>
+ /// Add all the items from another collection with an enumeration order that
+ /// is increasing in the items.
+ /// <exception cref="ArgumentException"/> if the enumerated items turns out
+ /// not to be in increasing order.
+ /// </summary>
+ /// <param name="items">The collection to add.</param>
+ /// <typeparam name="U"></typeparam>
+ [Tested]
+ public void AddSorted<U>(SCG.IEnumerable<U> items) where U : T
+ {
+ //Unless items have <=1 elements we would expect it to be
+ //too expensive to do repeated inserts, thus:
+ updatecheck();
+
+ int j = 0, i = 0, c = -1, itemcount = EnumerableBase<U>.countItems(items);
+ SortedArray<T> res = new SortedArray<T>(size + itemcount, comparer);
+ T lastitem = default(T);
+
+ foreach (T item in items)
+ {
+ while (i < size && (c = comparer.Compare(array[i], item)) <= 0)
+ {
+ lastitem = res.array[j++] = array[i++];
+ if (c == 0)
+ goto next;
+ }
+
+ if (j > 0 && comparer.Compare(lastitem, item) >= 0)
+ throw new ArgumentException("Argument not sorted");
+
+ lastitem = res.array[j++] = item;
+ next:
+ c = -1;
+ }
+
+ while (i < size) res.array[j++] = array[i++];
+
+ size = j;
+ array = res.array;
+ }
+
+
+ /// <summary>
+ /// Remove all items of this collection above or at a supplied threshold.
+ /// </summary>
+ /// <param name="low">The lower threshold (inclusive).</param>
+ [Tested]
+ public void RemoveRangeFrom(T low)
+ {
+ int lowind;
+
+ binarySearch(low, out lowind);
+ if (lowind == size)
+ return;
+
+ Array.Clear(array, lowind, size - lowind);
+ size = lowind;
+ }
+
+
+ /// <summary>
+ /// Remove all items of this collection between two supplied thresholds.
+ /// </summary>
+ /// <param name="low">The lower threshold (inclusive).</param>
+ /// <param name="hi">The upper threshold (exclusive).</param>
+ [Tested]
+ public void RemoveRangeFromTo(T low, T hi)
+ {
+ int lowind, highind;
+
+ binarySearch(low, out lowind);
+ binarySearch(hi, out highind);
+ if (highind <= lowind)
+ return;
+
+ Array.Copy(array, highind, array, lowind, size - highind);
+ Array.Clear(array, size - highind + lowind, highind - lowind);
+ size -= highind - lowind;
+ }
+
+
+ /// <summary>
+ /// Remove all items of this collection below a supplied threshold.
+ /// </summary>
+ /// <param name="hi">The upper threshold (exclusive).</param>
+ [Tested]
+ public void RemoveRangeTo(T hi)
+ {
+ int highind;
+
+ binarySearch(hi, out highind);
+ if (highind == 0)
+ return;
+
+ Array.Copy(array, highind, array, 0, size - highind);
+ Array.Clear(array, size - highind, highind);
+ size = size - highind;
+ }
+
+ #endregion
+
+ #region ICollection<T> Members
+ /// <summary>
+ /// The value is symbolic indicating the type of asymptotic complexity
+ /// in terms of the size of this collection (worst-case).
+ /// </summary>
+ /// <value>Speed.Log</value>
+ [Tested]
+ public Speed ContainsSpeed { [Tested]get { return Speed.Log; } }
+
+ /// <summary>
+ /// Check if this collection contains (an item equivalent to according to the
+ /// itemequalityComparer) a particular value.
+ /// </summary>
+ /// <param name="item">The value to check for.</param>
+ /// <returns>True if the items is in this collection.</returns>
+ [Tested]
+ public bool Contains(T item)
+ {
+ int ind;
+
+ return binarySearch(item, out ind);
+ }
+
+
+ /// <summary>
+ /// Check if this collection contains an item equivalent according to the
+ /// itemequalityComparer to a particular value. If so, return in the ref argument (a
+ /// binary copy of) the actual value found.
+ /// </summary>
+ /// <param name="item">The value to look for.</param>
+ /// <returns>True if the items is in this collection.</returns>
+ [Tested]
+ public bool Find(ref T item)
+ {
+ int ind;
+
+ if (binarySearch(item, out ind))
+ {
+ item = array[ind];
+ return true;
+ }
+
+ return false;
+ }
+
+
+ //This should probably just be bool Add(ref T item); !!!
+ /// <summary>
+ /// Check if this collection contains an item equivalent according to the
+ /// itemequalityComparer to a particular value. If so, return in the ref argument (a
+ /// binary copy of) the actual value found. Else, add the item to the collection.
+ /// </summary>
+ /// <param name="item">The value to look for.</param>
+ /// <returns>True if the item was added (hence not found).</returns>
+ [Tested]
+ public bool FindOrAdd(ref T item)
+ {
+ updatecheck();
+
+ int ind;
+
+ if (binarySearch(item, out ind))
+ {
+ item = array[ind];
+ return true;
+ }
+
+ if (size == array.Length - 1) expand();
+
+ Array.Copy(array, ind, array, ind + 1, size - ind);
+ array[ind] = item;
+ size++;
+ return false;
+ }
+
+
+ /// <summary>
+ /// Check if this collection contains an item equivalent according to the
+ /// itemequalityComparer to a particular value. If so, update the item in the collection
+ /// to with a binary copy of the supplied value. If the collection has bag semantics,
+ /// it is implementation dependent if this updates all equivalent copies in
+ /// the collection or just one.
+ /// </summary>
+ /// <param name="item">Value to update.</param>
+ /// <returns>True if the item was found and hence updated.</returns>
+ [Tested]
+ public bool Update(T item)
+ { T olditem; return Update(item, out olditem); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ /// <param name="olditem"></param>
+ /// <returns></returns>
+ public bool Update(T item, out T olditem)
+ {
+ updatecheck();
+
+ int ind;
+
+ if (binarySearch(item, out ind))
+ {
+ olditem = array[ind];
+ array[ind] = item;
+ return true;
+ }
+
+ olditem = default(T);
+ return false;
+ }
+
+
+ /// <summary>
+ /// Check if this collection contains an item equivalent according to the
+ /// itemequalityComparer to a particular value. If so, update the item in the collection
+ /// to with a binary copy of the supplied value; else add the value to the collection.
+ /// </summary>
+ /// <param name="item">Value to add or update.</param>
+ /// <returns>True if the item was found and updated (hence not added).</returns>
+ [Tested]
+ public bool UpdateOrAdd(T item)
+ { T olditem; return UpdateOrAdd(item, out olditem); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ /// <param name="olditem"></param>
+ /// <returns></returns>
+ public bool UpdateOrAdd(T item, out T olditem)
+ {
+ updatecheck();
+
+ int ind;
+
+ if (binarySearch(item, out ind))
+ {
+ olditem = array[ind];
+ array[ind] = item;
+ return true;
+ }
+
+ if (size == array.Length - 1) expand();
+
+ Array.Copy(array, ind, array, ind + 1, size - ind);
+ array[ind] = item;
+ size++;
+ olditem = default(T);
+ return false;
+ }
+
+
+ /// <summary>
+ /// Remove a particular item from this collection. If the collection has bag
+ /// semantics only one copy equivalent to the supplied item is removed.
+ /// </summary>
+ /// <param name="item">The value to remove.</param>
+ /// <returns>True if the item was found (and removed).</returns>
+ [Tested]
+ public bool Remove(T item)
+ {
+ int ind;
+
+ updatecheck();
+ if (binarySearch(item, out ind))
+ {
+ Array.Copy(array, ind + 1, array, ind, size - ind - 1);
+ array[--size] = default(T);
+ return true;
+ }
+
+ return false;
+ }
+
+
+ /// <summary>
+ /// Remove a particular item from this collection if found. If the collection
+ /// has bag semantics only one copy equivalent to the supplied item is removed,
+ /// which one is implementation dependent.
+ /// If an item was removed, report a binary copy of the actual item removed in
+ /// the argument.
+ /// </summary>
+ /// <param name="item">The value to remove.</param>
+ /// <param name="removeditem">The removed value.</param>
+ /// <returns>True if the item was found (and removed).</returns>
+ [Tested]
+ public bool Remove(T item, out T removeditem)
+ {
+ int ind;
+
+ updatecheck();
+ if (binarySearch(item, out ind))
+ {
+ removeditem = array[ind];
+ Array.Copy(array, ind + 1, array, ind, size - ind - 1);
+ array[--size] = default(T);
+ return true;
+ }
+
+ removeditem = default(T);
+ return false;
+ }
+
+
+ /// <summary>
+ /// Remove all items in another collection from this one.
+ /// </summary>
+ /// <typeparam name="U"></typeparam>
+ /// <param name="items">The items to remove.</param>
+ [Tested]
+ public void RemoveAll<U>(SCG.IEnumerable<U> items) where U : T
+ {
+ //This is O(m*logn) with n bits extra storage
+ //(Not better to collect the m items and sort them)
+ updatecheck();
+
+ int[] toremove = new int[(size >> 5) + 1];
+ int ind, j = 0;
+
+ foreach (T item in items)
+ if (binarySearch(item, out ind))
+ toremove[ind >> 5] |= 1 << (ind & 31);
+
+ for (int i = 0; i < size; i++)
+ if ((toremove[i >> 5] & (1 << (i & 31))) == 0)
+ array[j++] = array[i];
+
+ Array.Clear(array, j, size - j);
+ size = j;
+ }
+
+ /// <summary>
+ /// Remove all items not in some other collection from this one.
+ /// </summary>
+ /// <typeparam name="U"></typeparam>
+ /// <param name="items">The items to retain.</param>
+ [Tested]
+ public void RetainAll<U>(SCG.IEnumerable<U> items) where U : T
+ {
+ //This is O(m*logn) with n bits extra storage
+ //(Not better to collect the m items and sort them)
+ updatecheck();
+
+ int[] toretain = new int[(size >> 5) + 1];
+ int ind, j = 0;
+
+ foreach (T item in items)
+ if (binarySearch(item, out ind))
+ toretain[ind >> 5] |= 1 << (ind & 31);
+
+ for (int i = 0; i < size; i++)
+ if ((toretain[i >> 5] & (1 << (i & 31))) != 0)
+ array[j++] = array[i];
+
+ Array.Clear(array, j, size - j);
+ size = j;
+ }
+
+ /// <summary>
+ /// Check if this collection contains all the values in another collection.
+ /// Multiplicities are not taken into account.
+ /// </summary>
+ /// <param name="items">The </param>
+ /// <typeparam name="U"></typeparam>
+ /// <returns>True if all values in <code>items</code>is in this collection.</returns>
+ [Tested]
+ public bool ContainsAll<U>(SCG.IEnumerable<U> items) where U : T
+ {
+ int tmp;
+
+ foreach (T item in items)
+ if (!binarySearch(item, out tmp))
+ return false;
+
+ return true;
+ }
+
+
+ /// <summary>
+ /// Count the number of items of the collection equal to a particular value.
+ /// Returns 0 if and only if the value is not in the collection.
+ /// </summary>
+ /// <param name="item">The value to count.</param>
+ /// <returns>The number of copies found (0 or 1).</returns>
+ [Tested]
+ public int ContainsCount(T item)
+ {
+ int tmp;
+
+ return binarySearch(item, out tmp) ? 1 : 0;
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public virtual ICollectionValue<T> UniqueItems() { return this; }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public virtual ICollectionValue<KeyValuePair<T, int>> ItemMultiplicities()
+ {
+ return new MultiplicityOne<T>(this);
+ }
+
+ /// <summary>
+ /// Remove all (0 or 1) items equivalent to a given value.
+ /// </summary>
+ /// <param name="item">The value to remove.</param>
+ [Tested]
+ public void RemoveAllCopies(T item) { Remove(item); }
+
+
+ /// <summary>
+ /// Check the integrity of the internal data structures of this collection.
+ /// Only avaliable in DEBUG builds???
+ /// </summary>
+ /// <returns>True if check does not fail.</returns>
+ [Tested]
+ public override bool Check()
+ {
+ bool retval = true;
+
+ if (size > array.Length)
+ {
+ Console.WriteLine("Bad size ({0}) > array.Length ({1})", size, array.Length);
+ return false;
+ }
+
+ for (int i = 0; i < size; i++)
+ {
+ if ((object)(array[i]) == null)
+ {
+ Console.WriteLine("Bad element: null at index {0}", i);
+ return false;
+ }
+
+ if (i > 0 && comparer.Compare(array[i], array[i - 1]) <= 0)
+ {
+ Console.WriteLine("Inversion at index {0}", i);
+ retval = false;
+ }
+ }
+
+ return retval;
+ }
+
+ #endregion
+
+ #region IExtensible<T> Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>False since this collection has set semantics</value>
+ [Tested]
+ public bool AllowsDuplicates { [Tested]get { return false; } }
+
+ /// <summary>
+ /// By convention this is true for any collection with set semantics.
+ /// </summary>
+ /// <value>True if only one representative of a group of equal items
+ /// is kept in the collection together with the total count.</value>
+ public virtual bool DuplicatesByCounting { get { return true; } }
+
+ /// <summary>
+ /// Add an item to this collection if possible. If this collection has set
+ /// semantics, the item will be added if not already in the collection. If
+ /// bag semantics, the item will always be added.
+ /// </summary>
+ /// <param name="item">The item to add.</param>
+ /// <returns>True if item was added.</returns>
+ [Tested]
+ public bool Add(T item)
+ {
+ updatecheck();
+
+ int ind;
+
+ if (binarySearch(item, out ind)) return false;
+
+ insert(ind, item);
+ return true;
+ }
+
+ /// <summary>
+ /// Add the elements from another collection with a more specialized item type
+ /// to this collection. Since this
+ /// collection has set semantics, only items not already in the collection
+ /// will be added.
+ /// </summary>
+ /// <typeparam name="U">The type of items to add</typeparam>
+ /// <param name="items">The items to add</param>
+ [Tested]
+ public void AddAll<U>(SCG.IEnumerable<U> items) where U : T
+ {
+ int toadd = EnumerableBase<U>.countItems(items), newsize = array.Length;
+
+ while (newsize < size + toadd) { newsize *= 2; }
+
+ T[] newarr = new T[newsize];
+
+ toadd = 0;
+ foreach (T item in items) newarr[size + toadd++] = item;
+
+ Sorting.IntroSort<T>(newarr, size, toadd, comparer);
+
+ int j = 0, i = 0;
+ T lastitem = default(T);
+
+ //The following eliminates duplicates (including duplicates in input)
+ //while merging the old and new collection
+ for (int k = size, klimit = size + toadd; k < klimit; k++)
+ {
+ while (i < size && comparer.Compare(array[i], newarr[k]) <= 0)
+ lastitem = newarr[j++] = array[i++];
+
+ if (j == 0 || comparer.Compare(lastitem, newarr[k]) < 0)
+ lastitem = newarr[j++] = newarr[k];
+ }
+
+ while (i < size) newarr[j++] = array[i++];
+
+ Array.Clear(newarr, j, size + toadd - j);
+ size = j;
+ array = newarr;
+ }
+
+ #endregion
+
+ #region IPriorityQueue<T> Members
+
+ /// <summary>
+ /// Find the current least item of this priority queue.
+ /// </summary>
+ /// <returns>The least item.</returns>
+ [Tested]
+ public T FindMin()
+ {
+ if (size == 0)
+ throw new NoSuchItemException();
+
+ return array[0];
+ }
+
+ /// <summary>
+ /// Remove the least item from this priority queue.
+ /// </summary>
+ /// <returns>The removed item.</returns>
+ [Tested]
+ public T DeleteMin()
+ {
+ updatecheck();
+ if (size == 0)
+ throw new NoSuchItemException();
+
+ T retval = array[0];
+
+ size--;
+ Array.Copy(array, 1, array, 0, size);
+ array[size] = default(T);
+ return retval;
+ }
+
+
+ /// <summary>
+ /// Find the current largest item of this priority queue.
+ /// </summary>
+ /// <returns>The largest item.</returns>
+ [Tested]
+ public T FindMax()
+ {
+ if (size == 0)
+ throw new NoSuchItemException();
+
+ return array[size - 1];
+ }
+
+
+ /// <summary>
+ /// Remove the largest item from this priority queue.
+ /// </summary>
+ /// <returns>The removed item.</returns>
+ [Tested]
+ public T DeleteMax()
+ {
+ updatecheck();
+ if (size == 0)
+ throw new NoSuchItemException();
+
+ T retval = array[size - 1];
+
+ size--;
+ array[size] = default(T);
+ return retval;
+ }
+
+ /// <summary>
+ /// The comparer object supplied at creation time for this collection
+ /// </summary>
+ /// <value>The comparer</value>
+ public SCG.IComparer<T> Comparer { get { return comparer; } }
+
+ #endregion
+
+ #region IIndexed<T> Members
+
+ /// <summary>
+ /// <exception cref="IndexOutOfRangeException"/> if i is negative or
+ /// &gt;= the size of the collection.
+ /// </summary>
+ /// <value>The i'th item of this list.</value>
+ /// <param name="i">the index to lookup</param>
+ [Tested]
+ public T this[int i]
+ {
+ [Tested]
+ get
+ {
+ if (i < 0 || i >= size)
+ throw new IndexOutOfRangeException();
+
+ return array[i];
+ }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public virtual Speed IndexingSpeed { get { return Speed.Constant; } }
+
+ /// <summary>
+ /// Searches for an item in the list going forwrds from the start.
+ /// </summary>
+ /// <param name="item">Item to search for.</param>
+ /// <returns>Index of item from start.</returns>
+ [Tested]
+ public int IndexOf(T item) { return indexOf(item); }
+
+
+ /// <summary>
+ /// Searches for an item in the list going backwords from the end.
+ /// </summary>
+ /// <param name="item">Item to search for.</param>
+ /// <returns>Index of of item from the end.</returns>
+ [Tested]
+ public int LastIndexOf(T item) { return indexOf(item); }
+
+
+ /// <summary>
+ /// Remove the item at a specific position of the list.
+ /// <exception cref="IndexOutOfRangeException"/> if i is negative or
+ /// &gt;= the size of the collection.
+ /// </summary>
+ /// <param name="i">The index of the item to remove.</param>
+ /// <returns>The removed item.</returns>
+ [Tested]
+ public T RemoveAt(int i)
+ {
+ if (i < 0 || i >= size)
+ throw new IndexOutOfRangeException("Index out of range for sequenced collectionvalue");
+
+ updatecheck();
+
+ T retval = array[i];
+
+ size--;
+ Array.Copy(array, i + 1, array, i, size - i);
+ array[size] = default(T);
+ return retval;
+ }
+
+ /// <summary>
+ /// Remove all items in an index interval.
+ /// <exception cref="IndexOutOfRangeException"/>???.
+ /// </summary>
+ /// <param name="start">The index of the first item to remove.</param>
+ /// <param name="count">The number of items to remove.</param>
+ [Tested]
+ public void RemoveInterval(int start, int count)
+ {
+ updatecheck();
+ checkRange(start, count);
+ Array.Copy(array, start + count, array, start, size - start - count);
+ size -= count;
+ Array.Clear(array, size, count);
+ }
+
+ #endregion
+
+ #region IDirectedEnumerable<T> Members
+
+ /// <summary>
+ /// Create a collection containing the same items as this collection, but
+ /// whose enumerator will enumerate the items backwards. The new collection
+ /// will become invalid if the original is modified. Method typicaly used as in
+ /// <code>foreach (T x in coll.Backwards()) {...}</code>
+ /// </summary>
+ /// <returns>The backwards collection.</returns>
+ [Tested]
+ IDirectedEnumerable<T> IDirectedEnumerable<T>.Backwards()
+ { return Backwards(); }
+
+ #endregion
+
+ #region ICloneable Members
+
+ /// <summary>
+ /// Make a shallow copy of this SortedArray.
+ /// </summary>
+ /// <returns></returns>
+ public virtual object Clone()
+ {
+ SortedArray<T> clone = new SortedArray<T>(size, comparer, itemequalityComparer);
+ clone.AddSorted(this);
+ return clone;
+ }
+
+ #endregion
+
+ }
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/C5/hashing/HashBag.cs b/mcs/class/Mono.C5/C5/hashing/HashBag.cs
new file mode 100644
index 00000000000..e8ad80a137a
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/hashing/HashBag.cs
@@ -0,0 +1,678 @@
+/*
+ Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+using System;
+using System.Diagnostics;
+using SCG = System.Collections.Generic;
+
+namespace C5
+{
+ /// <summary>
+ /// A bag collection based on a hash table of (item,count) pairs.
+ /// </summary>
+ [Serializable]
+ public class HashBag<T> : CollectionBase<T>, ICollection<T>
+ {
+ #region Fields
+ HashSet<KeyValuePair<T, int>> dict;
+ #endregion
+
+ #region Events
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public override EventTypeEnum ListenableEvents { get { return EventTypeEnum.Basic; } }
+
+ #endregion
+
+ #region Constructors
+ /// <summary>
+ /// Create a hash bag with the deafult item equalityComparer.
+ /// </summary>
+ public HashBag() : this(EqualityComparer<T>.Default) { }
+
+ /// <summary>
+ /// Create a hash bag with an external item equalityComparer.
+ /// </summary>
+ /// <param name="itemequalityComparer">The external item equalityComparer.</param>
+ public HashBag(SCG.IEqualityComparer<T> itemequalityComparer)
+ : base(itemequalityComparer)
+ {
+ dict = new HashSet<KeyValuePair<T, int>>(new KeyValuePairEqualityComparer<T, int>(itemequalityComparer));
+ }
+
+ /// <summary>
+ /// Create a hash bag with external item equalityComparer, prescribed initial table size and default fill threshold (66%)
+ /// </summary>
+ /// <param name="capacity">Initial table size (rounded to power of 2, at least 16)</param>
+ /// <param name="itemequalityComparer">The external item equalityComparer</param>
+ public HashBag(int capacity, SCG.IEqualityComparer<T> itemequalityComparer)
+ : base(itemequalityComparer)
+ {
+ dict = new HashSet<KeyValuePair<T, int>>(capacity, new KeyValuePairEqualityComparer<T, int>(itemequalityComparer));
+ }
+
+
+ /// <summary>
+ /// Create a hash bag with external item equalityComparer, prescribed initial table size and fill threshold.
+ /// </summary>
+ /// <param name="capacity">Initial table size (rounded to power of 2, at least 16)</param>
+ /// <param name="fill">Fill threshold (valid range 10% to 90%)</param>
+ /// <param name="itemequalityComparer">The external item equalityComparer</param>
+ public HashBag(int capacity, double fill, SCG.IEqualityComparer<T> itemequalityComparer)
+ : base(itemequalityComparer)
+ {
+ dict = new HashSet<KeyValuePair<T, int>>(capacity, fill, new KeyValuePairEqualityComparer<T, int>(itemequalityComparer));
+ }
+
+ #endregion
+
+ #region IEditableCollection<T> Members
+
+ /// <summary>
+ /// The complexity of the Contains operation
+ /// </summary>
+ /// <value>Always returns Speed.Constant</value>
+ [Tested]
+ public virtual Speed ContainsSpeed { [Tested]get { return Speed.Constant; } }
+
+ /// <summary>
+ /// Check if an item is in the bag
+ /// </summary>
+ /// <param name="item">The item to look for</param>
+ /// <returns>True if bag contains item</returns>
+ [Tested]
+ public virtual bool Contains(T item)
+ { return dict.Contains(new KeyValuePair<T, int>(item, 0)); }
+
+
+ /// <summary>
+ /// Check if an item (collection equal to a given one) is in the bag and
+ /// if so report the actual item object found.
+ /// </summary>
+ /// <param name="item">On entry, the item to look for.
+ /// On exit the item found, if any</param>
+ /// <returns>True if bag contains item</returns>
+ [Tested]
+ public virtual bool Find(ref T item)
+ {
+ KeyValuePair<T, int> p = new KeyValuePair<T, int>(item, 0);
+
+ if (dict.Find(ref p))
+ {
+ item = p.Key;
+ return true;
+ }
+
+ return false;
+ }
+
+
+ /// <summary>
+ /// Check if an item (collection equal to a given one) is in the bag and
+ /// if so replace the item object in the bag with the supplied one.
+ /// </summary>
+ /// <param name="item">The item object to update with</param>
+ /// <returns>True if item was found (and updated)</returns>
+ [Tested]
+ public virtual bool Update(T item)
+ { T olditem = default(T); return Update(item, out olditem); }
+
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ /// <param name="olditem"></param>
+ /// <returns></returns>
+ public virtual bool Update(T item, out T olditem)
+ {
+ KeyValuePair<T, int> p = new KeyValuePair<T, int>(item, 0);
+
+ updatecheck();
+
+ //Note: we cannot just do dict.Update: we have to lookup the count before we
+ //know what to update with. There is of course a way around if we use the
+ //implementation of hashset -which we do not want to do.
+ //The hashbag is moreover mainly a proof of concept
+ if (dict.Find(ref p))
+ {
+ olditem = p.Key;
+ p.Key = item;
+ dict.Update(p);
+ if (ActiveEvents != 0)
+ raiseForUpdate(item, olditem, p.Value);
+ return true;
+ }
+
+ olditem = default(T);
+ return false;
+ }
+
+
+ /// <summary>
+ /// Check if an item (collection equal to a given one) is in the bag.
+ /// If found, report the actual item object in the bag,
+ /// else add the supplied one.
+ /// </summary>
+ /// <param name="item">On entry, the item to look for or add.
+ /// On exit the actual object found, if any.</param>
+ /// <returns>True if item was found</returns>
+ [Tested]
+ public virtual bool FindOrAdd(ref T item)
+ {
+ updatecheck();
+ if (Find(ref item))
+ return true;
+
+ Add(item);
+ return false;
+ }
+
+
+ /// <summary>
+ /// Check if an item (collection equal to a supplied one) is in the bag and
+ /// if so replace the item object in the set with the supplied one; else
+ /// add the supplied one.
+ /// </summary>
+ /// <param name="item">The item to look for and update or add</param>
+ /// <returns>True if item was updated</returns>
+ [Tested]
+ public virtual bool UpdateOrAdd(T item)
+ {
+ updatecheck();
+ if (Update(item))
+ return true;
+
+ Add(item);
+ return false;
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ /// <param name="olditem"></param>
+ /// <returns></returns>
+ public virtual bool UpdateOrAdd(T item, out T olditem)
+ {
+ updatecheck();
+ if (Update(item, out olditem))
+ return true;
+
+ Add(item);
+ return false;
+ }
+
+ /// <summary>
+ /// Remove one copy af an item from the bag
+ /// </summary>
+ /// <param name="item">The item to remove</param>
+ /// <returns>True if item was (found and) removed </returns>
+ [Tested]
+ public virtual bool Remove(T item)
+ {
+ KeyValuePair<T, int> p = new KeyValuePair<T, int>(item, 0);
+
+ updatecheck();
+ if (dict.Find(ref p))
+ {
+ size--;
+ if (p.Value == 1)
+ dict.Remove(p);
+ else
+ {
+ p.Value--;
+ dict.Update(p);
+ }
+ if (ActiveEvents != 0)
+ raiseForRemove(p.Key);
+ return true;
+ }
+
+ return false;
+ }
+
+
+ /// <summary>
+ /// Remove one copy of an item from the bag, reporting the actual matching item object.
+ /// </summary>
+ /// <param name="item">The value to remove.</param>
+ /// <param name="removeditem">The removed value.</param>
+ /// <returns>True if item was found.</returns>
+ [Tested]
+ public virtual bool Remove(T item, out T removeditem)
+ {
+ updatecheck();
+ KeyValuePair<T, int> p = new KeyValuePair<T, int>(item, 0);
+ if (dict.Find(ref p))
+ {
+ removeditem = p.Key;
+ size--;
+ if (p.Value == 1)
+ dict.Remove(p);
+ else
+ {
+ p.Value--;
+ dict.Update(p);
+ }
+ if (ActiveEvents != 0)
+ raiseForRemove(removeditem);
+
+ return true;
+ }
+
+ removeditem = default(T);
+ return false;
+ }
+
+ /// <summary>
+ /// Remove all items in a supplied collection from this bag, counting multiplicities.
+ /// </summary>
+ /// <typeparam name="U"></typeparam>
+ /// <param name="items">The items to remove.</param>
+ [Tested]
+ public virtual void RemoveAll<U>(SCG.IEnumerable<U> items) where U : T
+ {
+#warning Improve if items is a counting bag
+ updatecheck();
+ bool mustRaise = (ActiveEvents & (EventTypeEnum.Changed | EventTypeEnum.Removed)) != 0;
+ RaiseForRemoveAllHandler raiseHandler = mustRaise ? new RaiseForRemoveAllHandler(this) : null;
+ foreach (U item in items)
+ {
+ KeyValuePair<T, int> p = new KeyValuePair<T, int>(item, 0);
+ if (dict.Find(ref p))
+ {
+ size--;
+ if (p.Value == 1)
+ dict.Remove(p);
+ else
+ {
+ p.Value--;
+ dict.Update(p);
+ }
+ if (mustRaise)
+ raiseHandler.Remove(p.Key);
+ }
+ }
+ if (mustRaise)
+ raiseHandler.Raise();
+ }
+
+ /// <summary>
+ /// Remove all items from the bag, resetting internal table to initial size.
+ /// </summary>
+ [Tested]
+ public virtual void Clear()
+ {
+ updatecheck();
+ if (size == 0)
+ return;
+ dict.Clear();
+ int oldsize = size;
+ size = 0;
+ if ((ActiveEvents & EventTypeEnum.Cleared) != 0)
+ raiseCollectionCleared(true, oldsize);
+ if ((ActiveEvents & EventTypeEnum.Changed) != 0)
+ raiseCollectionChanged();
+ }
+
+
+ /// <summary>
+ /// Remove all items *not* in a supplied collection from this bag,
+ /// counting multiplicities.
+ /// </summary>
+ /// <typeparam name="U"></typeparam>
+ /// <param name="items">The items to retain</param>
+ [Tested]
+ public virtual void RetainAll<U>(SCG.IEnumerable<U> items) where U : T
+ {
+ updatecheck();
+
+ HashBag<T> res = new HashBag<T>(itemequalityComparer);
+
+ foreach (U item in items)
+ {
+ KeyValuePair<T, int> p = new KeyValuePair<T, int>(item);
+ if (dict.Find(ref p))
+ {
+ KeyValuePair<T, int> q = p;
+ if (res.dict.Find(ref q))
+ {
+ if (q.Value < p.Value)
+ {
+ q.Value++;
+ res.dict.Update(q);
+ res.size++;
+ }
+ }
+ else
+ {
+ q.Value = 1;
+ res.dict.Add(q);
+ res.size++;
+ }
+ }
+ }
+
+ if (size == res.size)
+ return;
+
+ CircularQueue<T> wasRemoved = null;
+ if ((ActiveEvents & EventTypeEnum.Removed) != 0)
+ {
+ wasRemoved = new CircularQueue<T>();
+ foreach (KeyValuePair<T, int> p in dict)
+ {
+ int removed = p.Value - res.ContainsCount(p.Key);
+ if (removed > 0)
+#warning We could send bag events here easily using a CircularQueue of (should?)
+ for (int i = 0; i < removed; i++)
+ wasRemoved.Enqueue(p.Key);
+ }
+ }
+ dict = res.dict;
+ size = res.size;
+
+ if ((ActiveEvents & EventTypeEnum.Removed) != 0)
+ raiseForRemoveAll(wasRemoved);
+ else if ((ActiveEvents & EventTypeEnum.Changed) != 0)
+ raiseCollectionChanged();
+ }
+
+ /// <summary>
+ /// Check if all items in a supplied collection is in this bag
+ /// (counting multiplicities).
+ /// </summary>
+ /// <param name="items">The items to look for.</param>
+ /// <typeparam name="U"></typeparam>
+ /// <returns>True if all items are found.</returns>
+ [Tested]
+ public virtual bool ContainsAll<U>(SCG.IEnumerable<U> items) where U : T
+ {
+ HashBag<T> res = new HashBag<T>(itemequalityComparer);
+
+ foreach (T item in items)
+ if (res.ContainsCount(item) < ContainsCount(item))
+ res.Add(item);
+ else
+ return false;
+
+ return true;
+ }
+
+
+ /// <summary>
+ /// Create an array containing all items in this bag (in enumeration order).
+ /// </summary>
+ /// <returns>The array</returns>
+ [Tested]
+ public override T[] ToArray()
+ {
+ T[] res = new T[size];
+ int ind = 0;
+
+ foreach (KeyValuePair<T, int> p in dict)
+ for (int i = 0; i < p.Value; i++)
+ res[ind++] = p.Key;
+
+ return res;
+ }
+
+
+ /// <summary>
+ /// Count the number of times an item is in this set.
+ /// </summary>
+ /// <param name="item">The item to look for.</param>
+ /// <returns>The count</returns>
+ [Tested]
+ public virtual int ContainsCount(T item)
+ {
+ KeyValuePair<T, int> p = new KeyValuePair<T, int>(item, 0);
+
+ if (dict.Find(ref p))
+ return p.Value;
+
+ return 0;
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public virtual ICollectionValue<T> UniqueItems() { return new DropMultiplicity<T>(dict); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public virtual ICollectionValue<KeyValuePair<T, int>> ItemMultiplicities()
+ {
+ return new GuardedCollectionValue<KeyValuePair<T, int>>(dict);
+ }
+
+ /// <summary>
+ /// Remove all copies of item from this set.
+ /// </summary>
+ /// <param name="item">The item to remove</param>
+ [Tested]
+ public virtual void RemoveAllCopies(T item)
+ {
+ updatecheck();
+
+ KeyValuePair<T, int> p = new KeyValuePair<T, int>(item, 0);
+
+ if (dict.Find(ref p))
+ {
+ size -= p.Value;
+ dict.Remove(p);
+ if ((ActiveEvents & EventTypeEnum.Removed) != 0)
+ raiseItemsRemoved(p.Key, p.Value);
+ if ((ActiveEvents & EventTypeEnum.Changed) != 0)
+ raiseCollectionChanged();
+ }
+ }
+
+ #endregion
+
+ #region ICollection<T> Members
+
+
+ /// <summary>
+ /// Copy the items of this bag to part of an array.
+ /// <exception cref="ArgumentOutOfRangeException"/> if i is negative.
+ /// <exception cref="ArgumentException"/> if the array does not have room for the items.
+ /// </summary>
+ /// <param name="array">The array to copy to</param>
+ /// <param name="index">The starting index.</param>
+ [Tested]
+ public override void CopyTo(T[] array, int index)
+ {
+ if (index < 0 || index >= array.Length || index + Count > array.Length)
+ throw new ArgumentOutOfRangeException();
+
+ foreach (KeyValuePair<T, int> p in dict)
+ for (int j = 0; j < p.Value; j++)
+ array[index++] = p.Key;
+ }
+
+ #endregion
+
+ #region IExtensible<T> Members
+
+ /// <summary>
+ /// Report if this is a set collection.
+ /// </summary>
+ /// <value>Always true</value>
+ [Tested]
+ public virtual bool AllowsDuplicates { [Tested] get { return true; } }
+
+ /// <summary>
+ /// By convention this is true for any collection with set semantics.
+ /// </summary>
+ /// <value>True if only one representative of a group of equal items
+ /// is kept in the collection together with the total count.</value>
+ public virtual bool DuplicatesByCounting { get { return true; } }
+
+ /// <summary>
+ /// Add an item to this bag.
+ /// </summary>
+ /// <param name="item">The item to add.</param>
+ /// <returns>Always true</returns>
+ [Tested]
+ public virtual bool Add(T item)
+ {
+ updatecheck();
+ add(ref item);
+ if (ActiveEvents != 0)
+ raiseForAdd(item);
+ return true;
+ }
+
+ private void add(ref T item)
+ {
+ KeyValuePair<T, int> p = new KeyValuePair<T, int>(item, 1);
+ if (dict.Find(ref p))
+ {
+ p.Value++;
+ dict.Update(p);
+ item = p.Key;
+ }
+ else
+ dict.Add(p);
+ size++;
+ }
+
+ /// <summary>
+ /// Add the elements from another collection with a more specialized item type
+ /// to this collection.
+ /// </summary>
+ /// <typeparam name="U">The type of items to add</typeparam>
+ /// <param name="items">The items to add</param>
+ public virtual void AddAll<U>(SCG.IEnumerable<U> items) where U : T
+ {
+ updatecheck();
+#warning We could easily raise bag events
+ bool mustRaiseAdded = (ActiveEvents & EventTypeEnum.Added) != 0;
+ CircularQueue<T> wasAdded = mustRaiseAdded ? new CircularQueue<T>() : null;
+ bool wasChanged = false;
+ foreach (T item in items)
+ {
+ T jtem = item;
+ add(ref jtem);
+ wasChanged = true;
+ if (mustRaiseAdded)
+ wasAdded.Enqueue(jtem);
+ }
+ if (!wasChanged)
+ return;
+ if (mustRaiseAdded)
+ foreach (T item in wasAdded)
+ raiseItemsAdded(item, 1);
+ if ((ActiveEvents & EventTypeEnum.Changed) != 0)
+ raiseCollectionChanged();
+ }
+
+ #endregion
+
+ #region IEnumerable<T> Members
+
+
+ /// <summary>
+ /// Choose some item of this collection.
+ /// </summary>
+ /// <exception cref="NoSuchItemException">if collection is empty.</exception>
+ /// <returns></returns>
+ public override T Choose()
+ {
+ return dict.Choose().Key;
+ }
+
+ /// <summary>
+ /// Create an enumerator for this bag.
+ /// </summary>
+ /// <returns>The enumerator</returns>
+ [Tested]
+ public override SCG.IEnumerator<T> GetEnumerator()
+ {
+ int left;
+ int mystamp = stamp;
+
+ foreach (KeyValuePair<T, int> p in dict)
+ {
+ left = p.Value;
+ while (left > 0)
+ {
+ if (mystamp != stamp)
+ throw new CollectionModifiedException();
+
+ left--;
+ yield return p.Key;
+ }
+ }
+ }
+ #endregion
+
+ #region ICloneable Members
+
+ /// <summary>
+ /// Make a shallow copy of this HashBag.
+ /// </summary>
+ /// <returns></returns>
+ public virtual object Clone()
+ {
+ //TODO: make sure this
+ HashBag<T> clone = new HashBag<T>(dict.Count > 0 ? dict.Count : 1, itemequalityComparer);
+ //TODO: make sure this really adds in the counting bag way!
+ clone.AddAll(this);
+ return clone;
+ }
+
+ #endregion
+
+
+ #region Diagnostics
+ /// <summary>
+ /// Test internal structure of data (invariants)
+ /// </summary>
+ /// <returns>True if pass</returns>
+ [Tested]
+ public virtual bool Check()
+ {
+ bool retval = dict.Check();
+ int count = 0;
+
+ foreach (KeyValuePair<T, int> p in dict)
+ count += p.Value;
+
+ if (count != size)
+ {
+ Console.WriteLine("count({0}) != size({1})", count, size);
+ retval = false;
+ }
+
+ return retval;
+ }
+ #endregion
+ }
+}
diff --git a/mcs/class/Mono.C5/C5/hashing/HashDictionary.cs b/mcs/class/Mono.C5/C5/hashing/HashDictionary.cs
new file mode 100644
index 00000000000..84adde2c458
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/hashing/HashDictionary.cs
@@ -0,0 +1,77 @@
+/*
+ Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+using System;
+using System.Diagnostics;
+using SCG = System.Collections.Generic;
+
+namespace C5
+{
+ /// <summary>
+ /// A generic dictionary class based on a hash set class <see cref="T:C5.HashSet`1"/>.
+ /// </summary>
+ [Serializable]
+ public class HashDictionary<K, V> : DictionaryBase<K, V>, IDictionary<K, V>
+ {
+ /// <summary>
+ /// Create a hash dictionary using a default equalityComparer for the keys.
+ /// Initial capacity of internal table will be 16 entries and threshold for
+ /// expansion is 66% fill.
+ /// </summary>
+ public HashDictionary() : this(EqualityComparer<K>.Default) { }
+
+ /// <summary>
+ /// Create a hash dictionary using a custom equalityComparer for the keys.
+ /// Initial capacity of internal table will be 16 entries and threshold for
+ /// expansion is 66% fill.
+ /// </summary>
+ /// <param name="keyequalityComparer">The external key equalityComparer</param>
+ public HashDictionary(SCG.IEqualityComparer<K> keyequalityComparer) : base(keyequalityComparer)
+ {
+ pairs = new HashSet<KeyValuePair<K, V>>(new KeyValuePairEqualityComparer<K, V>(keyequalityComparer));
+ }
+
+ /// <summary>
+ /// Create a hash dictionary using a custom equalityComparer and prescribing the
+ /// initial size of the dictionary and a non-default threshold for internal table expansion.
+ /// </summary>
+ /// <param name="capacity">The initial capacity. Will be rounded upwards to nearest
+ /// power of 2, at least 16.</param>
+ /// <param name="fill">The expansion threshold. Must be between 10% and 90%.</param>
+ /// <param name="keyequalityComparer">The external key equalityComparer</param>
+ public HashDictionary(int capacity, double fill, SCG.IEqualityComparer<K> keyequalityComparer): base(keyequalityComparer)
+ {
+ pairs = new HashSet<KeyValuePair<K, V>>(capacity, fill, new KeyValuePairEqualityComparer<K, V>(keyequalityComparer));
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public override object Clone()
+ {
+ HashDictionary<K, V> clone = new HashDictionary<K, V>(EqualityComparer);
+ clone.pairs.AddAll(pairs);
+ return clone;
+ }
+
+ }
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/C5/hashing/HashTable.cs b/mcs/class/Mono.C5/C5/hashing/HashTable.cs
new file mode 100644
index 00000000000..0db8f66f6af
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/hashing/HashTable.cs
@@ -0,0 +1,1600 @@
+/*
+ Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+#define LINEARPROBINGnot
+#define REFBUCKET
+#define SHRINKnot
+#define INTERHASHINGnot
+#define RANDOMINTERHASHING
+
+using System;
+using System.Diagnostics;
+using SCG = System.Collections.Generic;
+
+namespace C5
+{
+ /// <summary>
+ /// A set collection class based on linear hashing
+ /// </summary>
+ [Serializable]
+ public class HashSet<T> : CollectionBase<T>, ICollection<T>
+ {
+ #region Feature
+ /// <summary>
+ /// Enum class to assist printing of compilation alternatives.
+ /// </summary>
+ [Flags]
+ public enum Feature : short
+ {
+ /// <summary>
+ /// Nothing
+ /// </summary>
+ Dummy = 0,
+ /// <summary>
+ /// Buckets are of reference type
+ /// </summary>
+ RefTypeBucket = 1,
+ /// <summary>
+ /// Primary buckets are of value type
+ /// </summary>
+ ValueTypeBucket = 2,
+ /// <summary>
+ /// Using linear probing to resolve index clashes
+ /// </summary>
+ LinearProbing = 4,
+ /// <summary>
+ /// Shrink table when very sparsely filled
+ /// </summary>
+ ShrinkTable = 8,
+ /// <summary>
+ /// Use chaining to resolve index clashes
+ /// </summary>
+ Chaining = 16,
+ /// <summary>
+ /// Use hash function on item hash code
+ /// </summary>
+ InterHashing = 32,
+ /// <summary>
+ /// Use a universal family of hash functions on item hash code
+ /// </summary>
+ RandomInterHashing = 64
+ }
+
+
+
+ static Feature features = Feature.Dummy
+#if REFBUCKET
+ | Feature.RefTypeBucket
+#else
+ | Feature.ValueTypeBucket
+#endif
+#if SHRINK
+ | Feature.ShrinkTable
+#endif
+#if LINEARPROBING
+ | Feature.LinearProbing
+#else
+ | Feature.Chaining
+#endif
+#if INTERHASHING
+ | Feature.InterHashing
+#elif RANDOMINTERHASHING
+ | Feature.RandomInterHashing
+#endif
+;
+
+
+ /// <summary>
+ /// Show which implementation features was chosen at compilation time
+ /// </summary>
+ public static Feature Features { get { return features; } }
+
+ #endregion
+
+ #region Fields
+
+ int indexmask, bits, bitsc, origbits, lastchosen; //bitsc==32-bits; indexmask==(1<<bits)-1;
+
+ Bucket[] table;
+
+#if !REFBUCKET
+ bool defaultvalid = false;
+
+ T defaultitem;
+#endif
+ double fillfactor = 0.66;
+
+ int resizethreshhold;
+
+#if RANDOMINTERHASHING
+#if DEBUG
+ const uint randomhashfactor = 1529784659;
+#else
+ uint randomhashfactor = (2 * (uint)(new Random()).Next() + 1) * 1529784659;
+#endif
+#endif
+
+ #endregion
+
+ #region Events
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public override EventTypeEnum ListenableEvents { get { return EventTypeEnum.Basic; } }
+
+ #endregion
+
+ #region Bucket nested class(es)
+#if REFBUCKET
+ [Serializable]
+ class Bucket
+ {
+ internal T item;
+
+ internal int hashval; //Cache!
+
+#if LINEARPROBING
+ internal Bucket(T item, int hashval)
+ {
+ this.item = item;
+ this.hashval = hashval;
+ }
+#else
+ internal Bucket overflow;
+
+ internal Bucket(T item, int hashval, Bucket overflow)
+ {
+ this.item = item;
+ this.hashval = hashval;
+ this.overflow = overflow;
+ }
+#endif
+ }
+#else
+ struct Bucket
+ {
+ internal T item;
+
+ internal int hashval; //Cache!
+
+#if LINEARPROBING
+ internal Bucket(T item, int hashval)
+ {
+ this.item = item;
+ this.hashval = hashval;
+ }
+#else
+ internal OverflowBucket overflow;
+
+
+ internal Bucket(T item, int hashval)
+ {
+ this.item = item;
+ this.hashval = hashval;
+ this.overflow = default(OverflowBucket);
+ }
+#endif
+ }
+
+
+#if !LINEARPROBING
+ class OverflowBucket
+ {
+ internal T item;
+
+ internal int hashval; //Cache!
+
+ internal OverflowBucket overflow;
+
+
+ internal OverflowBucket(T item, int hashval, OverflowBucket overflow)
+ {
+ this.item = item;
+ this.hashval = hashval;
+ this.overflow = overflow;
+ }
+ }
+#endif
+#endif
+
+ #endregion
+
+ #region Basic Util
+
+ bool equals(T i1, T i2) { return itemequalityComparer.Equals(i1, i2); }
+
+#if !REFBUCKET
+ bool isnull(T item) { return itemequalityComparer.Equals(item, default(T)); }
+#endif
+
+ int gethashcode(T item) { return itemequalityComparer.GetHashCode(item); }
+
+
+ int hv2i(int hashval)
+ {
+#if INTERHASHING
+ //Note: *inverse mod 2^32 is -1503427877
+ return (int)(((uint)hashval * 1529784659) >>bitsc);
+#elif RANDOMINTERHASHING
+ return (int)(((uint)hashval * randomhashfactor) >> bitsc);
+#else
+ return indexmask & hashval;
+#endif
+ }
+
+
+ void expand()
+ {
+ //Console.WriteLine(String.Format("Expand to {0} bits", bits+1));
+ resize(bits + 1);
+ }
+
+
+ void shrink()
+ {
+ if (bits > 3)
+ {
+ //Console.WriteLine(String.Format("Shrink to {0} bits", bits - 1));
+ resize(bits - 1);
+ }
+ }
+
+
+ void resize(int bits)
+ {
+ //Console.WriteLine(String.Format("Resize to {0} bits", bits));
+ this.bits = bits;
+ bitsc = 32 - bits;
+ indexmask = (1 << bits) - 1;
+
+ Bucket[] newtable = new Bucket[indexmask + 1];
+
+ for (int i = 0, s = table.Length; i < s; i++)
+ {
+ Bucket b = table[i];
+
+#if LINEARPROBING
+#if REFBUCKET
+ if (b != null)
+ {
+ int j = hv2i(b.hashval);
+
+ while (newtable[j] != null) { j = indexmask & (j + 1); }
+
+ newtable[j] = b;
+ }
+#else
+ if (!isnull(b.item))
+ {
+ int j = hv2i(b.hashval);
+
+ while (!isnull(newtable[j].item)) { j = indexmask & (j + 1); }
+
+ newtable[j] = b;
+ }
+#endif
+#else
+#if REFBUCKET
+ while (b != null)
+ {
+ int j = hv2i(b.hashval);
+
+ newtable[j] = new Bucket(b.item, b.hashval, newtable[j]);
+ b = b.overflow;
+ }
+#else
+ if (!isnull(b.item))
+ {
+ insert(b.item, b.hashval, newtable);
+
+ OverflowBucket ob = b.overflow;
+
+ while (ob != null)
+ {
+ insert(ob.item, ob.hashval, newtable);
+ ob = ob.overflow;
+ }
+ }
+#endif
+#endif
+ }
+
+ table = newtable;
+ resizethreshhold = (int)(table.Length * fillfactor);
+ //Console.WriteLine(String.Format("Resize to {0} bits done", bits));
+ }
+
+#if REFBUCKET
+#else
+#if LINEARPROBING
+#else
+ //Only for resize!!!
+ private void insert(T item, int hashval, Bucket[] t)
+ {
+ int i = hv2i(hashval);
+ Bucket b = t[i];
+
+ if (!isnull(b.item))
+ {
+ t[i].overflow = new OverflowBucket(item, hashval, b.overflow);
+ }
+ else
+ t[i] = new Bucket(item, hashval);
+ }
+#endif
+#endif
+
+ /// <summary>
+ /// Search for an item equal (according to itemequalityComparer) to the supplied item.
+ /// </summary>
+ /// <param name="item"></param>
+ /// <param name="add">If true, add item to table if not found.</param>
+ /// <param name="update">If true, update table entry if item found.</param>
+ /// <param name="raise">If true raise events</param>
+ /// <returns>True if found</returns>
+ private bool searchoradd(ref T item, bool add, bool update, bool raise)
+ {
+
+#if LINEARPROBING
+#if REFBUCKET
+ int hashval = gethashcode(item);
+ int i = hv2i(hashval);
+ Bucket b = table[i];
+
+ while (b != null)
+ {
+ T olditem = b.item;
+ if (equals(olditem, item))
+ {
+ if (update)
+ b.item = item;
+ else
+ item = olditem;
+
+ if (raise && update)
+ raiseForUpdate(item, olditem);
+ return true;
+ }
+
+ b = table[i = indexmask & (i + 1)];
+ }
+
+ if (!add) goto notfound;
+
+ table[i] = new Bucket(item, hashval);
+
+#else
+ if (isnull(item))
+ {
+ if (defaultvalid)
+ {
+ T olditem = defaultitem;
+ if (update)
+ defaultitem = item;
+ else
+ item = defaultitem;
+
+ if (raise && update)
+ raiseForUpdate(item, olditem);
+ return true;
+ }
+
+ if (!add) goto notfound;
+
+ defaultvalid = true;
+ defaultitem = item;
+ }
+ else
+ {
+ int hashval = gethashcode(item);
+ int i = hv2i(hashval);
+ T t = table[i].item;
+
+ while (!isnull(t))
+ {
+ if (equals(t, item))
+ {
+ if (update)
+ table[i].item = item;
+ else
+ item = t;
+
+ if (raise && update)
+ raiseForUpdate(item, t);
+ return true;
+ }
+
+ t = table[i = indexmask & (i + 1)].item;
+ }
+
+ if (!add) goto notfound;
+
+ table[i] = new Bucket(item, hashval);
+ }
+#endif
+#else
+#if REFBUCKET
+ int hashval = gethashcode(item);
+ int i = hv2i(hashval);
+ Bucket b = table[i], bold = null;
+
+ if (b != null)
+ {
+ while (b != null)
+ {
+ T olditem = b.item;
+ if (equals(olditem, item))
+ {
+ if (update)
+ {
+ b.item = item;
+ }
+ item = b.item;
+
+ if (raise && update)
+ raiseForUpdate(item, olditem);
+ return true;
+ }
+
+ bold = b;
+ b = b.overflow;
+ }
+
+ if (!add) goto notfound;
+
+ bold.overflow = new Bucket(item, hashval, null);
+ }
+ else
+ {
+ if (!add) goto notfound;
+
+ table[i] = new Bucket(item, hashval, null);
+ }
+#else
+ if (isnull(item))
+ {
+ if (defaultvalid)
+ {
+ T olditem = defaultitem;
+ if (update)
+ defaultitem = item;
+ else
+ item = defaultitem;
+
+ if (raise && update)
+ raiseForUpdate(item, olditem);
+ return true;
+ }
+
+ if (!add) goto notfound;
+
+ defaultvalid = true;
+ defaultitem = item;
+ }
+ else
+ {
+ int hashval = gethashcode(item);
+ int i = hv2i(hashval);
+ Bucket b = table[i];
+
+ if (!isnull(b.item))
+ {
+ if (equals(b.item, item))
+ {
+ if (update)
+ table[i].item = item;
+ else
+ item = b.item;
+
+ if (raise && update)
+ raiseForUpdate(item, b.item);
+ return true;
+ }
+
+ OverflowBucket ob = table[i].overflow;
+
+ if (ob == null)
+ {
+ if (!add) goto notfound;
+
+ table[i].overflow = new OverflowBucket(item, hashval, null);
+ }
+ else
+ {
+ T olditem = ob.item;
+ while (ob.overflow != null)
+ {
+ if (equals(item, olditem))
+ {
+ if (update)
+ ob.item = item;
+ else
+ item = olditem;
+
+ if (raise && update)
+ raiseForUpdate(item, olditem);
+ return true;
+ }
+
+ ob = ob.overflow;
+ olditem = ob.item;
+ }
+
+ if (equals(item, olditem))
+ {
+ if (update)
+ ob.item = item;
+ else
+ item = olditem;
+
+ if (raise && update)
+ raiseForUpdate(item, olditem);
+ return true;
+ }
+
+ if (!add) goto notfound;
+
+ ob.overflow = new OverflowBucket(item, hashval, null);
+ }
+ }
+ else
+ {
+ if (!add) goto notfound;
+
+ table[i] = new Bucket(item, hashval);
+ }
+ }
+#endif
+#endif
+ size++;
+ if (size > resizethreshhold)
+ expand();
+ notfound:
+ if (raise && add)
+ raiseForAdd(item);
+ return false;
+ }
+
+
+ private bool remove(ref T item)
+ {
+
+ if (size == 0)
+ return false;
+#if LINEARPROBING
+#if REFBUCKET
+ int hashval = gethashcode(item);
+ int index = hv2i(hashval);
+ Bucket b = table[index];
+
+ while (b != null)
+ {
+ if (equals(item, b.item))
+ {
+ //ref
+ item = table[index].item;
+ table[index] = null;
+
+ //Algorithm R
+ int j = (index + 1) & indexmask;
+
+ b = table[j];
+ while (b != null)
+ {
+ int k = hv2i(b.hashval);
+
+ if ((k <= index && index < j) || (index < j && j < k) || (j < k && k <= index))
+ //if (index > j ? (j < k && k <= index): (k <= index || j < k) )
+ {
+ table[index] = b;
+ table[j] = null;
+ index = j;
+ }
+
+ j = (j + 1) & indexmask;
+ b = table[j];
+ }
+
+ goto found;
+ }
+
+ b = table[index = indexmask & (index + 1)];
+ }
+ return false;
+#else
+ if (isnull(item))
+ {
+ if (!defaultvalid)
+ return false;
+
+ //ref
+ item = defaultitem;
+ defaultvalid = false;
+ defaultitem = default(T); //No spaceleaks!
+ }
+ else
+ {
+ int hashval = gethashcode(item);
+ int index = hv2i(hashval);
+ T t = table[index].item;
+
+ while (!isnull(t))
+ {
+ if (equals(item, t))
+ {
+ //ref
+ item = table[index].item;
+ table[index].item = default(T);
+
+ //algorithm R
+ int j = (index + 1) & indexmask;
+ Bucket b = table[j];
+
+ while (!isnull(b.item))
+ {
+ int k = hv2i(b.hashval);
+
+ if ((k <= index && index < j) || (index < j && j < k) || (j < k && k <= index))
+ {
+ table[index] = b;
+ table[j].item = default(T);
+ index = j;
+ }
+
+ j = (j + 1) & indexmask;
+ b = table[j];
+ }
+
+ goto found;
+ }
+
+ t = table[index = indexmask & (index + 1)].item;
+ }
+
+ return false;
+ }
+#endif
+ found:
+#else
+#if REFBUCKET
+ int hashval = gethashcode(item);
+ int index = hv2i(hashval);
+ Bucket b = table[index], bold;
+
+ if (b == null)
+ return false;
+
+ if (equals(item, b.item))
+ {
+ //ref
+ item = b.item;
+ table[index] = b.overflow;
+ }
+ else
+ {
+ bold = b;
+ b = b.overflow;
+ while (b != null && !equals(item, b.item))
+ {
+ bold = b;
+ b = b.overflow;
+ }
+
+ if (b == null)
+ return false;
+
+ //ref
+ item = b.item;
+ bold.overflow = b.overflow;
+ }
+
+#else
+ if (isnull(item))
+ {
+ if (!defaultvalid)
+ return false;
+
+ //ref
+ item = defaultitem;
+ defaultvalid = false;
+ defaultitem = default(T); //No spaceleaks!
+ }
+ else
+ {
+ int hashval = gethashcode(item);
+ int index = hv2i(hashval);
+ Bucket b = table[index];
+ OverflowBucket ob = b.overflow;
+
+ if (equals(item, b.item))
+ {
+ //ref
+ item = b.item;
+ if (ob == null)
+ {
+ table[index] = new Bucket();
+ }
+ else
+ {
+ b = new Bucket(ob.item, ob.hashval);
+ b.overflow = ob.overflow;
+ table[index] = b;
+ }
+ }
+ else
+ {
+ if (ob == null)
+ return false;
+
+ if (equals(item, ob.item))
+ {
+ //ref
+ item=ob.item;
+ table[index].overflow = ob.overflow;
+ }
+ else
+ {
+ while (ob.overflow != null)
+ if (equals(item, ob.overflow.item))
+ {
+ //ref
+ item = ob.overflow.item;
+ break;
+ }
+ else
+ ob = ob.overflow;
+
+ if (ob.overflow == null)
+ return false;
+
+ ob.overflow = ob.overflow.overflow;
+ }
+ }
+ }
+#endif
+#endif
+ size--;
+
+ return true;
+ }
+
+
+ private void clear()
+ {
+ bits = origbits;
+ bitsc = 32 - bits;
+ indexmask = (1 << bits) - 1;
+ size = 0;
+ table = new Bucket[indexmask + 1];
+ resizethreshhold = (int)(table.Length * fillfactor);
+#if !REFBUCKET
+ defaultitem = default(T);
+ defaultvalid = false;
+#endif
+ }
+
+ #endregion
+
+ #region Constructors
+ /// <summary>
+ /// Create a hash set with natural item equalityComparer and default fill threshold (66%)
+ /// and initial table size (16).
+ /// </summary>
+ public HashSet()
+ : this(EqualityComparer<T>.Default) { }
+
+
+ /// <summary>
+ /// Create a hash set with external item equalityComparer and default fill threshold (66%)
+ /// and initial table size (16).
+ /// </summary>
+ /// <param name="itemequalityComparer">The external item equalityComparer</param>
+ public HashSet(SCG.IEqualityComparer<T> itemequalityComparer)
+ : this(16, itemequalityComparer) { }
+
+
+ /// <summary>
+ /// Create a hash set with external item equalityComparer and default fill threshold (66%)
+ /// </summary>
+ /// <param name="capacity">Initial table size (rounded to power of 2, at least 16)</param>
+ /// <param name="itemequalityComparer">The external item equalityComparer</param>
+ public HashSet(int capacity, SCG.IEqualityComparer<T> itemequalityComparer)
+ : this(capacity, 0.66, itemequalityComparer) { }
+
+
+ /// <summary>
+ /// Create a hash set with external item equalityComparer.
+ /// </summary>
+ /// <param name="capacity">Initial table size (rounded to power of 2, at least 16)</param>
+ /// <param name="fill">Fill threshold (in range 10% to 90%)</param>
+ /// <param name="itemequalityComparer">The external item equalityComparer</param>
+ public HashSet(int capacity, double fill, SCG.IEqualityComparer<T> itemequalityComparer) : base(itemequalityComparer)
+ {
+ if (fill < 0.1 || fill > 0.9)
+ throw new ArgumentException("Fill outside valid range [0.1, 0.9]");
+ if (capacity <= 0)
+ throw new ArgumentException("Capacity must be non-negative");
+ //this.itemequalityComparer = itemequalityComparer;
+ origbits = 4;
+ while (capacity - 1 >> origbits > 0) origbits++;
+ clear();
+ }
+
+
+
+ #endregion
+
+ #region IEditableCollection<T> Members
+
+ /// <summary>
+ /// The complexity of the Contains operation
+ /// </summary>
+ /// <value>Always returns Speed.Constant</value>
+ [Tested]
+ public virtual Speed ContainsSpeed { [Tested]get { return Speed.Constant; } }
+
+ /// <summary>
+ /// Check if an item is in the set
+ /// </summary>
+ /// <param name="item">The item to look for</param>
+ /// <returns>True if set contains item</returns>
+ [Tested]
+ public virtual bool Contains(T item) { return searchoradd(ref item, false, false, false); }
+
+
+ /// <summary>
+ /// Check if an item (collection equal to a given one) is in the set and
+ /// if so report the actual item object found.
+ /// </summary>
+ /// <param name="item">On entry, the item to look for.
+ /// On exit the item found, if any</param>
+ /// <returns>True if set contains item</returns>
+ [Tested]
+ public virtual bool Find(ref T item) { return searchoradd(ref item, false, false, false); }
+
+
+ /// <summary>
+ /// Check if an item (collection equal to a given one) is in the set and
+ /// if so replace the item object in the set with the supplied one.
+ /// </summary>
+ /// <param name="item">The item object to update with</param>
+ /// <returns>True if item was found (and updated)</returns>
+ [Tested]
+ public virtual bool Update(T item)
+ { updatecheck(); return searchoradd(ref item, false, true, true); }
+
+ /// <summary>
+ /// Check if an item (collection equal to a given one) is in the set and
+ /// if so replace the item object in the set with the supplied one.
+ /// </summary>
+ /// <param name="item">The item object to update with</param>
+ /// <param name="olditem"></param>
+ /// <returns>True if item was found (and updated)</returns>
+ public virtual bool Update(T item, out T olditem)
+ { updatecheck(); olditem = item; return searchoradd(ref olditem, false, true, true); }
+
+
+ /// <summary>
+ /// Check if an item (collection equal to a given one) is in the set.
+ /// If found, report the actual item object in the set,
+ /// else add the supplied one.
+ /// </summary>
+ /// <param name="item">On entry, the item to look for or add.
+ /// On exit the actual object found, if any.</param>
+ /// <returns>True if item was found</returns>
+ [Tested]
+ public virtual bool FindOrAdd(ref T item)
+ { updatecheck(); return searchoradd(ref item, true, false, true); }
+
+
+ /// <summary>
+ /// Check if an item (collection equal to a supplied one) is in the set and
+ /// if so replace the item object in the set with the supplied one; else
+ /// add the supplied one.
+ /// </summary>
+ /// <param name="item">The item to look for and update or add</param>
+ /// <returns>True if item was updated</returns>
+ [Tested]
+ public virtual bool UpdateOrAdd(T item)
+ { updatecheck(); return searchoradd(ref item, true, true, true); }
+
+
+ /// <summary>
+ /// Check if an item (collection equal to a supplied one) is in the set and
+ /// if so replace the item object in the set with the supplied one; else
+ /// add the supplied one.
+ /// </summary>
+ /// <param name="item">The item to look for and update or add</param>
+ /// <param name="olditem"></param>
+ /// <returns>True if item was updated</returns>
+ public virtual bool UpdateOrAdd(T item, out T olditem)
+ { updatecheck(); olditem = item; return searchoradd(ref olditem, true, true, true); }
+
+
+ /// <summary>
+ /// Remove an item from the set
+ /// </summary>
+ /// <param name="item">The item to remove</param>
+ /// <returns>True if item was (found and) removed </returns>
+ [Tested]
+ public virtual bool Remove(T item)
+ {
+ updatecheck();
+ if (remove(ref item))
+ {
+#if SHRINK
+ if (size<resizethreshhold/2 && resizethreshhold>8)
+ shrink();
+#endif
+ raiseForRemove(item);
+ return true;
+ }
+ else
+ return false;
+ }
+
+
+ /// <summary>
+ /// Remove an item from the set, reporting the actual matching item object.
+ /// </summary>
+ /// <param name="item">The value to remove.</param>
+ /// <param name="removeditem">The removed value.</param>
+ /// <returns>True if item was found.</returns>
+ [Tested]
+ public virtual bool Remove(T item, out T removeditem)
+ {
+ updatecheck();
+ removeditem = item;
+ if (remove(ref removeditem))
+ {
+#if SHRINK
+ if (size<resizethreshhold/2 && resizethreshhold>8)
+ shrink();
+#endif
+ raiseForRemove(removeditem);
+ return true;
+ }
+ else
+ return false;
+ }
+
+
+ /// <summary>
+ /// Remove all items in a supplied collection from this set.
+ /// </summary>
+ /// <typeparam name="U"></typeparam>
+ /// <param name="items">The items to remove.</param>
+ [Tested]
+ public virtual void RemoveAll<U>(SCG.IEnumerable<U> items) where U : T
+ {
+ updatecheck();
+ RaiseForRemoveAllHandler raiseHandler = new RaiseForRemoveAllHandler(this);
+ bool raise = raiseHandler.MustFire;
+ T jtem;
+ foreach (U item in items)
+ { jtem = item; if (remove(ref jtem) && raise) raiseHandler.Remove(jtem); }
+#if SHRINK
+ if (size < resizethreshhold / 2 && resizethreshhold > 16)
+ {
+ int newlength = table.Length;
+
+ while (newlength >= 32 && newlength * fillfactor / 2 > size)
+ newlength /= 2;
+
+ resize(newlength - 1);
+ }
+#endif
+ if (raise) raiseHandler.Raise();
+ }
+
+ /// <summary>
+ /// Remove all items from the set, resetting internal table to initial size.
+ /// </summary>
+ [Tested]
+ public virtual void Clear()
+ {
+ updatecheck();
+ int oldsize = size;
+ clear();
+ if (ActiveEvents != 0 && oldsize > 0)
+ {
+ raiseCollectionCleared(true, oldsize);
+ raiseCollectionChanged();
+ }
+ }
+
+
+ /// <summary>
+ /// Remove all items *not* in a supplied collection from this set.
+ /// </summary>
+ /// <typeparam name="U"></typeparam>
+ /// <param name="items">The items to retain</param>
+ [Tested]
+ public virtual void RetainAll<U>(SCG.IEnumerable<U> items) where U : T
+ {
+ updatecheck();
+
+ HashSet<T> aux = new HashSet<T>(EqualityComparer);
+
+ //This only works for sets:
+ foreach (U item in items)
+ if (Contains(item))
+ {
+ T jtem = item;
+
+ aux.searchoradd(ref jtem, true, false, false);
+ }
+
+ if (size == aux.size)
+ return;
+
+ CircularQueue<T> wasRemoved = null;
+ if ((ActiveEvents & EventTypeEnum.Removed) != 0)
+ {
+ wasRemoved = new CircularQueue<T>();
+ foreach (T item in this)
+ if (!aux.Contains(item))
+ wasRemoved.Enqueue(item);
+ }
+
+ table = aux.table;
+ size = aux.size;
+#if !REFBUCKET
+ defaultvalid = aux.defaultvalid;
+ defaultitem = aux.defaultitem;
+#endif
+ indexmask = aux.indexmask;
+ resizethreshhold = aux.resizethreshhold;
+
+
+ if ((ActiveEvents & EventTypeEnum.Removed) != 0)
+ raiseForRemoveAll(wasRemoved);
+ else if ((ActiveEvents & EventTypeEnum.Changed) != 0)
+ raiseCollectionChanged();
+ }
+
+ /// <summary>
+ /// Check if all items in a supplied collection is in this set
+ /// (ignoring multiplicities).
+ /// </summary>
+ /// <param name="items">The items to look for.</param>
+ /// <typeparam name="U"></typeparam>
+ /// <returns>True if all items are found.</returns>
+ [Tested]
+ public virtual bool ContainsAll<U>(SCG.IEnumerable<U> items) where U : T
+ {
+ foreach (U item in items)
+ if (!Contains(item))
+ return false;
+ return true;
+ }
+
+
+ /// <summary>
+ /// Create an array containing all items in this set (in enumeration order).
+ /// </summary>
+ /// <returns>The array</returns>
+ [Tested]
+ public override T[] ToArray()
+ {
+ T[] res = new T[size];
+ int index = 0;
+
+#if !REFBUCKET
+ if (defaultvalid)
+ res[index++] = defaultitem;
+#endif
+ for (int i = 0; i < table.Length; i++)
+ {
+ Bucket b = table[i];
+#if LINEARPROBING
+#if REFBUCKET
+ if (b != null)
+ res[index++] = b.item;
+#else
+ if (!isnull(b.item))
+ res[index++] = b.item;
+#endif
+#else
+#if REFBUCKET
+ while (b != null)
+ {
+ res[index++] = b.item;
+ b = b.overflow;
+ }
+#else
+ if (!isnull(b.item))
+ {
+ res[index++] = b.item;
+
+ OverflowBucket ob = b.overflow;
+
+ while (ob != null)
+ {
+ res[index++] = ob.item;
+ ob = ob.overflow;
+ }
+ }
+#endif
+#endif
+ }
+
+ Debug.Assert(size == index);
+ return res;
+ }
+
+
+ /// <summary>
+ /// Count the number of times an item is in this set (either 0 or 1).
+ /// </summary>
+ /// <param name="item">The item to look for.</param>
+ /// <returns>1 if item is in set, 0 else</returns>
+ [Tested]
+ public virtual int ContainsCount(T item) { return Contains(item) ? 1 : 0; }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public virtual ICollectionValue<T> UniqueItems() { return this; }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public virtual ICollectionValue<KeyValuePair<T, int>> ItemMultiplicities()
+ {
+ return new MultiplicityOne<T>(this);
+ }
+
+ /// <summary>
+ /// Remove all (at most 1) copies of item from this set.
+ /// </summary>
+ /// <param name="item">The item to remove</param>
+ [Tested]
+ public virtual void RemoveAllCopies(T item) { Remove(item); }
+
+ #endregion
+
+ #region IEnumerable<T> Members
+
+
+ /// <summary>
+ /// Choose some item of this collection.
+ /// </summary>
+ /// <exception cref="NoSuchItemException">if collection is empty.</exception>
+ /// <returns></returns>
+ [Tested]
+ public override T Choose()
+ {
+ int len = table.Length;
+ if (size == 0)
+ throw new NoSuchItemException();
+#if REFBUCKET
+ do { if (++lastchosen >= len) lastchosen = 0; } while (table[lastchosen] == null);
+#else
+ if (defaultvalid) return defaultitem;
+ do { if (++lastchosen >= len) lastchosen = 0; } while (isnull(table[lastchosen].item));
+#endif
+ return table[lastchosen].item;
+ }
+
+ /// <summary>
+ /// Create an enumerator for this set.
+ /// </summary>
+ /// <returns>The enumerator</returns>
+ [Tested]
+ public override SCG.IEnumerator<T> GetEnumerator()
+ {
+ int index = -1;
+ int mystamp = stamp;
+ int len = table.Length;
+
+#if LINEARPROBING
+#if REFBUCKET
+ while (++index < len)
+ {
+ if (mystamp != stamp) throw new CollectionModifiedException();
+
+ if (table[index] != null) yield return table[index].item;
+ }
+#else
+ if (defaultvalid)
+ yield return defaultitem;
+
+ while (++index < len)
+ {
+ if (mystamp != stamp) throw new CollectionModifiedException();
+
+ T item = table[index].item;
+
+ if (!isnull(item)) yield return item;
+ }
+#endif
+#else
+#if REFBUCKET
+ Bucket b = null;
+#else
+ OverflowBucket ob = null;
+
+ if (defaultvalid)
+ yield return defaultitem;
+#endif
+ while (true)
+ {
+ if (mystamp != stamp)
+ throw new CollectionModifiedException();
+
+#if REFBUCKET
+ if (b == null || b.overflow == null)
+ {
+ do
+ {
+ if (++index >= len) yield break;
+ } while (table[index] == null);
+
+ b = table[index];
+ yield return b.item;
+ }
+ else
+ {
+ b = b.overflow;
+ yield return b.item;
+ }
+#else
+ if (ob != null && ob.overflow != null)
+ {
+ ob = ob.overflow;
+ yield return ob.item;
+ }
+ else if (index >= 0 && ob == null && (ob = table[index].overflow) != null)
+ {
+ yield return ob.item;
+ }
+ else
+ {
+ do
+ {
+ if (++index >= len) yield break;
+ } while (isnull(table[index].item));
+
+ yield return table[index].item;
+ ob = null;
+ }
+#endif
+ }
+#endif
+ }
+
+ #endregion
+
+ #region ISink<T> Members
+ /// <summary>
+ /// Report if this is a set collection.
+ /// </summary>
+ /// <value>Always false</value>
+ [Tested]
+ public virtual bool AllowsDuplicates { [Tested]get { return false; } }
+
+ /// <summary>
+ /// By convention this is true for any collection with set semantics.
+ /// </summary>
+ /// <value>True if only one representative of a group of equal items
+ /// is kept in the collection together with the total count.</value>
+ public virtual bool DuplicatesByCounting { get { return true; } }
+
+ /// <summary>
+ /// Add an item to this set.
+ /// </summary>
+ /// <param name="item">The item to add.</param>
+ /// <returns>True if item was added (i.e. not found)</returns>
+ [Tested]
+ public virtual bool Add(T item)
+ {
+ updatecheck();
+ return !searchoradd(ref item, true, false, true);
+ }
+
+ /// <summary>
+ /// Add the elements from another collection with a more specialized item type
+ /// to this collection. Since this
+ /// collection has set semantics, only items not already in the collection
+ /// will be added.
+ /// </summary>
+ /// <typeparam name="U">The type of items to add</typeparam>
+ /// <param name="items">The items to add</param>
+ [Tested]
+ public virtual void AddAll<U>(SCG.IEnumerable<U> items) where U : T
+ {
+ updatecheck();
+ bool wasChanged = false;
+ bool raiseAdded = (ActiveEvents & EventTypeEnum.Added) != 0;
+ CircularQueue<T> wasAdded = raiseAdded ? new CircularQueue<T>() : null;
+ foreach (T item in items)
+ {
+ T jtem = item;
+
+ if (!searchoradd(ref jtem, true, false, false))
+ {
+ wasChanged = true;
+ if (raiseAdded)
+ wasAdded.Enqueue(item);
+ }
+ }
+ //TODO: implement a RaiseForAddAll() method
+ if (raiseAdded & wasChanged)
+ foreach (T item in wasAdded)
+ raiseItemsAdded(item, 1);
+ if (((ActiveEvents & EventTypeEnum.Changed) != 0 && wasChanged))
+ raiseCollectionChanged();
+ }
+
+
+ #endregion
+
+ #region Diagnostics
+
+ /// <summary>
+ /// Test internal structure of data (invariants)
+ /// </summary>
+ /// <returns>True if pass</returns>
+ [Tested]
+ public virtual bool Check()
+ {
+ int count = 0;
+#if LINEARPROBING
+ int lasthole = table.Length - 1;
+
+#if REFBUCKET
+ while (lasthole >= 0 && table[lasthole] != null)
+#else
+ while (lasthole >= 0 && !isnull(table[lasthole].item))
+#endif
+ {
+ lasthole--;
+ count++;
+ }
+
+ if (lasthole < 0)
+ {
+ Console.WriteLine("Table is completely filled!");
+ return false;
+ }
+
+ for (int cellindex = lasthole + 1, s = table.Length; cellindex < s; cellindex++)
+ {
+ Bucket b = table[cellindex];
+ int hashindex = hv2i(b.hashval);
+
+ if (hashindex <= lasthole || hashindex > cellindex)
+ {
+ Console.WriteLine("Bad cell item={0}, hashval={1}, hashindex={2}, cellindex={3}, lasthole={4}", b.item, b.hashval, hashindex, cellindex, lasthole);
+ return false;
+ }
+ }
+
+ int latesthole = -1;
+
+ for (int cellindex = 0; cellindex < lasthole; cellindex++)
+ {
+ Bucket b = table[cellindex];
+
+#if REFBUCKET
+ if (b != null)
+#else
+ if (!isnull(b.item))
+#endif
+ {
+ count++;
+
+ int hashindex = hv2i(b.hashval);
+
+ if (cellindex < hashindex && hashindex <= lasthole)
+ {
+ Console.WriteLine("Bad cell item={0}, hashval={1}, hashindex={2}, cellindex={3}, latesthole={4}", b.item, b.hashval, hashindex, cellindex, latesthole);
+ return false;
+ }
+ }
+ else
+ {
+ latesthole = cellindex;
+ break;
+ }
+ }
+
+ for (int cellindex = latesthole + 1; cellindex < lasthole; cellindex++)
+ {
+ Bucket b = table[cellindex];
+
+#if REFBUCKET
+ if (b != null)
+#else
+ if (!isnull(b.item))
+#endif
+ {
+ count++;
+
+ int hashindex = hv2i(b.hashval);
+
+ if (hashindex <= latesthole || cellindex < hashindex)
+ {
+ Console.WriteLine("Bad cell item={0}, hashval={1}, hashindex={2}, cellindex={3}, latesthole={4}", b.item, b.hashval, hashindex, cellindex, latesthole);
+ return false;
+ }
+ }
+ else
+ {
+ latesthole = cellindex;
+ }
+ }
+
+ return true;
+#else
+ bool retval = true;
+ for (int i = 0, s = table.Length; i < s; i++)
+ {
+ int level = 0;
+ Bucket b = table[i];
+#if REFBUCKET
+ while (b != null)
+ {
+ if (i != hv2i(b.hashval))
+ {
+ Console.WriteLine("Bad cell item={0}, hashval={1}, index={2}, level={3}", b.item, b.hashval, i, level);
+ retval = false;
+ }
+
+ count++;
+ level++;
+ b = b.overflow;
+ }
+#else
+ if (!isnull(b.item))
+ {
+ count++;
+ if (i != hv2i(b.hashval))
+ {
+ Console.WriteLine("Bad cell item={0}, hashval={1}, index={2}, level={3}", b.item, b.hashval, i, level);
+ retval = false;
+ }
+
+ OverflowBucket ob = b.overflow;
+
+ while (ob != null)
+ {
+ level++;
+ count++;
+ if (i != hv2i(ob.hashval))
+ {
+ Console.WriteLine("Bad cell item={0}, hashval={1}, index={2}, level={3}", b.item, b.hashval, i, level);
+ retval = false;
+ }
+
+ ob = ob.overflow;
+ }
+ }
+#endif
+ }
+
+ if (count != size)
+ {
+ Console.WriteLine("size({0}) != count({1})", size, count);
+ retval = false;
+ }
+
+ return retval;
+#endif
+ }
+
+
+ /// <summary>
+ /// Produce statistics on distribution of bucket sizes. Current implementation is incomplete.
+ /// </summary>
+ /// <returns>Histogram data.</returns>
+ [Tested(via = "Manually")]
+ public ISortedDictionary<int, int> BucketCostDistribution()
+ {
+ TreeDictionary<int, int> res = new TreeDictionary<int, int>();
+#if LINEARPROBING
+ int count = 0;
+#if REFBUCKET
+ while (table[count] != null)
+#else
+ while (!isnull(table[count].item))
+#endif
+ count++;
+ for (int i = table.Length - 1; i >= 0; i--)
+ {
+#if REFBUCKET
+ if (table[i] != null)
+#else
+ if (!isnull(table[i].item))
+#endif
+ count++;
+ else
+ count = 0;
+ if (res.Contains(count))
+ res[count]++;
+ else
+ res[count] = 1;
+ }
+
+ return res;
+#else
+ for (int i = 0, s = table.Length; i < s; i++)
+ {
+ int count = 0;
+#if REFBUCKET
+ Bucket b = table[i];
+
+ while (b != null)
+ {
+ count++;
+ b = b.overflow;
+ }
+#else
+ Bucket b = table[i];
+
+ if (!isnull(b.item))
+ {
+ count = 1;
+
+ OverflowBucket ob = b.overflow;
+
+ while (ob != null)
+ {
+ count++;
+ ob = ob.overflow;
+ }
+ }
+#endif
+ if (res.Contains(count))
+ res[count]++;
+ else
+ res[count] = 1;
+ }
+
+ return res;
+#endif
+ }
+
+ #endregion
+
+ #region ICloneable Members
+
+ /// <summary>
+ /// Make a shallow copy of this HashSet.
+ /// </summary>
+ /// <returns></returns>
+ public virtual object Clone()
+ {
+ HashSet<T> clone = new HashSet<T>(size > 0 ? size : 1, itemequalityComparer);
+ //TODO: make sure this really adds in the counting bag way!
+ clone.AddAll(this);
+ return clone;
+ }
+
+ #endregion
+
+ }
+}
diff --git a/mcs/class/Mono.C5/C5/heaps/IntervalHeap.cs b/mcs/class/Mono.C5/C5/heaps/IntervalHeap.cs
new file mode 100644
index 00000000000..bf5f0d91e3f
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/heaps/IntervalHeap.cs
@@ -0,0 +1,1100 @@
+/*
+ Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+using System;
+using System.Diagnostics;
+using SCG = System.Collections.Generic;
+
+namespace C5
+{
+ /// <summary>
+ /// A priority queue class based on an interval heap data structure.
+ /// </summary>
+ /// <typeparam name="T">The item type</typeparam>
+ [Serializable]
+ public class IntervalHeap<T> : CollectionValueBase<T>, IPriorityQueue<T>
+ {
+ #region Events
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public override EventTypeEnum ListenableEvents { get { return EventTypeEnum.Basic; } }
+
+ #endregion
+
+ #region Fields
+ [Serializable]
+ struct Interval
+ {
+ internal T first, last; internal Handle firsthandle, lasthandle;
+
+
+ public override string ToString() { return String.Format("[{0}; {1}]", first, last); }
+ }
+
+
+
+ object syncroot = new object();
+
+ int stamp;
+
+ SCG.IComparer<T> comparer;
+ SCG.IEqualityComparer<T> itemequalityComparer;
+
+ Interval[] heap;
+
+ int size;
+ #endregion
+
+ #region Util
+ bool heapifyMin(int i)
+ {
+ bool swappedroot = false;
+ int cell = i, currentmin = cell;
+ T currentitem = heap[cell].first;
+ Handle currenthandle = heap[cell].firsthandle;
+
+ if (i > 0)
+ {
+ T other = heap[cell].last;
+ if (2 * cell + 1 < size && comparer.Compare(currentitem, other) > 0)
+ {
+ swappedroot = true;
+ Handle otherhandle = heap[cell].lasthandle;
+ updateLast(cell, currentitem, currenthandle);
+ currentitem = other;
+ currenthandle = otherhandle;
+ }
+ }
+
+ T minitem = currentitem;
+ Handle minhandle = currenthandle;
+
+ while (true)
+ {
+ int l = 2 * cell + 1, r = l + 1;
+ T lv, rv;
+
+ if (2 * l < size && comparer.Compare(lv = heap[l].first, minitem) < 0)
+ { currentmin = l; minitem = lv; }
+
+ if (2 * r < size && comparer.Compare(rv = heap[r].first, minitem) < 0)
+ { currentmin = r; minitem = rv; }
+
+ if (currentmin == cell)
+ break;
+
+ minhandle = heap[currentmin].firsthandle;
+ updateFirst(cell, minitem, minhandle);
+ cell = currentmin;
+
+ //Maybe swap first and last
+ T other = heap[cell].last;
+ if (2 * currentmin + 1 < size && comparer.Compare(currentitem, other) > 0)
+ {
+ Handle otherhandle = heap[cell].lasthandle;
+ updateLast(cell, currentitem, currenthandle);
+ currentitem = other;
+ currenthandle = otherhandle;
+ }
+
+
+ minitem = currentitem;
+ minhandle = currenthandle;
+ }
+
+ if (cell != i || swappedroot)
+ updateFirst(cell, minitem, minhandle);
+ return swappedroot;
+ }
+
+
+ bool heapifyMax(int i)
+ {
+ bool swappedroot = false;
+ int cell = i, currentmax = cell;
+ T currentitem = heap[cell].last;
+ Handle currenthandle = heap[cell].lasthandle;
+
+ if (i > 0)
+ {
+ T other = heap[cell].first;
+ if (comparer.Compare(currentitem, other) < 0)
+ {
+ swappedroot = true;
+ Handle otherhandle = heap[cell].firsthandle;
+ updateFirst(cell, currentitem, currenthandle);
+ currentitem = other;
+ currenthandle = otherhandle;
+ }
+ }
+
+ T maxitem = currentitem;
+ Handle maxhandle = currenthandle;
+
+ while (true)
+ {
+ int l = 2 * cell + 1, r = l + 1;
+ T lv, rv;
+
+ if (2 * l + 1 < size && comparer.Compare(lv = heap[l].last, maxitem) > 0)
+ { currentmax = l; maxitem = lv; }
+
+ if (2 * r + 1 < size && comparer.Compare(rv = heap[r].last, maxitem) > 0)
+ { currentmax = r; maxitem = rv; }
+
+ if (currentmax == cell)
+ break;
+
+ maxhandle = heap[currentmax].lasthandle;
+ updateLast(cell, maxitem, maxhandle);
+ cell = currentmax;
+
+ //Maybe swap first and last
+ T other = heap[cell].first;
+ if (comparer.Compare(currentitem, other) < 0)
+ {
+ Handle otherhandle = heap[cell].firsthandle;
+ updateFirst(cell, currentitem, currenthandle);
+ currentitem = other;
+ currenthandle = otherhandle;
+ }
+
+ maxitem = currentitem;
+ maxhandle = currenthandle;
+ }
+
+ if (cell != i || swappedroot) //Check could be better?
+ updateLast(cell, maxitem, maxhandle);
+ return swappedroot;
+ }
+
+
+ void bubbleUpMin(int i)
+ {
+ if (i > 0)
+ {
+ T min = heap[i].first, iv = min;
+ Handle minhandle = heap[i].firsthandle;
+ int p = (i + 1) / 2 - 1;
+
+ while (i > 0)
+ {
+ if (comparer.Compare(iv, min = heap[p = (i + 1) / 2 - 1].first) < 0)
+ {
+ updateFirst(i, min, heap[p].firsthandle);
+ min = iv;
+ i = p;
+ }
+ else
+ break;
+ }
+
+ updateFirst(i, iv, minhandle);
+ }
+ }
+
+
+ void bubbleUpMax(int i)
+ {
+ if (i > 0)
+ {
+ T max = heap[i].last, iv = max;
+ Handle maxhandle = heap[i].lasthandle;
+ int p = (i + 1) / 2 - 1;
+
+ while (i > 0)
+ {
+ if (comparer.Compare(iv, max = heap[p = (i + 1) / 2 - 1].last) > 0)
+ {
+ updateLast(i, max, heap[p].lasthandle);
+ max = iv;
+ i = p;
+ }
+ else
+ break;
+ }
+
+ updateLast(i, iv, maxhandle);
+
+ }
+ }
+
+ #endregion
+
+ #region Constructors
+ /// <summary>
+ /// Create an interval heap with natural item comparer and default initial capacity (16)
+ /// </summary>
+ public IntervalHeap() : this(16) { }
+
+
+ /// <summary>
+ /// Create an interval heap with external item comparer and default initial capacity (16)
+ /// </summary>
+ /// <param name="comparer">The external comparer</param>
+ public IntervalHeap(SCG.IComparer<T> comparer) : this(16,comparer) { }
+
+
+ //TODO: maybe remove
+ /// <summary>
+ /// Create an interval heap with natural item comparer and prescribed initial capacity
+ /// </summary>
+ /// <param name="capacity">The initial capacity</param>
+ public IntervalHeap(int capacity) : this(capacity, Comparer<T>.Default, EqualityComparer<T>.Default) { }
+
+
+ /// <summary>
+ /// Create an interval heap with external item comparer and prescribed initial capacity
+ /// </summary>
+ /// <param name="comparer">The external comparer</param>
+ /// <param name="capacity">The initial capacity</param>
+ public IntervalHeap(int capacity, SCG.IComparer<T> comparer) : this(capacity,comparer,new ComparerZeroHashCodeEqualityComparer<T>(comparer)) { }
+
+ IntervalHeap(int capacity, SCG.IComparer<T> comparer, SCG.IEqualityComparer<T> itemequalityComparer)
+ {
+ if (comparer == null)
+ throw new NullReferenceException("Item comparer cannot be null");
+ if (itemequalityComparer == null)
+ throw new NullReferenceException("Item equality comparer cannot be null");
+ this.comparer = comparer;
+ this.itemequalityComparer = itemequalityComparer;
+ int length = 1;
+ while (length < capacity) length <<= 1;
+ heap = new Interval[length];
+ }
+
+ #endregion
+
+ #region IPriorityQueue<T> Members
+
+ /// <summary>
+ /// Find the current least item of this priority queue.
+ /// <exception cref="NoSuchItemException"/> if queue is empty
+ /// </summary>
+ /// <returns>The least item.</returns>
+ [Tested]
+ public T FindMin()
+ {
+ if (size == 0)
+ throw new NoSuchItemException();
+
+ return heap[0].first;
+ }
+
+
+ /// <summary>
+ /// Remove the least item from this priority queue.
+ /// <exception cref="NoSuchItemException"/> if queue is empty
+ /// </summary>
+ /// <returns>The removed item.</returns>
+ [Tested]
+ public T DeleteMin()
+ {
+ IPriorityQueueHandle<T> handle = null;
+ return DeleteMin(out handle);
+ }
+
+
+ /// <summary>
+ /// Find the current largest item of this priority queue.
+ /// <exception cref="NoSuchItemException"/> if queue is empty
+ /// </summary>
+ /// <returns>The largest item.</returns>
+ [Tested]
+ public T FindMax()
+ {
+ if (size == 0)
+ throw new NoSuchItemException("Heap is empty");
+ else if (size == 1)
+ return heap[0].first;
+ else
+ return heap[0].last;
+ }
+
+
+ /// <summary>
+ /// Remove the largest item from this priority queue.
+ /// <exception cref="NoSuchItemException"/> if queue is empty
+ /// </summary>
+ /// <returns>The removed item.</returns>
+ [Tested]
+ public T DeleteMax()
+ {
+ IPriorityQueueHandle<T> handle = null;
+ return DeleteMax(out handle);
+ }
+
+
+ /// <summary>
+ /// The comparer object supplied at creation time for this collection
+ /// </summary>
+ /// <value>The comparer</value>
+ public SCG.IComparer<T> Comparer { get { return comparer; } }
+
+ #endregion
+
+ #region IExtensible<T> Members
+
+ /// <summary>
+ /// If true any call of an updating operation will throw an
+ /// <code>ReadOnlyCollectionException</code>
+ /// </summary>
+ /// <value>True if this collection is read-only.</value>
+ public bool IsReadOnly { get { return false; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>True since this collection has bag semantics</value>
+ [Tested]
+ public bool AllowsDuplicates { [Tested]get { return true; } }
+
+ /// <summary>
+ /// Value is null since this collection has no equality concept for its items.
+ /// </summary>
+ /// <value></value>
+ public virtual SCG.IEqualityComparer<T> EqualityComparer { get { return itemequalityComparer; } }
+
+ /// <summary>
+ /// By convention this is true for any collection with set semantics.
+ /// </summary>
+ /// <value>True if only one representative of a group of equal items
+ /// is kept in the collection together with the total count.</value>
+ public virtual bool DuplicatesByCounting { get { return false; } }
+
+
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>The distinguished object to use for locking to synchronize multithreaded access</value>
+ [Tested]
+ public object SyncRoot { [Tested]get { return syncroot; } }
+
+
+ /// <summary>
+ /// Add an item to this priority queue.
+ /// </summary>
+ /// <param name="item">The item to add.</param>
+ /// <returns>True</returns>
+ [Tested]
+ public bool Add(T item)
+ {
+ stamp++;
+ if (add(null, item))
+ {
+ raiseItemsAdded(item, 1);
+ raiseCollectionChanged();
+ return true;
+ }
+ return false;
+ }
+
+ private bool add(Handle itemhandle, T item)
+ {
+ if (size == 0)
+ {
+ size = 1;
+ updateFirst(0, item, itemhandle);
+ return true;
+ }
+
+ if (size == 2 * heap.Length)
+ {
+ Interval[] newheap = new Interval[2 * heap.Length];
+
+ Array.Copy(heap, newheap, heap.Length);
+ heap = newheap;
+ }
+
+ if (size % 2 == 0)
+ {
+ int i = size / 2, p = (i + 1) / 2 - 1;
+ T tmp = heap[p].last;
+
+ if (comparer.Compare(item, tmp) > 0)
+ {
+ updateFirst(i, tmp, heap[p].lasthandle);
+ updateLast(p, item, itemhandle);
+ bubbleUpMax(p);
+ }
+ else
+ {
+ updateFirst(i, item, itemhandle);
+
+ if (comparer.Compare(item, heap[p].first) < 0)
+ bubbleUpMin(i);
+ }
+ }
+ else
+ {
+ int i = size / 2;
+ T other = heap[i].first;
+
+ if (comparer.Compare(item, other) < 0)
+ {
+ updateLast(i, other, heap[i].firsthandle);
+ updateFirst(i, item, itemhandle);
+ bubbleUpMin(i);
+ }
+ else
+ {
+ updateLast(i, item, itemhandle);
+ bubbleUpMax(i);
+ }
+ }
+ size++;
+
+ return true;
+ }
+
+ private void updateLast(int cell, T item, Handle handle)
+ {
+ heap[cell].last = item;
+ if (handle != null)
+ handle.index = 2 * cell + 1;
+ heap[cell].lasthandle = handle;
+ }
+
+ private void updateFirst(int cell, T item, Handle handle)
+ {
+ heap[cell].first = item;
+ if (handle != null)
+ handle.index = 2 * cell;
+ heap[cell].firsthandle = handle;
+ }
+
+
+ /// <summary>
+ /// Add the elements from another collection with a more specialized item type
+ /// to this collection.
+ /// </summary>
+ /// <typeparam name="U">The type of items to add</typeparam>
+ /// <param name="items">The items to add</param>
+ [Tested]
+ public void AddAll<U>(SCG.IEnumerable<U> items) where U : T
+ {
+ stamp++;
+ int oldsize = size;
+ foreach (T item in items)
+ add(null, item);
+ if (size != oldsize)
+ {
+ if ((ActiveEvents & EventTypeEnum.Added) != 0)
+ foreach (T item in items)
+ raiseItemsAdded(item, 1);
+ raiseCollectionChanged();
+ }
+ }
+
+ #endregion
+
+ #region ICollection<T> members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>True if this collection is empty.</value>
+ [Tested]
+ public override bool IsEmpty { [Tested]get { return size == 0; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>The size of this collection</value>
+ [Tested]
+ public override int Count { [Tested]get { return size; } }
+
+
+ /// <summary>
+ /// The value is symbolic indicating the type of asymptotic complexity
+ /// in terms of the size of this collection (worst-case or amortized as
+ /// relevant).
+ /// </summary>
+ /// <value>A characterization of the speed of the
+ /// <code>Count</code> property in this collection.</value>
+ public override Speed CountSpeed { get { return Speed.Constant; } }
+
+ /// <summary>
+ /// Choose some item of this collection.
+ /// </summary>
+ /// <exception cref="NoSuchItemException">if collection is empty.</exception>
+ /// <returns></returns>
+ public override T Choose()
+ {
+ if (size == 0)
+ throw new NoSuchItemException("Collection is empty");
+ return heap[0].first;
+ }
+
+
+ /// <summary>
+ /// Create an enumerator for the collection
+ /// <para>Note: the enumerator does *not* enumerate the items in sorted order,
+ /// but in the internal table order.</para>
+ /// </summary>
+ /// <returns>The enumerator(SIC)</returns>
+ [Tested]
+ public override SCG.IEnumerator<T> GetEnumerator()
+ {
+ int mystamp = stamp;
+ for (int i = 0; i < size; i++)
+ {
+ if (mystamp != stamp) throw new CollectionModifiedException();
+ yield return i % 2 == 0 ? heap[i >> 1].first : heap[i >> 1].last;
+ }
+ yield break;
+ }
+
+
+ #endregion
+
+ #region Diagnostics
+ private bool check(int i, T min, T max)
+ {
+ bool retval = true;
+ Interval interval = heap[i];
+ T first = interval.first, last = interval.last;
+
+ if (2 * i + 1 == size)
+ {
+ if (comparer.Compare(min, first) > 0)
+ {
+ Console.WriteLine("Cell {0}: parent.first({1}) > first({2}) [size={3}]", i, min, first, size);
+ retval = false;
+ }
+
+ if (comparer.Compare(first, max) > 0)
+ {
+ Console.WriteLine("Cell {0}: first({1}) > parent.last({2}) [size={3}]", i, first, max, size);
+ retval = false;
+ }
+ if (interval.firsthandle != null && interval.firsthandle.index != 2 * i)
+ {
+ Console.WriteLine("Cell {0}: firsthandle.index({1}) != 2*cell({2}) [size={3}]", i, interval.firsthandle.index, 2 * i, size);
+ retval = false;
+ }
+
+ return retval;
+ }
+ else
+ {
+ if (comparer.Compare(min, first) > 0)
+ {
+ Console.WriteLine("Cell {0}: parent.first({1}) > first({2}) [size={3}]", i, min, first, size);
+ retval = false;
+ }
+
+ if (comparer.Compare(first, last) > 0)
+ {
+ Console.WriteLine("Cell {0}: first({1}) > last({2}) [size={3}]", i, first, last, size);
+ retval = false;
+ }
+
+ if (comparer.Compare(last, max) > 0)
+ {
+ Console.WriteLine("Cell {0}: last({1}) > parent.last({2}) [size={3}]", i, last, max, size);
+ retval = false;
+ }
+ if (interval.firsthandle != null && interval.firsthandle.index != 2 * i)
+ {
+ Console.WriteLine("Cell {0}: firsthandle.index({1}) != 2*cell({2}) [size={3}]", i, interval.firsthandle.index, 2 * i, size);
+ retval = false;
+ }
+ if (interval.lasthandle != null && interval.lasthandle.index != 2 * i + 1)
+ {
+ Console.WriteLine("Cell {0}: lasthandle.index({1}) != 2*cell+1({2}) [size={3}]", i, interval.lasthandle.index, 2 * i + 1, size);
+ retval = false;
+ }
+
+ int l = 2 * i + 1, r = l + 1;
+
+ if (2 * l < size)
+ retval = retval && check(l, first, last);
+
+ if (2 * r < size)
+ retval = retval && check(r, first, last);
+ }
+
+ return retval;
+ }
+
+
+ /// <summary>
+ /// Check the integrity of the internal data structures of this collection.
+ /// Only avaliable in DEBUG builds???
+ /// </summary>
+ /// <returns>True if check does not fail.</returns>
+ [Tested]
+ public bool Check()
+ {
+ if (size == 0)
+ return true;
+
+ if (size == 1)
+ return (object)(heap[0].first) != null;
+
+ return check(0, heap[0].first, heap[0].last);
+ }
+
+ #endregion
+
+ #region IPriorityQueue<T> Members
+
+ [Serializable]
+ class Handle : IPriorityQueueHandle<T>
+ {
+ /// <summary>
+ /// To save space, the index is 2*cell for heap[cell].first, and 2*cell+1 for heap[cell].last
+ /// </summary>
+ internal int index = -1;
+
+ public override string ToString()
+ {
+ return String.Format("[{0}]", index);
+ }
+
+ }
+
+ /// <summary>
+ /// Get or set the item corresponding to a handle.
+ /// </summary>
+ /// <exception cref="InvalidPriorityQueueHandleException">if the handle is invalid for this queue</exception>
+ /// <param name="handle">The reference into the heap</param>
+ /// <returns></returns>
+ [Tested]
+ public T this[IPriorityQueueHandle<T> handle]
+ {
+ get
+ {
+ int cell;
+ bool isfirst;
+ Handle myhandle = checkHandle(handle, out cell, out isfirst);
+
+ return isfirst ? heap[cell].first : heap[cell].last;
+ }
+ set
+ {
+ Replace(handle, value);
+ }
+ }
+
+
+ /// <summary>
+ /// Check safely if a handle is valid for this queue and if so, report the corresponding queue item.
+ /// </summary>
+ /// <param name="handle">The handle to check</param>
+ /// <param name="item">If the handle is valid this will contain the corresponding item on output.</param>
+ /// <returns>True if the handle is valid.</returns>
+ public bool Find(IPriorityQueueHandle<T> handle, out T item)
+ {
+ Handle myhandle = handle as Handle;
+ if (myhandle == null)
+ {
+ item = default(T);
+ return false;
+ }
+ int toremove = myhandle.index;
+ int cell = toremove / 2;
+ bool isfirst = toremove % 2 == 0;
+ {
+ if (toremove == -1 || toremove >= size)
+ {
+ item = default(T);
+ return false;
+ }
+ Handle actualhandle = isfirst ? heap[cell].firsthandle : heap[cell].lasthandle;
+ if (actualhandle != myhandle)
+ {
+ item = default(T);
+ return false;
+ }
+ }
+ item = isfirst ? heap[cell].first : heap[cell].last;
+ return true;
+ }
+
+
+ /// <summary>
+ /// Add an item to the priority queue, receiving a
+ /// handle for the item in the queue,
+ /// or reusing an already existing handle.
+ /// </summary>
+ /// <param name="handle">On output: a handle for the added item.
+ /// On input: null for allocating a new handle, an invalid handle for reuse.
+ /// A handle for reuse must be compatible with this priority queue,
+ /// by being created by a priority queue of the same runtime type, but not
+ /// necessarily the same priority queue object.</param>
+ /// <param name="item">The item to add.</param>
+ /// <returns>True since item will always be added unless the call throws an exception.</returns>
+ [Tested]
+ public bool Add(ref IPriorityQueueHandle<T> handle, T item)
+ {
+ stamp++;
+ Handle myhandle = (Handle)handle;
+ if (myhandle == null)
+ handle = myhandle = new Handle();
+ else
+ if (myhandle.index != -1)
+ throw new InvalidPriorityQueueHandleException("Handle not valid for reuse");
+ if (add(myhandle, item))
+ {
+ raiseItemsAdded(item, 1);
+ raiseCollectionChanged();
+ return true;
+ }
+ return false;
+ }
+
+ /// <summary>
+ /// Delete an item with a handle from a priority queue.
+ /// </summary>
+ /// <exception cref="InvalidPriorityQueueHandleException">if the handle is invalid</exception>
+ /// <param name="handle">The handle for the item. The handle will be invalidated, but reusable.</param>
+ /// <returns>The deleted item</returns>
+ [Tested]
+ public T Delete(IPriorityQueueHandle<T> handle)
+ {
+ stamp++;
+ int cell;
+ bool isfirst;
+ Handle myhandle = checkHandle(handle, out cell, out isfirst);
+
+ T retval;
+ myhandle.index = -1;
+ int lastcell = (size - 1) / 2;
+
+ if (cell == lastcell)
+ {
+ if (isfirst)
+ {
+ retval = heap[cell].first;
+ if (size % 2 == 0)
+ {
+ updateFirst(cell, heap[cell].last, heap[cell].lasthandle);
+ heap[cell].last = default(T);
+ heap[cell].lasthandle = null;
+ }
+ else
+ {
+ heap[cell].first = default(T);
+ heap[cell].firsthandle = null;
+ }
+ }
+ else
+ {
+ retval = heap[cell].last;
+ heap[cell].last = default(T);
+ heap[cell].lasthandle = null;
+ }
+ size--;
+ }
+ else if (isfirst)
+ {
+ retval = heap[cell].first;
+
+ if (size % 2 == 0)
+ {
+ updateFirst(cell, heap[lastcell].last, heap[lastcell].lasthandle);
+ heap[lastcell].last = default(T);
+ heap[lastcell].lasthandle = null;
+ }
+ else
+ {
+ updateFirst(cell, heap[lastcell].first, heap[lastcell].firsthandle);
+ heap[lastcell].first = default(T);
+ heap[lastcell].firsthandle = null;
+ }
+
+ size--;
+ if (heapifyMin(cell))
+ bubbleUpMax(cell);
+ else
+ bubbleUpMin(cell);
+ }
+ else
+ {
+ retval = heap[cell].last;
+
+ if (size % 2 == 0)
+ {
+ updateLast(cell, heap[lastcell].last, heap[lastcell].lasthandle);
+ heap[lastcell].last = default(T);
+ heap[lastcell].lasthandle = null;
+ }
+ else
+ {
+ updateLast(cell, heap[lastcell].first, heap[lastcell].firsthandle);
+ heap[lastcell].first = default(T);
+ heap[lastcell].firsthandle = null;
+ }
+
+ size--;
+ if (heapifyMax(cell))
+ bubbleUpMin(cell);
+ else
+ bubbleUpMax(cell);
+ }
+
+ raiseItemsRemoved(retval, 1);
+ raiseCollectionChanged();
+
+ return retval;
+ }
+
+ private Handle checkHandle(IPriorityQueueHandle<T> handle, out int cell, out bool isfirst)
+ {
+ Handle myhandle = (Handle)handle;
+ int toremove = myhandle.index;
+ cell = toremove / 2;
+ isfirst = toremove % 2 == 0;
+ {
+ if (toremove == -1 || toremove >= size)
+ throw new InvalidPriorityQueueHandleException("Invalid handle, index out of range");
+ Handle actualhandle = isfirst ? heap[cell].firsthandle : heap[cell].lasthandle;
+ if (actualhandle != myhandle)
+ throw new InvalidPriorityQueueHandleException("Invalid handle, doesn't match queue");
+ }
+ return myhandle;
+ }
+
+
+ /// <summary>
+ /// Replace an item with a handle in a priority queue with a new item.
+ /// Typically used for changing the priority of some queued object.
+ /// </summary>
+ /// <param name="handle">The handle for the old item</param>
+ /// <param name="item">The new item</param>
+ /// <returns>The old item</returns>
+ [Tested]
+ public T Replace(IPriorityQueueHandle<T> handle, T item)
+ {
+ stamp++;
+ int cell;
+ bool isfirst;
+ checkHandle(handle, out cell, out isfirst);
+ if (size == 0)
+ throw new NoSuchItemException();
+
+ T retval;
+
+ if (isfirst)
+ {
+ retval = heap[cell].first;
+ heap[cell].first = item;
+ if (size == 2 * cell + 1) // cell == lastcell
+ {
+ int p = (cell + 1) / 2 - 1;
+ if (comparer.Compare(item, heap[p].last) > 0)
+ {
+ Handle thehandle = heap[cell].firsthandle;
+ updateFirst(cell, heap[p].last, heap[p].lasthandle);
+ updateLast(p, item, thehandle);
+ bubbleUpMax(p);
+ }
+ else
+ bubbleUpMin(cell);
+ }
+ else if (heapifyMin(cell))
+ bubbleUpMax(cell);
+ else
+ bubbleUpMin(cell);
+ }
+ else
+ {
+ retval = heap[cell].last;
+ heap[cell].last = item;
+ if (heapifyMax(cell))
+ bubbleUpMin(cell);
+ else
+ bubbleUpMax(cell);
+ }
+
+ raiseItemsRemoved(retval, 1);
+ raiseItemsAdded(item, 1);
+ raiseCollectionChanged();
+
+ return retval;
+ }
+
+ /// <summary>
+ /// Find the current least item of this priority queue.
+ /// </summary>
+ /// <param name="handle">On return: the handle of the item.</param>
+ /// <returns>The least item.</returns>
+ public T FindMin(out IPriorityQueueHandle<T> handle)
+ {
+ if (size == 0)
+ throw new NoSuchItemException();
+ handle = heap[0].firsthandle;
+
+ return heap[0].first;
+ }
+
+ /// <summary>
+ /// Find the current largest item of this priority queue.
+ /// </summary>
+ /// <param name="handle">On return: the handle of the item.</param>
+ /// <returns>The largest item.</returns>
+ public T FindMax(out IPriorityQueueHandle<T> handle)
+ {
+ if (size == 0)
+ throw new NoSuchItemException();
+ else if (size == 1)
+ {
+ handle = heap[0].firsthandle;
+ return heap[0].first;
+ }
+ else
+ {
+ handle = heap[0].lasthandle;
+ return heap[0].last;
+ }
+ }
+
+ /// <summary>
+ /// Remove the least item from this priority queue.
+ /// </summary>
+ /// <param name="handle">On return: the handle of the removed item.</param>
+ /// <returns>The removed item.</returns>
+ public T DeleteMin(out IPriorityQueueHandle<T> handle)
+ {
+ stamp++;
+ if (size == 0)
+ throw new NoSuchItemException();
+
+ T retval = heap[0].first;
+ Handle myhandle = heap[0].firsthandle;
+ handle = myhandle;
+ if (myhandle != null)
+ myhandle.index = -1;
+
+ if (size == 1)
+ {
+ size = 0;
+ heap[0].first = default(T);
+ heap[0].firsthandle = null;
+ }
+ else
+ {
+ int lastcell = (size - 1) / 2;
+
+ if (size % 2 == 0)
+ {
+ updateFirst(0, heap[lastcell].last, heap[lastcell].lasthandle);
+ heap[lastcell].last = default(T);
+ heap[lastcell].lasthandle = null;
+ }
+ else
+ {
+ updateFirst(0, heap[lastcell].first, heap[lastcell].firsthandle);
+ heap[lastcell].first = default(T);
+ heap[lastcell].firsthandle = null;
+ }
+
+ size--;
+ heapifyMin(0);
+ }
+
+ raiseItemsRemoved(retval, 1);
+ raiseCollectionChanged();
+ return retval;
+
+ }
+
+ /// <summary>
+ /// Remove the largest item from this priority queue.
+ /// </summary>
+ /// <param name="handle">On return: the handle of the removed item.</param>
+ /// <returns>The removed item.</returns>
+ public T DeleteMax(out IPriorityQueueHandle<T> handle)
+ {
+ stamp++;
+ if (size == 0)
+ throw new NoSuchItemException();
+
+ T retval;
+ Handle myhandle;
+
+ if (size == 1)
+ {
+ size = 0;
+ retval = heap[0].first;
+ myhandle = heap[0].firsthandle;
+ if (myhandle != null)
+ myhandle.index = -1;
+ heap[0].first = default(T);
+ heap[0].firsthandle = null;
+ }
+ else
+ {
+ retval = heap[0].last;
+ myhandle = heap[0].lasthandle;
+ if (myhandle != null)
+ myhandle.index = -1;
+
+ int lastcell = (size - 1) / 2;
+
+ if (size % 2 == 0)
+ {
+ updateLast(0, heap[lastcell].last, heap[lastcell].lasthandle);
+ heap[lastcell].last = default(T);
+ heap[lastcell].lasthandle = null;
+ }
+ else
+ {
+ updateLast(0, heap[lastcell].first, heap[lastcell].firsthandle);
+ heap[lastcell].first = default(T);
+ heap[lastcell].firsthandle = null;
+ }
+
+ size--;
+ heapifyMax(0);
+ }
+ raiseItemsRemoved(retval, 1);
+ raiseCollectionChanged();
+ handle = myhandle;
+ return retval;
+ }
+
+ #endregion
+
+ #region ICloneable Members
+
+ /// <summary>
+ /// Make a shallow copy of this IntervalHeap.
+ /// </summary>
+ /// <returns></returns>
+ public virtual object Clone()
+ {
+ IntervalHeap<T> clone = new IntervalHeap<T>(size, comparer, itemequalityComparer);
+ clone.AddAll(this);
+ return clone;
+ }
+
+ #endregion
+
+ }
+
+}
diff --git a/mcs/class/Mono.C5/C5/linkedlists/LinkedList.cs b/mcs/class/Mono.C5/C5/linkedlists/LinkedList.cs
new file mode 100644
index 00000000000..322a4c0cb3d
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/linkedlists/LinkedList.cs
@@ -0,0 +1,3782 @@
+/*
+ Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+#define HASHINDEXnot
+
+using System;
+using System.Diagnostics;
+using SCG = System.Collections.Generic;
+
+namespace C5
+{
+ /// <summary>
+ /// A list collection class based on a doubly linked list data structure.
+ /// </summary>
+ [Serializable]
+ public class LinkedList<T> : SequencedBase<T>, IList<T>
+#if HASHINDEX
+#else
+, IStack<T>, IQueue<T>
+#endif
+ {
+ #region Fields
+ /// <summary>
+ /// IExtensible.Add(T) always does AddLast(T), fIFO determines
+ /// if T Remove() does RemoveFirst() or RemoveLast()
+ /// </summary>
+ bool fIFO = true;
+
+ #region Events
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public override EventTypeEnum ListenableEvents { get { return underlying == null ? EventTypeEnum.All : EventTypeEnum.None; } }
+
+ #endregion
+
+ //Invariant: startsentinel != null && endsentinel != null
+ //If size==0: startsentinel.next == endsentinel && endsentinel.prev == startsentinel
+ //Else: startsentinel.next == First && endsentinel.prev == Last)
+ /// <summary>
+ /// Node to the left of first node
+ /// </summary>
+ Node startsentinel;
+ /// <summary>
+ /// Node to the right of last node
+ /// </summary>
+ Node endsentinel;
+ /// <summary>
+ /// Offset of this view in underlying list
+ /// </summary>
+#if HASHINDEX
+ int? offset;
+#else
+ int offset;
+#endif
+
+ /// <summary>
+ /// underlying list of this view (or null for the underlying list)
+ /// </summary>
+ LinkedList<T> underlying;
+
+ //Note: all views will have the same views list since all view objects are created by MemeberwiseClone()
+ WeakViewList<LinkedList<T>> views;
+ WeakViewList<LinkedList<T>>.Node myWeakReference;
+
+ /// <summary>
+ /// Has this list or view not been invalidated by some operation (by someone calling Dispose())
+ /// </summary>
+ bool isValid = true;
+
+
+#if HASHINDEX
+ HashDictionary<T, Node> dict;
+ /// <summary>
+ /// Number of taggroups
+ /// </summary>
+ int taggroups;
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ int Taggroups
+ {
+ get { return underlying == null ? taggroups : underlying.taggroups; }
+ set { if (underlying == null) taggroups = value; else underlying.taggroups = value; }
+ }
+#endif
+
+ #endregion
+
+ #region Util
+
+ bool equals(T i1, T i2) { return itemequalityComparer.Equals(i1, i2); }
+
+ #region Check utilities
+ /// <summary>
+ /// Check if it is valid to perform updates and increment stamp of
+ /// underlying if this is a view.
+ /// <para>This method should be called in every public modifying
+ /// methods before any modifications are performed.
+ /// </para>
+ /// </summary>
+ /// <exception cref="InvalidOperationException"> if check fails.</exception>
+ protected override void updatecheck()
+ {
+ validitycheck();
+ base.updatecheck();
+ if (underlying != null)
+ underlying.stamp++;
+ }
+
+ /// <summary>
+ /// Check if we are a view that the underlyinglist has only been updated through us.
+ /// <br/>
+ /// This method should be called from enumerators etc to guard against
+ /// modification of the base collection.
+ /// </summary>
+ /// <exception cref="InvalidOperationException"> if check fails.</exception>
+ void validitycheck()
+ {
+ if (!isValid)
+ throw new ViewDisposedException();
+ }
+
+ /// <summary>
+ /// Check that the list has not been updated since a particular time.
+ /// </summary>
+ /// <param name="stamp">The stamp indicating the time.</param>
+ /// <exception cref="CollectionModifiedException"> if check fails.</exception>
+ protected override void modifycheck(int stamp)
+ {
+ validitycheck();
+ if ((underlying != null ? underlying.stamp : this.stamp) != stamp)
+ throw new CollectionModifiedException();
+ }
+ #endregion
+
+ #region Searching
+ bool contains(T item, out Node node)
+ {
+#if HASHINDEX
+ if (dict.Find(item, out node))
+ return insideview(node);
+#else
+ //TODO: search from both ends? Or search from the end selected by FIFO?
+ node = startsentinel.next;
+ while (node != endsentinel)
+ {
+ if (equals(item, node.item))
+ return true;
+ node = node.next;
+ }
+#endif
+ return false;
+ }
+
+ /// <summary>
+ /// Search forwards from a node for a node with a particular item.
+ /// </summary>
+ /// <param name="item">The item to look for</param>
+ /// <param name="node">On input, the node to start at. If item was found, the node found on output.</param>
+ /// <param name="index">If node was found, the value will be the number of links followed higher than
+ /// the value on input. If item was not found, the value on output is undefined.</param>
+ /// <returns>True if node was found.</returns>
+ bool find(T item, ref Node node, ref int index)
+ {
+ while (node != endsentinel)
+ {
+ //if (item.Equals(node.item))
+ if (itemequalityComparer.Equals(item, node.item))
+ return true;
+
+ index++;
+ node = node.next;
+ }
+
+ return false;
+ }
+
+ bool dnif(T item, ref Node node, ref int index)
+ {
+ while (node != startsentinel)
+ {
+ //if (item.Equals(node.item))
+ if (itemequalityComparer.Equals(item, node.item))
+ return true;
+
+ index--;
+ node = node.prev;
+ }
+
+ return false;
+ }
+
+#if HASHINDEX
+ bool insideview(Node node)
+ {
+ if (underlying == null)
+ return true;
+ return (startsentinel.precedes(node) && node.precedes(endsentinel));
+ }
+#endif
+
+ #endregion
+
+ #region Indexing
+ /// <summary>
+ /// Return the node at position pos
+ /// </summary>
+ /// <param name="pos"></param>
+ /// <returns></returns>
+ Node get(int pos)
+ {
+ if (pos < 0 || pos >= size)
+ throw new IndexOutOfRangeException();
+ else if (pos < size / 2)
+ { // Closer to front
+ Node node = startsentinel;
+
+ for (int i = 0; i <= pos; i++)
+ node = node.next;
+
+ return node;
+ }
+ else
+ { // Closer to end
+ Node node = endsentinel;
+
+ for (int i = size; i > pos; i--)
+ node = node.prev;
+
+ return node;
+ }
+ }
+
+ /// <summary>
+ /// Find the distance from pos to the set given by positions. Return the
+ /// signed distance as return value and as an out parameter, the
+ /// array index of the nearest position. This is used for up to length 5 of
+ /// positions, and we do not assume it is sorted.
+ /// </summary>
+ /// <param name="pos"></param>
+ /// <param name="positions"></param>
+ /// <param name="nearest"></param>
+ /// <returns></returns>
+ int dist(int pos, out int nearest, int[] positions)
+ {
+ nearest = -1;
+ int bestdist = int.MaxValue;
+ int signeddist = bestdist;
+ for (int i = 0; i < positions.Length; i++)
+ {
+ int thisdist = positions[i] - pos;
+ if (thisdist >= 0 && thisdist < bestdist) { nearest = i; bestdist = thisdist; signeddist = thisdist; }
+ if (thisdist < 0 && -thisdist < bestdist) { nearest = i; bestdist = -thisdist; signeddist = thisdist; }
+ }
+ return signeddist;
+ }
+
+ /// <summary>
+ /// Find the node at position pos, given known positions of several nodes.
+ /// </summary>
+ /// <param name="pos"></param>
+ /// <param name="positions"></param>
+ /// <param name="nodes"></param>
+ /// <returns></returns>
+ Node get(int pos, int[] positions, Node[] nodes)
+ {
+ int nearest;
+ int delta = dist(pos, out nearest, positions);
+ Node node = nodes[nearest];
+ if (delta > 0)
+ for (int i = 0; i < delta; i++)
+ node = node.prev;
+ else
+ for (int i = 0; i > delta; i--)
+ node = node.next;
+ return node;
+ }
+
+ /// <summary>
+ /// Get nodes at positions p1 and p2, given nodes at several positions.
+ /// </summary>
+ /// <param name="p1"></param>
+ /// <param name="p2"></param>
+ /// <param name="n1"></param>
+ /// <param name="n2"></param>
+ /// <param name="positions"></param>
+ /// <param name="nodes"></param>
+ void getPair(int p1, int p2, out Node n1, out Node n2, int[] positions, Node[] nodes)
+ {
+ int nearest1, nearest2;
+ int delta1 = dist(p1, out nearest1, positions), d1 = delta1 < 0 ? -delta1 : delta1;
+ int delta2 = dist(p2, out nearest2, positions), d2 = delta2 < 0 ? -delta2 : delta2;
+
+ if (d1 < d2)
+ {
+ n1 = get(p1, positions, nodes);
+ n2 = get(p2, new int[] { positions[nearest2], p1 }, new Node[] { nodes[nearest2], n1 });
+ }
+ else
+ {
+ n2 = get(p2, positions, nodes);
+ n1 = get(p1, new int[] { positions[nearest1], p2 }, new Node[] { nodes[nearest1], n2 });
+ }
+ }
+ #endregion
+
+ #region Insertion
+#if HASHINDEX
+ void insert(int index, Node succ, T item)
+ {
+ Node newnode = new Node(item);
+ if (dict.FindOrAdd(item, ref newnode))
+ throw new DuplicateNotAllowedException("Item already in indexed list");
+ insertNode(true, succ, newnode);
+ }
+
+ /// <summary>
+ /// Insert a Node before another one. Unchecked version.
+ /// </summary>
+ /// <param name="succ">The successor to be</param>
+ /// <param name="newnode">Node to insert</param>
+ /// <param name="updateViews">update overlapping view in this call</param>
+ void insertNode(bool updateViews, Node succ, Node newnode)
+ {
+ newnode.next = succ;
+ Node pred = newnode.prev = succ.prev;
+ succ.prev.next = newnode;
+ succ.prev = newnode;
+ size++;
+ if (underlying != null)
+ underlying.size++;
+ settag(newnode);
+ if (updateViews)
+ fixViewsAfterInsert(succ, pred, 1, 0);
+ }
+#else
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="index">The index in this view</param>
+ /// <param name="succ"></param>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ Node insert(int index, Node succ, T item)
+ {
+ Node newnode = new Node(item, succ.prev, succ);
+ succ.prev.next = newnode;
+ succ.prev = newnode;
+ size++;
+ if (underlying != null)
+ underlying.size++;
+ fixViewsAfterInsert(succ, newnode.prev, 1, Offset + index);
+ return newnode;
+ }
+#endif
+ #endregion
+
+ #region Removal
+ T remove(Node node, int index)
+ {
+ fixViewsBeforeSingleRemove(node, Offset + index);
+ node.prev.next = node.next;
+ node.next.prev = node.prev;
+ size--;
+ if (underlying != null)
+ underlying.size--;
+#if HASHINDEX
+ removefromtaggroup(node);
+#endif
+ return node.item;
+ }
+
+#if HASHINDEX
+ private bool dictremove(T item, out Node node)
+ {
+ if (underlying == null)
+ {
+ if (!dict.Remove(item, out node))
+ return false;
+ }
+ else
+ {
+ //We cannot avoid calling dict twice - have to intersperse the listorder test!
+ if (!contains(item, out node))
+ return false;
+ dict.Remove(item);
+ }
+ return true;
+ }
+#endif
+ #endregion
+
+ #region fixView utilities
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="added">The actual number of inserted nodes</param>
+ /// <param name="pred">The predecessor of the inserted nodes</param>
+ /// <param name="succ">The successor of the added nodes</param>
+ /// <param name="realInsertionIndex"></param>
+ void fixViewsAfterInsert(Node succ, Node pred, int added, int realInsertionIndex)
+ {
+ if (views != null)
+ foreach (LinkedList<T> view in views)
+ {
+ if (view != this)
+ {
+#if HASHINDEX
+ if (pred.precedes(view.startsentinel) || (view.startsentinel == pred && view.size > 0))
+ view.offset += added;
+ if (view.startsentinel.precedes(pred) && succ.precedes(view.endsentinel))
+ view.size += added;
+ if (view.startsentinel == pred && view.size > 0)
+ view.startsentinel = succ.prev;
+ if (view.endsentinel == succ)
+ view.endsentinel = pred.next;
+#else
+ if (view.Offset == realInsertionIndex && view.size > 0)
+ view.startsentinel = succ.prev;
+ if (view.Offset + view.size == realInsertionIndex)
+ view.endsentinel = pred.next;
+ if (view.Offset < realInsertionIndex && view.Offset + view.size > realInsertionIndex)
+ view.size += added;
+ if (view.Offset > realInsertionIndex || (view.Offset == realInsertionIndex && view.size > 0))
+ view.offset += added;
+#endif
+ }
+ }
+ }
+
+ void fixViewsBeforeSingleRemove(Node node, int realRemovalIndex)
+ {
+ if (views != null)
+ foreach (LinkedList<T> view in views)
+ {
+ if (view != this)
+ {
+#if HASHINDEX
+ if (view.startsentinel.precedes(node) && node.precedes(view.endsentinel))
+ view.size--;
+ if (!view.startsentinel.precedes(node))
+ view.offset--;
+ if (view.startsentinel == node)
+ view.startsentinel = node.prev;
+ if (view.endsentinel == node)
+ view.endsentinel = node.next;
+#else
+ if (view.offset - 1 == realRemovalIndex)
+ view.startsentinel = node.prev;
+ if (view.offset + view.size == realRemovalIndex)
+ view.endsentinel = node.next;
+ if (view.offset <= realRemovalIndex && view.offset + view.size > realRemovalIndex)
+ view.size--;
+ if (view.offset > realRemovalIndex)
+ view.offset--;
+#endif
+ }
+ }
+ }
+
+#if HASHINDEX
+#else
+ void fixViewsBeforeRemove(int start, int count, Node first, Node last)
+ {
+ int clearend = start + count - 1;
+ if (views != null)
+ foreach (LinkedList<T> view in views)
+ {
+ if (view == this)
+ continue;
+ int viewoffset = view.Offset, viewend = viewoffset + view.size - 1;
+ //sentinels
+ if (start < viewoffset && viewoffset - 1 <= clearend)
+ view.startsentinel = first.prev;
+ if (start <= viewend + 1 && viewend < clearend)
+ view.endsentinel = last.next;
+ //offsets and sizes
+ if (start < viewoffset)
+ {
+ if (clearend < viewoffset)
+ view.offset = viewoffset - count;
+ else
+ {
+ view.offset = start;
+ view.size = clearend < viewend ? viewend - clearend : 0;
+ }
+ }
+ else if (start <= viewend)
+ view.size = clearend <= viewend ? view.size - count : start - viewoffset;
+ }
+ }
+#endif
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="otherView"></param>
+ /// <returns>The position of View(otherOffset, otherSize) wrt. this view</returns>
+ MutualViewPosition viewPosition(LinkedList<T> otherView)
+ {
+#if HASHINDEX
+ Node otherstartsentinel = otherView.startsentinel, otherendsentinel = otherView.endsentinel,
+ first = startsentinel.next, last = endsentinel.prev,
+ otherfirst = otherstartsentinel.next, otherlast = otherendsentinel.prev;
+ if (last.precedes(otherfirst) || otherlast.precedes(first))
+ return MutualViewPosition.NonOverlapping;
+ if (size == 0 || (otherstartsentinel.precedes(first) && last.precedes(otherendsentinel)))
+ return MutualViewPosition.Contains;
+ if (otherView.size == 0 || (startsentinel.precedes(otherfirst) && otherlast.precedes(endsentinel)))
+ return MutualViewPosition.ContainedIn;
+ return MutualViewPosition.Overlapping;
+#else
+ int end = offset + size, otherOffset = otherView.offset, otherSize = otherView.size, otherEnd = otherOffset + otherSize;
+ if (otherOffset >= end || otherEnd <= offset)
+ return MutualViewPosition.NonOverlapping;
+ if (size == 0 || (otherOffset <= offset && end <= otherEnd))
+ return MutualViewPosition.Contains;
+ if (otherSize == 0 || (offset <= otherOffset && otherEnd <= end))
+ return MutualViewPosition.ContainedIn;
+ return MutualViewPosition.Overlapping;
+#endif
+ }
+
+ void disposeOverlappingViews(bool reverse)
+ {
+ if (views != null)
+ {
+ foreach (LinkedList<T> view in views)
+ {
+ if (view != this)
+ {
+ switch (viewPosition(view))
+ {
+ case MutualViewPosition.ContainedIn:
+ if (reverse)
+ { }
+ else
+ view.Dispose();
+ break;
+ case MutualViewPosition.Overlapping:
+ view.Dispose();
+ break;
+ case MutualViewPosition.Contains:
+ case MutualViewPosition.NonOverlapping:
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ #endregion
+
+ #endregion
+
+ #region Constructors
+
+ /// <summary>
+ /// Create a linked list with en external item equalityComparer
+ /// </summary>
+ /// <param name="itemequalityComparer">The external equalityComparer</param>
+ public LinkedList(SCG.IEqualityComparer<T> itemequalityComparer)
+ : base(itemequalityComparer)
+ {
+ offset = 0;
+ size = stamp = 0;
+ startsentinel = new Node(default(T));
+ endsentinel = new Node(default(T));
+ startsentinel.next = endsentinel;
+ endsentinel.prev = startsentinel;
+#if HASHINDEX
+ //It is important that the sentinels are different:
+ startsentinel.taggroup = new TagGroup();
+ startsentinel.taggroup.tag = int.MinValue;
+ startsentinel.taggroup.count = 0;
+ endsentinel.taggroup = new TagGroup();
+ endsentinel.taggroup.tag = int.MaxValue;
+ endsentinel.taggroup.count = 0;
+ dict = new HashDictionary<T, Node>(itemequalityComparer);
+#endif
+ }
+
+ /// <summary>
+ /// Create a linked list with the natural item equalityComparer
+ /// </summary>
+ public LinkedList() : this(EqualityComparer<T>.Default) { }
+
+ #endregion
+
+ #region Node nested class
+
+ /// <summary>
+ /// An individual cell in the linked list
+ /// </summary>
+ [Serializable]
+ class Node
+ {
+ public Node prev;
+
+ public Node next;
+
+ public T item;
+
+ #region Tag support
+#if HASHINDEX
+ internal int tag;
+
+ internal TagGroup taggroup;
+
+ internal bool precedes(Node that)
+ {
+ //Debug.Assert(taggroup != null, "taggroup field null");
+ //Debug.Assert(that.taggroup != null, "that.taggroup field null");
+ int t1 = taggroup.tag;
+ int t2 = that.taggroup.tag;
+
+ return t1 < t2 ? true : t1 > t2 ? false : tag < that.tag;
+ }
+#endif
+ #endregion
+
+ [Tested]
+ internal Node(T item) { this.item = item; }
+
+ [Tested]
+ internal Node(T item, Node prev, Node next)
+ {
+ this.item = item; this.prev = prev; this.next = next;
+ }
+
+ public override string ToString()
+ {
+#if HASHINDEX
+ return String.Format("Node: (item={0}, tag={1})", item, tag);
+#else
+ return String.Format("Node(item={0})", item);
+#endif
+ }
+ }
+
+ #endregion
+
+ #region Taggroup nested class and tag maintenance utilities
+#if HASHINDEX
+ /// <summary>
+ /// A group of nodes with the same high tag. Purpose is to be
+ /// able to tell the sequence order of two nodes without having to scan through
+ /// the list.
+ /// </summary>
+ [Serializable]
+ class TagGroup
+ {
+ internal int tag, count;
+
+ internal Node first, last;
+
+ /// <summary>
+ /// Pretty print a tag group
+ /// </summary>
+ /// <returns>Formatted tag group</returns>
+ public override string ToString()
+ { return String.Format("TagGroup(tag={0}, cnt={1}, fst={2}, lst={3})", tag, count, first, last); }
+ }
+
+ //Constants for tag maintenance
+ const int wordsize = 32;
+
+ const int lobits = 3;
+
+ const int hibits = lobits + 1;
+
+ const int losize = 1 << lobits;
+
+ const int hisize = 1 << hibits;
+
+ const int logwordsize = 5;
+
+ TagGroup gettaggroup(Node pred, Node succ, out int lowbound, out int highbound)
+ {
+ TagGroup predgroup = pred.taggroup, succgroup = succ.taggroup;
+
+ if (predgroup == succgroup)
+ {
+ lowbound = pred.tag + 1;
+ highbound = succ.tag - 1;
+ return predgroup;
+ }
+ else if (predgroup.first != null)
+ {
+ lowbound = pred.tag + 1;
+ highbound = int.MaxValue;
+ return predgroup;
+ }
+ else if (succgroup.first != null)
+ {
+ lowbound = int.MinValue;
+ highbound = succ.tag - 1;
+ return succgroup;
+ }
+ else
+ {
+ lowbound = int.MinValue;
+ highbound = int.MaxValue;
+ return new TagGroup();
+ }
+ }
+
+
+ /// <summary>
+ /// Put a tag on a node (already inserted in the list). Split taggroups and renumber as
+ /// necessary.
+ /// </summary>
+ /// <param name="node">The node to tag</param>
+ void settag(Node node)
+ {
+ Node pred = node.prev, succ = node.next;
+ TagGroup predgroup = pred.taggroup, succgroup = succ.taggroup;
+
+ if (predgroup == succgroup)
+ {
+ node.taggroup = predgroup;
+ predgroup.count++;
+ if (pred.tag + 1 == succ.tag)
+ splittaggroup(predgroup);
+ else
+ node.tag = (pred.tag + 1) / 2 + (succ.tag - 1) / 2;
+ }
+ else if (predgroup.first != null)
+ {
+ node.taggroup = predgroup;
+ predgroup.last = node;
+ predgroup.count++;
+ if (pred.tag == int.MaxValue)
+ splittaggroup(predgroup);
+ else
+ node.tag = pred.tag / 2 + int.MaxValue / 2 + 1;
+ }
+ else if (succgroup.first != null)
+ {
+ node.taggroup = succgroup;
+ succgroup.first = node;
+ succgroup.count++;
+ if (succ.tag == int.MinValue)
+ splittaggroup(node.taggroup);
+ else
+ node.tag = int.MinValue / 2 + (succ.tag - 1) / 2;
+ }
+ else
+ {
+ Debug.Assert(Taggroups == 0);
+
+ TagGroup newgroup = new TagGroup();
+
+ Taggroups = 1;
+ node.taggroup = newgroup;
+ newgroup.first = newgroup.last = node;
+ newgroup.count = 1;
+ return;
+ }
+ }
+
+
+ /// <summary>
+ /// Remove a node from its taggroup.
+ /// <br/> When this is called, node must already have been removed from the underlying list
+ /// </summary>
+ /// <param name="node">The node to remove</param>
+ void removefromtaggroup(Node node)
+ {
+ //
+ TagGroup taggroup = node.taggroup;
+
+ if (--taggroup.count == 0)
+ {
+ Taggroups--;
+ return;
+ }
+
+ if (node == taggroup.first)
+ taggroup.first = node.next;
+
+ if (node == taggroup.last)
+ taggroup.last = node.prev;
+
+ //node.taggroup = null;
+ if (taggroup.count != losize || Taggroups == 1)
+ return;
+
+ TagGroup otg;
+
+ if ((otg = taggroup.first.prev.taggroup).count <= losize)
+ taggroup.first = otg.first;
+ else if ((otg = taggroup.last.next.taggroup).count <= losize)
+ taggroup.last = otg.last;
+ else
+ return;
+
+ Node n = otg.first;
+
+ for (int i = 0, length = otg.count; i < length; i++)
+ {
+ n.taggroup = taggroup;
+ n = n.next;
+ }
+
+ taggroup.count += otg.count;
+ Taggroups--;
+ n = taggroup.first;
+
+ const int ofs = wordsize - hibits;
+
+ for (int i = 0, count = taggroup.count; i < count; i++)
+ {
+ n.tag = (i - losize) << ofs; //(i-8)<<28
+ n = n.next;
+ }
+ }
+
+
+ /// <summary>
+ /// Split a tag group to make rom for more tags.
+ /// </summary>
+ /// <param name="taggroup">The tag group</param>
+ void splittaggroup(TagGroup taggroup)
+ {
+ Node n = taggroup.first;
+ int ptgt = taggroup.first.prev.taggroup.tag;
+ int ntgt = taggroup.last.next.taggroup.tag;
+
+ Debug.Assert(ptgt + 1 <= ntgt - 1);
+
+ int ofs = wordsize - hibits;
+#warning hack alert was there a -1 here?
+ int newtgs = taggroup.count / hisize;// - 1;
+ int tgtdelta = (int)((ntgt + 0.0 - ptgt) / (newtgs + 2)), tgtag = ptgt;
+
+ tgtdelta = tgtdelta == 0 ? 1 : tgtdelta;
+ for (int j = 0; j < newtgs; j++)
+ {
+ TagGroup newtaggroup = new TagGroup();
+
+ newtaggroup.tag = (tgtag = tgtag >= ntgt - tgtdelta ? ntgt : tgtag + tgtdelta);
+ newtaggroup.first = n;
+ newtaggroup.count = hisize;
+ for (int i = 0; i < hisize; i++)
+ {
+ n.taggroup = newtaggroup;
+ n.tag = (i - losize) << ofs; //(i-8)<<28
+ n = n.next;
+ }
+
+ newtaggroup.last = n.prev;
+ }
+
+ int rest = taggroup.count - hisize * newtgs;
+
+ taggroup.first = n;
+ taggroup.count = rest;
+ taggroup.tag = (tgtag = tgtag >= ntgt - tgtdelta ? ntgt : tgtag + tgtdelta); ofs--;
+ for (int i = 0; i < rest; i++)
+ {
+ n.tag = (i - hisize) << ofs; //(i-16)<<27
+ n = n.next;
+ }
+
+ taggroup.last = n.prev;
+ Taggroups += newtgs;
+ if (tgtag == ntgt)
+ redistributetaggroups(taggroup);
+ }
+
+
+ private void redistributetaggroups(TagGroup taggroup)
+ {
+ TagGroup pred = taggroup, succ = taggroup, tmp;
+ double limit = 1, bigt = Math.Pow(Taggroups, 1.0 / 30);//?????
+ int bits = 1, count = 1, lowmask = 0, himask = 0, target = 0;
+
+ do
+ {
+ bits++;
+ lowmask = (1 << bits) - 1;
+ himask = ~lowmask;
+ target = taggroup.tag & himask;
+ while ((tmp = pred.first.prev.taggroup).first != null && (tmp.tag & himask) == target)
+ { count++; pred = tmp; }
+
+ while ((tmp = succ.last.next.taggroup).last != null && (tmp.tag & himask) == target)
+ { count++; succ = tmp; }
+
+ limit *= bigt;
+ } while (count > limit);
+
+ //redistibute tags
+ int lob = pred.first.prev.taggroup.tag, upb = succ.last.next.taggroup.tag;
+ int delta = upb / (count + 1) - lob / (count + 1);
+
+ Debug.Assert(delta > 0);
+ for (int i = 0; i < count; i++)
+ {
+ pred.tag = lob + (i + 1) * delta;
+ pred = pred.last.next.taggroup;
+ }
+ }
+#endif
+
+ #endregion
+
+ #region Position, PositionComparer and ViewHandler nested types
+ class PositionComparer : SCG.IComparer<Position>
+ {
+ static PositionComparer _default;
+ PositionComparer() { }
+ public static PositionComparer Default { get { return _default ?? (_default = new PositionComparer()); } }
+ public int Compare(Position a, Position b)
+ {
+#if HASHINDEX
+ return a.Endpoint == b.Endpoint ? 0 : a.Endpoint.precedes(b.Endpoint) ? -1 : 1;
+#else
+ return a.Index.CompareTo(b.Index);
+#endif
+ }
+ }
+ /// <summary>
+ /// During RemoveAll, we need to cache the original endpoint indices of views
+ /// </summary>
+ struct Position
+ {
+ public readonly LinkedList<T> View;
+ public bool Left;
+#if HASHINDEX
+ public readonly Node Endpoint;
+#else
+ public readonly int Index;
+#endif
+ public Position(LinkedList<T> view, bool left)
+ {
+ View = view;
+ Left = left;
+#if HASHINDEX
+ Endpoint = left ? view.startsentinel.next : view.endsentinel.prev;
+#else
+ Index = left ? view.Offset : view.Offset + view.size - 1;
+#endif
+ }
+#if HASHINDEX
+ public Position(Node node, int foo) { this.Endpoint = node; View = null; Left = false;}
+#else
+ public Position(int index) { this.Index = index; View = null; Left = false; }
+#endif
+ }
+
+ //TODO: merge the two implementations using Position values as arguments
+ /// <summary>
+ /// Handle the update of (other) views during a multi-remove operation.
+ /// </summary>
+ struct ViewHandler
+ {
+ ArrayList<Position> leftEnds;
+ ArrayList<Position> rightEnds;
+ int leftEndIndex, rightEndIndex, leftEndIndex2, rightEndIndex2;
+ internal readonly int viewCount;
+ internal ViewHandler(LinkedList<T> list)
+ {
+ leftEndIndex = rightEndIndex = leftEndIndex2 = rightEndIndex2 = viewCount = 0;
+ leftEnds = rightEnds = null;
+ if (list.views != null)
+ foreach (LinkedList<T> v in list.views)
+ if (v != list)
+ {
+ if (leftEnds == null)
+ {
+ leftEnds = new ArrayList<Position>();
+ rightEnds = new ArrayList<Position>();
+ }
+ leftEnds.Add(new Position(v, true));
+ rightEnds.Add(new Position(v, false));
+ }
+ if (leftEnds == null)
+ return;
+ viewCount = leftEnds.Count;
+ leftEnds.Sort(PositionComparer.Default);
+ rightEnds.Sort(PositionComparer.Default);
+ }
+#if HASHINDEX
+ internal void skipEndpoints(int removed, Node n)
+ {
+ if (viewCount > 0)
+ {
+ Position endpoint;
+ while (leftEndIndex < viewCount && ((endpoint = leftEnds[leftEndIndex]).Endpoint.prev.precedes(n)))
+ {
+ LinkedList<T> view = endpoint.View;
+ view.offset = view.offset - removed;//TODO: extract offset.Value?
+ view.size += removed;
+ leftEndIndex++;
+ }
+ while (rightEndIndex < viewCount && (endpoint = rightEnds[rightEndIndex]).Endpoint.precedes(n))
+ {
+ LinkedList<T> view = endpoint.View;
+ view.size -= removed;
+ rightEndIndex++;
+ }
+ }
+ if (viewCount > 0)
+ {
+ Position endpoint;
+ while (leftEndIndex2 < viewCount && (endpoint = leftEnds[leftEndIndex2]).Endpoint.prev.precedes(n))
+ leftEndIndex2++;
+ while (rightEndIndex2 < viewCount && (endpoint = rightEnds[rightEndIndex2]).Endpoint.next.precedes(n))
+ rightEndIndex2++;
+ }
+ }
+ /// <summary>
+ /// To be called with n pointing to the right of each node to be removed in a stretch.
+ /// And at the endsentinel.
+ ///
+ /// Update offset of a view whose left endpoint (has not already been handled and) is n or precedes n.
+ /// I.e. startsentinel precedes n.
+ /// Also update the size as a prelude to handling the right endpoint.
+ ///
+ /// Update size of a view not already handled and whose right endpoint precedes n.
+ /// </summary>
+ /// <param name="removed">The number of nodes left of n to be removed</param>
+ /// <param name="n"></param>
+ internal void updateViewSizesAndCounts(int removed, Node n)
+ {
+ if (viewCount > 0)
+ {
+ Position endpoint;
+ while (leftEndIndex < viewCount && ((endpoint = leftEnds[leftEndIndex]).Endpoint.prev.precedes(n)))
+ {
+ LinkedList<T> view = endpoint.View;
+ view.offset = view.offset - removed; //TODO: fix use of offset
+ view.size += removed;
+ leftEndIndex++;
+ }
+ while (rightEndIndex < viewCount && (endpoint = rightEnds[rightEndIndex]).Endpoint.precedes(n))
+ {
+ LinkedList<T> view = endpoint.View;
+ view.size -= removed;
+ rightEndIndex++;
+ }
+ }
+ }
+ /// <summary>
+ /// To be called with n being the first not-to-be-removed node after a (stretch of) node(s) to be removed.
+ ///
+ /// It will update the startsentinel of views (that have not been handled before and)
+ /// whose startsentinel precedes n, i.e. is to be deleted.
+ ///
+ /// It will update the endsentinel of views (...) whose endsentinel precedes n, i.e. is to be deleted.
+ ///
+ /// PROBLEM: DOESNT WORK AS ORIGINALLY ADVERTISED. WE MUST DO THIS BEFORE WE ACTUALLY REMOVE THE NODES. WHEN THE
+ /// NODES HAVE BEEN REMOVED, THE precedes METHOD WILL NOT WORK!
+ /// </summary>
+ /// <param name="n"></param>
+ /// <param name="newstart"></param>
+ /// <param name="newend"></param>
+ internal void updateSentinels(Node n, Node newstart, Node newend)
+ {
+ if (viewCount > 0)
+ {
+ Position endpoint;
+ while (leftEndIndex2 < viewCount && (endpoint = leftEnds[leftEndIndex2]).Endpoint.prev.precedes(n))
+ {
+ LinkedList<T> view = endpoint.View;
+ view.startsentinel = newstart;
+ leftEndIndex2++;
+ }
+ while (rightEndIndex2 < viewCount && (endpoint = rightEnds[rightEndIndex2]).Endpoint.next.precedes(n))
+ {
+ LinkedList<T> view = endpoint.View;
+ view.endsentinel = newend;
+ rightEndIndex2++;
+ }
+ }
+ }
+#else
+ /// <summary>
+ /// This is to be called with realindex pointing to the first node to be removed after a (stretch of) node that was not removed
+ /// </summary>
+ /// <param name="removed"></param>
+ /// <param name="realindex"></param>
+ internal void skipEndpoints(int removed, int realindex)
+ {
+ if (viewCount > 0)
+ {
+ Position endpoint;
+ while (leftEndIndex < viewCount && (endpoint = leftEnds[leftEndIndex]).Index <= realindex)
+ {
+ LinkedList<T> view = endpoint.View;
+ view.offset = view.offset - removed;
+ view.size += removed;
+ leftEndIndex++;
+ }
+ while (rightEndIndex < viewCount && (endpoint = rightEnds[rightEndIndex]).Index < realindex)
+ {
+ LinkedList<T> view = endpoint.View;
+ view.size -= removed;
+ rightEndIndex++;
+ }
+ }
+ if (viewCount > 0)
+ {
+ Position endpoint;
+ while (leftEndIndex2 < viewCount && (endpoint = leftEnds[leftEndIndex2]).Index <= realindex)
+ leftEndIndex2++;
+ while (rightEndIndex2 < viewCount && (endpoint = rightEnds[rightEndIndex2]).Index < realindex - 1)
+ rightEndIndex2++;
+ }
+ }
+ internal void updateViewSizesAndCounts(int removed, int realindex)
+ {
+ if (viewCount > 0)
+ {
+ Position endpoint;
+ while (leftEndIndex < viewCount && (endpoint = leftEnds[leftEndIndex]).Index <= realindex)
+ {
+ LinkedList<T> view = endpoint.View;
+ view.offset = view.Offset - removed;
+ view.size += removed;
+ leftEndIndex++;
+ }
+ while (rightEndIndex < viewCount && (endpoint = rightEnds[rightEndIndex]).Index < realindex)
+ {
+ LinkedList<T> view = endpoint.View;
+ view.size -= removed;
+ rightEndIndex++;
+ }
+ }
+ }
+ internal void updateSentinels(int realindex, Node newstart, Node newend)
+ {
+ if (viewCount > 0)
+ {
+ Position endpoint;
+ while (leftEndIndex2 < viewCount && (endpoint = leftEnds[leftEndIndex2]).Index <= realindex)
+ {
+ LinkedList<T> view = endpoint.View;
+ view.startsentinel = newstart;
+ leftEndIndex2++;
+ }
+ while (rightEndIndex2 < viewCount && (endpoint = rightEnds[rightEndIndex2]).Index < realindex - 1)
+ {
+ LinkedList<T> view = endpoint.View;
+ view.endsentinel = newend;
+ rightEndIndex2++;
+ }
+ }
+ }
+#endif
+ }
+ #endregion
+
+ #region Range nested class
+
+ class Range : DirectedCollectionValueBase<T>, IDirectedCollectionValue<T>
+ {
+ int start, count, rangestamp;
+ Node startnode, endnode;
+
+ LinkedList<T> list;
+
+ bool forwards;
+
+
+ internal Range(LinkedList<T> list, int start, int count, bool forwards)
+ {
+ this.list = list; this.rangestamp = list.underlying != null ? list.underlying.stamp : list.stamp;
+ this.start = start; this.count = count; this.forwards = forwards;
+ if (count > 0)
+ {
+ startnode = list.get(start);
+ endnode = list.get(start + count - 1);
+ }
+ }
+
+ public override bool IsEmpty { get { list.modifycheck(rangestamp); return count == 0; } }
+
+ [Tested]
+ public override int Count { [Tested]get { list.modifycheck(rangestamp); return count; } }
+
+
+ public override Speed CountSpeed { get { list.modifycheck(rangestamp); return Speed.Constant; } }
+
+
+ public override T Choose()
+ {
+ list.modifycheck(rangestamp);
+ if (count > 0) return startnode.item;
+ throw new NoSuchItemException();
+ }
+
+
+ [Tested]
+ public override SCG.IEnumerator<T> GetEnumerator()
+ {
+ int togo = count;
+
+ list.modifycheck(rangestamp);
+ if (togo == 0)
+ yield break;
+
+ Node cursor = forwards ? startnode : endnode;
+
+ yield return cursor.item;
+ while (--togo > 0)
+ {
+ cursor = forwards ? cursor.next : cursor.prev;
+ list.modifycheck(rangestamp);
+ yield return cursor.item;
+ }
+ }
+
+
+ [Tested]
+ public override IDirectedCollectionValue<T> Backwards()
+ {
+ list.modifycheck(rangestamp);
+
+ Range b = (Range)MemberwiseClone();
+
+ b.forwards = !forwards;
+ return b;
+ }
+
+
+ [Tested]
+ IDirectedEnumerable<T> IDirectedEnumerable<T>.Backwards() { return Backwards(); }
+
+
+ [Tested]
+ public override EnumerationDirection Direction
+ {
+ [Tested]
+ get
+ { return forwards ? EnumerationDirection.Forwards : EnumerationDirection.Backwards; }
+ }
+ }
+
+
+ #endregion
+
+ #region IDisposable Members
+
+ /// <summary>
+ /// Invalidate this list. If a view, just invalidate the view.
+ /// If not a view, invalidate the list and all views on it.
+ /// </summary>
+ public virtual void Dispose()
+ {
+ Dispose(false);
+ }
+
+ void Dispose(bool disposingUnderlying)
+ {
+ if (isValid)
+ {
+ if (underlying != null)
+ {
+ isValid = false;
+ if (!disposingUnderlying)
+ views.Remove(myWeakReference);
+ endsentinel = null;
+ startsentinel = null;
+ underlying = null;
+ views = null;
+ myWeakReference = null;
+ }
+ else
+ {
+ //isValid = false;
+ //endsentinel = null;
+ //startsentinel = null;
+ foreach (LinkedList<T> view in views)
+ view.Dispose(true);
+ //views = null;
+ Clear();
+ }
+ }
+ }
+
+ #endregion IDisposable stuff
+
+ #region IList<T> Members
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if this list is empty.</exception>
+ /// <value>The first item in this list.</value>
+ [Tested]
+ public virtual T First
+ {
+ [Tested]
+ get
+ {
+ validitycheck();
+ if (size == 0)
+ throw new NoSuchItemException();
+ return startsentinel.next.item;
+ }
+ }
+
+
+ /// <summary>
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if this list is empty.</exception>
+ /// <value>The last item in this list.</value>
+ [Tested]
+ public virtual T Last
+ {
+ [Tested]
+ get
+ {
+ validitycheck();
+ if (size == 0)
+ throw new NoSuchItemException();
+ return endsentinel.prev.item;
+ }
+ }
+
+ /// <summary>
+ /// Since <code>Add(T item)</code> always add at the end of the list,
+ /// this describes if list has FIFO or LIFO semantics.
+ /// </summary>
+ /// <value>True if the <code>Remove()</code> operation removes from the
+ /// start of the list, false if it removes from the end. THe default for a new linked list is true.</value>
+ [Tested]
+ public virtual bool FIFO
+ {
+ [Tested]
+ get { validitycheck(); return fIFO; }
+ [Tested]
+ set { updatecheck(); fIFO = value; }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ public virtual bool IsFixedSize
+ {
+ get { validitycheck(); return false; }
+ }
+
+ /// <summary>
+ /// On this list, this indexer is read/write.
+ /// <exception cref="IndexOutOfRangeException"/> if i is negative or
+ /// &gt;= the size of the collection.
+ /// </summary>
+ /// <value>The i'th item of this list.</value>
+ /// <param name="index">The index of the item to fetch or store.</param>
+ [Tested]
+ public virtual T this[int index]
+ {
+ [Tested]
+ get { validitycheck(); return get(index).item; }
+ [Tested]
+ set
+ {
+ updatecheck();
+ Node n = get(index);
+ //
+ T item = n.item;
+#if HASHINDEX
+
+ if (itemequalityComparer.Equals(value, item))
+ {
+ n.item = value;
+ dict.Update(value, n);
+ }
+ else if (!dict.FindOrAdd(value, ref n))
+ {
+ dict.Remove(item);
+ n.item = value;
+ }
+ else
+ throw new ArgumentException("Item already in indexed list");
+#else
+ n.item = value;
+#endif
+ (underlying ?? this).raiseForSetThis(index, value, item);
+ }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public virtual Speed IndexingSpeed { get { return Speed.Linear; } }
+
+ /// <summary>
+ /// Insert an item at a specific index location in this list.
+ /// <exception cref="IndexOutOfRangeException"/> if i is negative or
+ /// &gt; the size of the collection.</summary>
+ /// <param name="i">The index at which to insert.</param>
+ /// <param name="item">The item to insert.</param>
+ [Tested]
+ public virtual void Insert(int i, T item)
+ {
+ updatecheck();
+ insert(i, i == size ? endsentinel : get(i), item);
+ if (ActiveEvents != EventTypeEnum.None)
+ (underlying ?? this).raiseForInsert(i + Offset, item);
+ }
+
+ /// <summary>
+ /// Insert an item at the end of a compatible view, used as a pointer.
+ /// <para>The <code>pointer</code> must be a view on the same list as
+ /// <code>this</code> and the endpoitn of <code>pointer</code> must be
+ /// a valid insertion point of <code>this</code></para>
+ /// </summary>
+ /// <exception cref="IncompatibleViewException">If <code>pointer</code>
+ /// is not a view on the same list as <code>this</code></exception>
+ /// <exception cref="IndexOutOfRangeException"><b>??????</b> if the endpoint of
+ /// <code>pointer</code> is not inside <code>this</code></exception>
+ /// <exception cref="DuplicateNotAllowedException"> if the list has
+ /// <code>AllowsDuplicates==false</code> and the item is
+ /// already in the list.</exception>
+ /// <param name="pointer"></param>
+ /// <param name="item"></param>
+ public void Insert(IList<T> pointer, T item)
+ {
+ updatecheck();
+ if ((pointer == null) || ((pointer.Underlying ?? pointer) != (underlying ?? this)))
+ throw new IncompatibleViewException();
+#warning INEFFICIENT
+ //TODO: make this efficient (the whole point of the method:
+ //Do NOT use Insert, but insert the node at pointer.endsentinel, checking
+ //via the ordering that this is a valid insertion point
+ Insert(pointer.Offset + pointer.Count - Offset, item);
+ }
+
+ /// <summary>
+ /// Insert into this list all items from an enumerable collection starting
+ /// at a particular index.
+ /// <exception cref="IndexOutOfRangeException"/> if i is negative or
+ /// &gt; the size of the collection.
+ /// </summary>
+ /// <param name="i">Index to start inserting at</param>
+ /// <param name="items">Items to insert</param>
+ /// <typeparam name="U"></typeparam>
+ [Tested]
+ public virtual void InsertAll<U>(int i, SCG.IEnumerable<U> items) where U : T
+ {
+ insertAll(i, items, true);
+ }
+
+ void insertAll<U>(int i, SCG.IEnumerable<U> items, bool insertion) where U : T
+ {
+ updatecheck();
+ Node succ, node, pred;
+ int count = 0;
+ succ = i == size ? endsentinel : get(i);
+ pred = node = succ.prev;
+#if HASHINDEX
+ TagGroup taggroup = null;
+ int taglimit = 0, thetag = 0;
+ taggroup = gettaggroup(node, succ, out thetag, out taglimit);
+ try
+ {
+ foreach (T item in items)
+ {
+ Node tmp = new Node(item, node, null);
+ if (!dict.FindOrAdd(item, ref tmp))
+ {
+ tmp.tag = thetag < taglimit ? ++thetag : thetag;
+ tmp.taggroup = taggroup;
+ node.next = tmp;
+ count++;
+ node = tmp;
+ }
+ else
+ throw new DuplicateNotAllowedException("Item already in indexed list");
+ }
+ }
+ finally
+ {
+ taggroup.count += count;
+ taggroup.first = succ.prev;
+ taggroup.last = node;
+ succ.prev = node;
+ node.next = succ;
+ if (node.tag == node.prev.tag)
+ splittaggroup(taggroup);
+ size += count;
+ if (underlying != null)
+ underlying.size += count;
+ if (count > 0)
+ {
+ fixViewsAfterInsert(succ, pred, count, 0);
+ raiseForInsertAll(pred, i, count, insertion);
+ }
+ }
+#else
+ foreach (T item in items)
+ {
+ Node tmp = new Node(item, node, null);
+ node.next = tmp;
+ count++;
+ node = tmp;
+ }
+ if (count == 0)
+ return;
+ succ.prev = node;
+ node.next = succ;
+ size += count;
+ if (underlying != null)
+ underlying.size += count;
+ if (count > 0)
+ {
+ fixViewsAfterInsert(succ, pred, count, offset + i);
+ raiseForInsertAll(pred, i, count, insertion);
+ }
+#endif
+ }
+
+ private void raiseForInsertAll(Node node, int i, int added, bool insertion)
+ {
+ if (ActiveEvents != 0)
+ {
+ int index = Offset + i;
+ if ((ActiveEvents & (EventTypeEnum.Added | EventTypeEnum.Inserted)) != 0)
+ for (int j = index; j < index + added; j++)
+ {
+#warning must we check stamps here?
+ node = node.next;
+ T item = node.item;
+ if (insertion) raiseItemInserted(item, j);
+ raiseItemsAdded(item, 1);
+ }
+ raiseCollectionChanged();
+ }
+ }
+
+ /// <summary>
+ /// Insert an item at the front of this list.
+ /// </summary>
+ /// <param name="item">The item to insert.</param>
+ [Tested]
+ public virtual void InsertFirst(T item)
+ {
+ updatecheck();
+ insert(0, startsentinel.next, item);
+ if (ActiveEvents != EventTypeEnum.None)
+ (underlying ?? this).raiseForInsert(0 + Offset, item);
+ }
+
+ /// <summary>
+ /// Insert an item at the back of this list.
+ /// </summary>
+ /// <param name="item">The item to insert.</param>
+ [Tested]
+ public virtual void InsertLast(T item)
+ {
+ updatecheck();
+ insert(size, endsentinel, item);
+ if (ActiveEvents != EventTypeEnum.None)
+ (underlying ?? this).raiseForInsert(size - 1 + Offset, item);
+ }
+
+ /// <summary>
+ /// Create a new list consisting of the results of mapping all items of this
+ /// list.
+ /// </summary>
+ /// <param name="mapper">The delegate definging the map.</param>
+ /// <returns>The new list.</returns>
+ [Tested]
+ public IList<V> Map<V>(Fun<T, V> mapper)
+ {
+ validitycheck();
+
+ LinkedList<V> retval = new LinkedList<V>();
+ return map<V>(mapper, retval);
+ }
+
+ /// <summary>
+ /// Create a new list consisting of the results of mapping all items of this
+ /// list. The new list will use a specified equalityComparer for the item type.
+ /// </summary>
+ /// <typeparam name="V">The type of items of the new list</typeparam>
+ /// <param name="mapper">The delegate defining the map.</param>
+ /// <param name="equalityComparer">The equalityComparer to use for the new list</param>
+ /// <returns>The new list.</returns>
+ public IList<V> Map<V>(Fun<T, V> mapper, SCG.IEqualityComparer<V> equalityComparer)
+ {
+ validitycheck();
+
+ LinkedList<V> retval = new LinkedList<V>(equalityComparer);
+ return map<V>(mapper, retval);
+ }
+
+ private IList<V> map<V>(Fun<T, V> mapper, LinkedList<V> retval)
+ {
+ if (size == 0)
+ return retval;
+ int stamp = this.stamp;
+ Node cursor = startsentinel.next;
+ LinkedList<V>.Node mcursor = retval.startsentinel;
+
+#if HASHINDEX
+ double tagdelta = int.MaxValue / (size + 1.0);
+ int count = 1;
+ LinkedList<V>.TagGroup taggroup = null;
+ taggroup = new LinkedList<V>.TagGroup();
+ retval.taggroups = 1;
+ taggroup.count = size;
+#endif
+ while (cursor != endsentinel)
+ {
+ V v = mapper(cursor.item);
+ modifycheck(stamp);
+ mcursor.next = new LinkedList<V>.Node(v, mcursor, null);
+ cursor = cursor.next;
+ mcursor = mcursor.next;
+#if HASHINDEX
+ retval.dict.Add(v, mcursor);
+ mcursor.taggroup = taggroup;
+ mcursor.tag = (int)(tagdelta * count++);
+#endif
+ }
+
+ retval.endsentinel.prev = mcursor;
+ mcursor.next = retval.endsentinel;
+ retval.size = size;
+ return retval;
+ }
+
+ /// <summary>
+ /// Remove one item from the list: from the front if <code>FIFO</code>
+ /// is true, else from the back.
+ /// <exception cref="NoSuchItemException"/> if this list is empty.
+ /// </summary>
+ /// <returns>The removed item.</returns>
+ [Tested]
+ public virtual T Remove()
+ {
+ updatecheck();
+ if (size == 0)
+ throw new NoSuchItemException("List is empty");
+ T item = fIFO ? remove(startsentinel.next, 0) : remove(endsentinel.prev, size - 1);
+#if HASHINDEX
+ dict.Remove(item);
+#endif
+ (underlying ?? this).raiseForRemove(item);
+ return item;
+ }
+
+ /// <summary>
+ /// Remove one item from the front of the list.
+ /// <exception cref="NoSuchItemException"/> if this list is empty.
+ /// </summary>
+ /// <returns>The removed item.</returns>
+ [Tested]
+ public virtual T RemoveFirst()
+ {
+ updatecheck();
+ if (size == 0)
+ throw new NoSuchItemException("List is empty");
+
+ T item = remove(startsentinel.next, 0);
+#if HASHINDEX
+ dict.Remove(item);
+#endif
+ if (ActiveEvents != EventTypeEnum.None)
+ (underlying ?? this).raiseForRemoveAt(Offset, item);
+ return item;
+ }
+
+ /// <summary>
+ /// Remove one item from the back of the list.
+ /// <exception cref="NoSuchItemException"/> if this list is empty.
+ /// </summary>
+ /// <returns>The removed item.</returns>
+ [Tested]
+ public virtual T RemoveLast()
+ {
+ updatecheck();
+ if (size == 0)
+ throw new NoSuchItemException("List is empty");
+
+ T item = remove(endsentinel.prev, size - 1);
+#if HASHINDEX
+ dict.Remove(item);
+#endif
+ if (ActiveEvents != EventTypeEnum.None)
+ (underlying ?? this).raiseForRemoveAt(size + Offset, item);
+ return item;
+ }
+
+ /// <summary>
+ /// Create a list view on this list.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException"> if the start or count is negative</exception>
+ /// <exception cref="ArgumentException"> if the range does not fit within list.</exception>
+ /// <param name="start">The index in this list of the start of the view.</param>
+ /// <param name="count">The size of the view.</param>
+ /// <returns>The new list view.</returns>
+ [Tested]
+ public virtual IList<T> View(int start, int count)
+ {
+ checkRange(start, count);
+ validitycheck();
+ if (views == null)
+ views = new WeakViewList<LinkedList<T>>();
+ LinkedList<T> retval = (LinkedList<T>)MemberwiseClone();
+ retval.underlying = underlying != null ? underlying : this;
+ retval.offset = offset + start;
+ retval.size = count;
+ getPair(start - 1, start + count, out retval.startsentinel, out retval.endsentinel,
+ new int[] { -1, size }, new Node[] { startsentinel, endsentinel });
+ //retval.startsentinel = start == 0 ? startsentinel : get(start - 1);
+ //retval.endsentinel = start + count == size ? endsentinel : get(start + count);
+
+ //TODO: for the purpose of Dispose, we need to retain a ref to the node
+ retval.myWeakReference = views.Add(retval);
+ return retval;
+ }
+
+ /// <summary>
+ /// Create a list view on this list containing the (first) occurrence of a particular item.
+ /// </summary>
+ /// <exception cref="ArgumentException"> if the item is not in this list.</exception>
+ /// <param name="item">The item to find.</param>
+ /// <returns>The new list view.</returns>
+ public virtual IList<T> ViewOf(T item)
+ {
+#if HASHINDEX
+ Node n;
+ validitycheck();
+ if (!contains(item, out n))
+ return null;
+ LinkedList<T> retval = (LinkedList<T>)MemberwiseClone();
+ retval.underlying = underlying != null ? underlying : this;
+ retval.offset = null;
+ retval.startsentinel = n.prev;
+ retval.endsentinel = n.next;
+ retval.size = 1;
+ return retval;
+#else
+ int index = 0;
+ Node n = startsentinel.next;
+ if (!find(item, ref n, ref index))
+ return null;
+ //TODO: optimize with getpair!
+ return View(index, 1);
+#endif
+ }
+
+ /// <summary>
+ /// Create a list view on this list containing the last occurrence of a particular item.
+ /// <exception cref="ArgumentException"/> if the item is not in this list.
+ /// </summary>
+ /// <param name="item">The item to find.</param>
+ /// <returns>The new list view.</returns>
+ public virtual IList<T> LastViewOf(T item)
+ {
+#if HASHINDEX
+ return ViewOf(item);
+#else
+ int index = size - 1;
+ Node n = endsentinel.prev;
+ if (!dnif(item, ref n, ref index))
+ return null;
+ return View(index, 1);
+#endif
+ }
+
+ /// <summary>
+ /// Null if this list is not a view.
+ /// </summary>
+ /// <value>Underlying list for view.</value>
+ [Tested]
+ public virtual IList<T> Underlying { [Tested]get { validitycheck(); return underlying; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public virtual bool IsValid { get { return isValid; } }
+
+ /// <summary>
+ /// </summary>
+ /// <value>Offset for this list view or 0 for a underlying list.</value>
+ [Tested]
+ public virtual int Offset
+ {
+ [Tested]
+ get
+ {
+ validitycheck();
+#if HASHINDEX
+ if (offset == null && underlying != null)
+ {
+ //TODO: search from both ends simultaneously!
+ Node n = underlying.startsentinel;
+ int i = 0;
+ while (n != startsentinel) { n = n.next; i++; }
+ offset = i;
+ }
+#endif
+ return (int)offset;
+ }
+ }
+
+ /// <summary>
+ /// Slide this list view along the underlying list.
+ /// </summary>
+ /// <exception cref="NotAViewException"> if this list is not a view.</exception>
+ /// <exception cref="ArgumentOutOfRangeException"> if the operation
+ /// would bring either end of the view outside the underlying list.</exception>
+ /// <param name="offset">The signed amount to slide: positive to slide
+ /// towards the end.</param>
+ [Tested]
+ public IList<T> Slide(int offset)
+ {
+ if (!TrySlide(offset, size))
+ throw new ArgumentOutOfRangeException();
+ return this;
+ }
+
+ //TODO: more test cases
+ /// <summary>
+ /// Slide this list view along the underlying list, perhaps changing its size.
+ /// </summary>
+ /// <exception cref="NotAViewException"> if this list is not a view.</exception>
+ /// <exception cref="ArgumentOutOfRangeException"> if the operation
+ /// would bring either end of the view outside the underlying list.</exception>
+ /// <param name="offset">The signed amount to slide: positive to slide
+ /// towards the end.</param>
+ /// <param name="size">The new size of the view.</param>
+ public IList<T> Slide(int offset, int size)
+ {
+ if (!TrySlide(offset, size))
+ throw new ArgumentOutOfRangeException();
+ return this;
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="offset"></param>
+ /// <returns></returns>
+ public virtual bool TrySlide(int offset) { return TrySlide(offset, size); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="offset"></param>
+ /// <param name="size"></param>
+ /// <returns></returns>
+ public virtual bool TrySlide(int offset, int size)
+ {
+ updatecheck();
+ if (underlying == null)
+ throw new NotAViewException("List not a view");
+
+#pragma warning disable 472
+ if (this.offset == null) //Note: only possible with HASHINDEX
+#pragma warning restore 472
+ {
+#pragma warning disable 162
+ try
+ {
+ getPair(offset - 1, offset + size, out startsentinel, out endsentinel,
+ new int[] { -1, this.size }, new Node[] { startsentinel, endsentinel });
+ //TODO: maybe-update offset field
+ }
+ catch (NullReferenceException)
+ {
+ return false;
+ }
+#pragma warning restore 162
+ }
+ else
+ {
+ if (offset + this.offset < 0 || offset + this.offset + size > underlying.size)
+ return false;
+ int oldoffset = (int)(this.offset);
+ getPair(offset - 1, offset + size, out startsentinel, out endsentinel,
+ new int[] { -oldoffset - 1, -1, this.size, underlying.size - oldoffset },
+ new Node[] { underlying.startsentinel, startsentinel, endsentinel, underlying.endsentinel });
+ }
+ this.size = size;
+ this.offset += offset;
+ return true;
+ }
+
+
+ //TODO: improve the complexity of the implementation
+ /// <summary>
+ ///
+ /// <para>Returns null if <code>otherView</code> is strictly to the left of this view</para>
+ /// </summary>
+ /// <param name="otherView"></param>
+ /// <exception cref="IncompatibleViewException">If otherView does not have the same underlying list as this</exception>
+ /// <returns></returns>
+ public virtual IList<T> Span(IList<T> otherView)
+ {
+ if ((otherView == null) || ((otherView.Underlying ?? otherView) != (underlying ?? this)))
+ throw new IncompatibleViewException();
+ if (otherView.Offset + otherView.Count - Offset < 0)
+ return null;
+ return (underlying ?? this).View(Offset, otherView.Offset + otherView.Count - Offset);
+ }
+
+
+ //Question: should we swap items or move nodes around?
+ //The first seems much more efficient unless the items are value types
+ //with a large memory footprint.
+ //(Swapping will do count*3/2 T assignments, linking around will do
+ // 4*count ref assignments; note that ref assignments are more expensive
+ //than copying non-ref bits)
+ /// <summary>
+ /// Reverse the list so the items are in the opposite sequence order.
+ /// </summary>
+ [Tested]
+ public virtual void Reverse()
+ {
+ updatecheck();
+ if (size == 0)
+ return;
+
+ Position[] positions = null;
+ int poslow = 0, poshigh = 0;
+ if (views != null)
+ {
+ CircularQueue<Position> _positions = null;
+ foreach (LinkedList<T> view in views)
+ {
+ if (view != this)
+ {
+ switch (viewPosition(view))
+ {
+ case MutualViewPosition.ContainedIn:
+ (_positions ?? (_positions = new CircularQueue<Position>())).Enqueue(new Position(view, true));
+ _positions.Enqueue(new Position(view, false));
+ break;
+ case MutualViewPosition.Overlapping:
+ view.Dispose();
+ break;
+ case MutualViewPosition.Contains:
+ case MutualViewPosition.NonOverlapping:
+ break;
+ }
+ }
+ }
+ if (_positions != null)
+ {
+ positions = _positions.ToArray();
+ Sorting.IntroSort<Position>(positions, 0, positions.Length, PositionComparer.Default);
+ poshigh = positions.Length - 1;
+ }
+ }
+
+ Node a = get(0), b = get(size - 1);
+ for (int i = 0; i < size / 2; i++)
+ {
+ T swap;
+ swap = a.item; a.item = b.item; b.item = swap;
+#if HASHINDEX
+ dict[a.item] = a; dict[b.item] = b;
+#endif
+ if (positions != null)
+ mirrorViewSentinelsForReverse(positions, ref poslow, ref poshigh, a, b, i);
+ a = a.next; b = b.prev;
+ }
+ if (positions != null && size % 2 != 0)
+ mirrorViewSentinelsForReverse(positions, ref poslow, ref poshigh, a, b, size / 2);
+ (underlying ?? this).raiseCollectionChanged();
+ }
+
+ private void mirrorViewSentinelsForReverse(Position[] positions, ref int poslow, ref int poshigh, Node a, Node b, int i)
+ {
+#if HASHINDEX
+ int? aindex = offset + i, bindex = offset + size - 1 - i;
+#else
+ int aindex = offset + i, bindex = offset + size - 1 - i;
+#endif
+ Position pos;
+#if HASHINDEX
+ while (poslow <= poshigh && (pos = positions[poslow]).Endpoint == a)
+#else
+ while (poslow <= poshigh && (pos = positions[poslow]).Index == aindex)
+#endif
+ {
+ //TODO: Note: in the case og hashed linked list, if this.offset == null, but pos.View.offset!=null
+ //we may at this point compute this.offset and non-null values of aindex and bindex
+ if (pos.Left)
+ pos.View.endsentinel = b.next;
+ else
+ {
+ pos.View.startsentinel = b.prev;
+ pos.View.offset = bindex;
+ }
+ poslow++;
+ }
+#if HASHINDEX
+ while (poslow < poshigh && (pos = positions[poshigh]).Endpoint == b)
+#else
+ while (poslow < poshigh && (pos = positions[poshigh]).Index == bindex)
+#endif
+ {
+ if (pos.Left)
+ pos.View.endsentinel = a.next;
+ else
+ {
+ pos.View.startsentinel = a.prev;
+ pos.View.offset = aindex;
+ }
+ poshigh--;
+ }
+ }
+
+ /// <summary>
+ /// Check if this list is sorted according to the default sorting order
+ /// for the item type T, as defined by the <see cref="T:C5.Comparer`1"/> class
+ /// </summary>
+ /// <exception cref="NotComparableException">if T is not comparable</exception>
+ /// <returns>True if the list is sorted, else false.</returns>
+ public bool IsSorted() { return IsSorted(Comparer<T>.Default); }
+
+ /// <summary>
+ /// Check if this list is sorted according to a specific sorting order.
+ /// </summary>
+ /// <param name="c">The comparer defining the sorting order.</param>
+ /// <returns>True if the list is sorted, else false.</returns>
+ [Tested]
+ public virtual bool IsSorted(SCG.IComparer<T> c)
+ {
+ validitycheck();
+ if (size <= 1)
+ return true;
+
+ Node node = startsentinel.next;
+ T prevItem = node.item;
+
+ node = node.next;
+ while (node != endsentinel)
+ {
+ if (c.Compare(prevItem, node.item) > 0)
+ return false;
+ else
+ {
+ prevItem = node.item;
+ node = node.next;
+ }
+ }
+
+ return true;
+ }
+
+ /// <summary>
+ /// Sort the items of the list according to the default sorting order
+ /// for the item type T, as defined by the Comparer[T] class.
+ /// (<see cref="T:C5.Comparer`1"/>).
+ /// The sorting is stable.
+ /// </summary>
+ /// <exception cref="InvalidOperationException">if T is not comparable</exception>
+ public virtual void Sort() { Sort(Comparer<T>.Default); }
+
+ // Sort the linked list using mergesort
+ /// <summary>
+ /// Sort the items of the list according to a specific sorting order.
+ /// The sorting is stable.
+ /// </summary>
+ /// <param name="c">The comparer defining the sorting order.</param>
+ [Tested]
+ public virtual void Sort(SCG.IComparer<T> c)
+ {
+ updatecheck();
+ if (size == 0)
+ return;
+ disposeOverlappingViews(false);
+#if HASHINDEX
+ if (underlying != null)
+ {
+ Node cursor = startsentinel.next;
+ while (cursor != endsentinel)
+ {
+ cursor.taggroup.count--;
+ cursor = cursor.next;
+ }
+ }
+#endif
+ // Build a linked list of non-empty runs.
+ // The prev field in first node of a run points to next run's first node
+ Node runTail = startsentinel.next;
+ Node prevNode = startsentinel.next;
+
+ endsentinel.prev.next = null;
+ while (prevNode != null)
+ {
+ Node node = prevNode.next;
+
+ while (node != null && c.Compare(prevNode.item, node.item) <= 0)
+ {
+ prevNode = node;
+ node = prevNode.next;
+ }
+
+ // Completed a run; prevNode is the last node of that run
+ prevNode.next = null; // Finish the run
+ runTail.prev = node; // Link it into the chain of runs
+ runTail = node;
+ if (c.Compare(endsentinel.prev.item, prevNode.item) <= 0)
+ endsentinel.prev = prevNode; // Update last pointer to point to largest
+
+ prevNode = node; // Start a new run
+ }
+
+ // Repeatedly merge runs two and two, until only one run remains
+ while (startsentinel.next.prev != null)
+ {
+ Node run = startsentinel.next;
+ Node newRunTail = null;
+
+ while (run != null && run.prev != null)
+ { // At least two runs, merge
+ Node nextRun = run.prev.prev;
+ Node newrun = mergeRuns(run, run.prev, c);
+
+ if (newRunTail != null)
+ newRunTail.prev = newrun;
+ else
+ startsentinel.next = newrun;
+
+ newRunTail = newrun;
+ run = nextRun;
+ }
+
+ if (run != null) // Add the last run, if any
+ newRunTail.prev = run;
+ }
+
+ endsentinel.prev.next = endsentinel;
+ startsentinel.next.prev = startsentinel;
+
+ //assert invariant();
+ //assert isSorted();
+#if HASHINDEX
+ {
+ Node cursor = startsentinel.next, end = endsentinel;
+ int tag, taglimit;
+ TagGroup t = gettaggroup(startsentinel, endsentinel, out tag, out taglimit);
+ int tagdelta = taglimit / (size + 1) - tag / (size + 1);
+ tagdelta = tagdelta == 0 ? 1 : tagdelta;
+ if (underlying == null)
+ taggroups = 1;
+ while (cursor != end)
+ {
+ tag = tag + tagdelta > taglimit ? taglimit : tag + tagdelta;
+ cursor.tag = tag;
+ t.count++;
+ cursor = cursor.next;
+ }
+ if (tag == taglimit)
+ splittaggroup(t);
+ }
+#endif
+ (underlying ?? this).raiseCollectionChanged();
+ }
+
+ private static Node mergeRuns(Node run1, Node run2, SCG.IComparer<T> c)
+ {
+ //assert run1 != null && run2 != null;
+ Node prev;
+ bool prev1; // is prev from run1?
+
+ if (c.Compare(run1.item, run2.item) <= 0)
+ {
+ prev = run1;
+ prev1 = true;
+ run1 = run1.next;
+ }
+ else
+ {
+ prev = run2;
+ prev1 = false;
+ run2 = run2.next;
+ }
+
+ Node start = prev;
+
+ //assert start != null;
+ start.prev = null;
+ while (run1 != null && run2 != null)
+ {
+ if (prev1)
+ {
+ //assert prev.next == run1;
+ //Comparable run2item = (Comparable)run2.item;
+ while (run1 != null && c.Compare(run2.item, run1.item) >= 0)
+ {
+ prev = run1;
+ run1 = prev.next;
+ }
+
+ if (run1 != null)
+ { // prev.item <= run2.item < run1.item; insert run2
+ prev.next = run2;
+ run2.prev = prev;
+ prev = run2;
+ run2 = prev.next;
+ prev1 = false;
+ }
+ }
+ else
+ {
+ //assert prev.next == run2;
+ //Comparable run1item = (Comparable)run1.item;
+ while (run2 != null && c.Compare(run1.item, run2.item) > 0)
+ {
+ prev = run2;
+ run2 = prev.next;
+ }
+
+ if (run2 != null)
+ { // prev.item < run1.item <= run2.item; insert run1
+ prev.next = run1;
+ run1.prev = prev;
+ prev = run1;
+ run1 = prev.next;
+ prev1 = true;
+ }
+ }
+ }
+
+ //assert !(run1 != null && prev1) && !(run2 != null && !prev1);
+ if (run1 != null)
+ { // last run2 < all of run1; attach run1 at end
+ prev.next = run1;
+ run1.prev = prev;
+ }
+ else if (run2 != null)
+ { // last run1
+ prev.next = run2;
+ run2.prev = prev;
+ }
+
+ return start;
+ }
+
+ /// <summary>
+ /// Randomly shuffle the items of this list.
+ /// <para>Will invalidate overlapping views???</para>
+ /// </summary>
+ public virtual void Shuffle() { Shuffle(new C5Random()); }
+
+
+ /// <summary>
+ /// Shuffle the items of this list according to a specific random source.
+ /// <para>Will invalidate overlapping views???</para>
+ /// </summary>
+ /// <param name="rnd">The random source.</param>
+ public virtual void Shuffle(Random rnd)
+ {
+ updatecheck();
+ if (size == 0)
+ return;
+ disposeOverlappingViews(false);
+ ArrayList<T> a = new ArrayList<T>();
+ a.AddAll(this);
+ a.Shuffle(rnd);
+ Node cursor = startsentinel.next;
+ int j = 0;
+ while (cursor != endsentinel)
+ {
+ cursor.item = a[j++];
+#if HASHINDEX
+ dict[cursor.item] = cursor;
+#endif
+ cursor = cursor.next;
+ }
+ (underlying ?? this).raiseCollectionChanged();
+ }
+
+ #endregion
+
+ #region IIndexed<T> Members
+
+ /// <summary>
+ /// <exception cref="IndexOutOfRangeException"/>.
+ /// </summary>
+ /// <value>The directed collection of items in a specific index interval.</value>
+ /// <param name="start">The low index of the interval (inclusive).</param>
+ /// <param name="count">The size of the range.</param>
+ [Tested]
+ public IDirectedCollectionValue<T> this[int start, int count]
+ {
+ [Tested]
+ get
+ {
+ validitycheck();
+ checkRange(start, count);
+ return new Range(this, start, count, true);
+ }
+ }
+
+ /// <summary>
+ /// Searches for an item in the list going forwrds from the start.
+ /// </summary>
+ /// <param name="item">Item to search for.</param>
+ /// <returns>Index of item from start.</returns>
+ [Tested]
+ public virtual int IndexOf(T item)
+ {
+ validitycheck();
+ Node node;
+#if HASHINDEX
+ if (!dict.Find(item, out node) || !insideview(node))
+ return ~size;
+#endif
+ node = startsentinel.next;
+ int index = 0;
+ if (find(item, ref node, ref index))
+ return index;
+ else
+ return ~size;
+ }
+
+ /// <summary>
+ /// Searches for an item in the list going backwords from the end.
+ /// </summary>
+ /// <param name="item">Item to search for.</param>
+ /// <returns>Index of of item from the end.</returns>
+ [Tested]
+ public virtual int LastIndexOf(T item)
+ {
+#if HASHINDEX
+ return IndexOf(item);
+#else
+ validitycheck();
+
+ Node node = endsentinel.prev;
+ int index = size - 1;
+
+ if (dnif(item, ref node, ref index))
+ return index;
+ else
+ return ~size;
+#endif
+ }
+
+ /// <summary>
+ /// Remove the item at a specific position of the list.
+ /// <exception cref="IndexOutOfRangeException"/> if i is negative or
+ /// &gt;= the size of the collection.
+ /// </summary>
+ /// <param name="i">The index of the item to remove.</param>
+ /// <returns>The removed item.</returns>
+ [Tested]
+ public virtual T RemoveAt(int i)
+ {
+ updatecheck();
+ T retval = remove(get(i), i);
+#if HASHINDEX
+ dict.Remove(retval);
+#endif
+ if (ActiveEvents != EventTypeEnum.None)
+ (underlying ?? this).raiseForRemoveAt(Offset + i, retval);
+ return retval;
+ }
+
+ /// <summary>
+ /// Remove all items in an index interval.
+ /// <exception cref="IndexOutOfRangeException"/>???.
+ /// </summary>
+ /// <param name="start">The index of the first item to remove.</param>
+ /// <param name="count">The number of items to remove.</param>
+ [Tested]
+ public virtual void RemoveInterval(int start, int count)
+ {
+#if HASHINDEX
+ updatecheck();
+ checkRange(start, count);
+ if (count == 0)
+ return;
+
+ View(start, count).Clear();
+#else
+ //Note: this is really almost equaivalent to Clear on a view
+ updatecheck();
+ checkRange(start, count);
+ if (count == 0)
+ return;
+
+ //for small count: optimize
+ //use an optimal get(int i, int j, ref Node ni, ref Node nj)?
+ Node a = get(start), b = get(start + count - 1);
+ fixViewsBeforeRemove(start, count, a, b);
+ a.prev.next = b.next;
+ b.next.prev = a.prev;
+ if (underlying != null)
+ underlying.size -= count;
+
+ size -= count;
+ if (ActiveEvents != EventTypeEnum.None)
+ (underlying ?? this).raiseForRemoveInterval(start + Offset, count);
+#endif
+ }
+
+ void raiseForRemoveInterval(int start, int count)
+ {
+ if (ActiveEvents != 0)
+ {
+ raiseCollectionCleared(size == 0, count, start);
+ raiseCollectionChanged();
+ }
+ }
+ #endregion
+
+ #region ISequenced<T> Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ [Tested]
+ public override int GetSequencedHashCode() { validitycheck(); return base.GetSequencedHashCode(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="that"></param>
+ /// <returns></returns>
+ [Tested]
+ public override bool SequencedEquals(ISequenced<T> that) { validitycheck(); return base.SequencedEquals(that); }
+
+ #endregion
+
+ #region IDirectedCollection<T> Members
+
+ /// <summary>
+ /// Create a collection containing the same items as this collection, but
+ /// whose enumerator will enumerate the items backwards. The new collection
+ /// will become invalid if the original is modified. Method typicaly used as in
+ /// <code>foreach (T x in coll.Backwards()) {...}</code>
+ /// </summary>
+ /// <returns>The backwards collection.</returns>
+ [Tested]
+ public override IDirectedCollectionValue<T> Backwards()
+ { return this[0, size].Backwards(); }
+
+ #endregion
+
+ #region IDirectedEnumerable<T> Members
+
+ [Tested]
+ IDirectedEnumerable<T> IDirectedEnumerable<T>.Backwards() { return Backwards(); }
+
+ #endregion
+
+ #region IEditableCollection<T> Members
+
+ /// <summary>
+ /// The value is symbolic indicating the type of asymptotic complexity
+ /// in terms of the size of this collection (worst-case or amortized as
+ /// relevant).
+ /// </summary>
+ /// <value>Speed.Linear</value>
+ [Tested]
+ public virtual Speed ContainsSpeed
+ {
+ [Tested]
+ get
+ {
+#if HASHINDEX
+ return Speed.Constant ;
+#else
+ return Speed.Linear;
+#endif
+ }
+ }
+
+ /// <summary>
+ /// Performs a check for view validity before calling base.GetUnsequencedHashCode()
+ /// </summary>
+ /// <returns></returns>
+ [Tested]
+ public override int GetUnsequencedHashCode()
+ { validitycheck(); return base.GetUnsequencedHashCode(); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="that"></param>
+ /// <returns></returns>
+ [Tested]
+ public override bool UnsequencedEquals(ICollection<T> that)
+ { validitycheck(); return base.UnsequencedEquals(that); }
+
+ /// <summary>
+ /// Check if this collection contains (an item equivalent to according to the
+ /// itemequalityComparer) a particular value.
+ /// </summary>
+ /// <param name="item">The value to check for.</param>
+ /// <returns>True if the items is in this collection.</returns>
+ [Tested]
+ public virtual bool Contains(T item)
+ {
+ validitycheck();
+ Node node;
+ return contains(item, out node);
+ }
+
+ /// <summary>
+ /// Check if this collection contains an item equivalent according to the
+ /// itemequalityComparer to a particular value. If so, return in the ref argument (a
+ /// binary copy of) the actual value found.
+ /// </summary>
+ /// <param name="item">The value to look for.</param>
+ /// <returns>True if the items is in this collection.</returns>
+ [Tested]
+ public virtual bool Find(ref T item)
+ {
+ validitycheck();
+ Node node;
+ if (contains(item, out node)) { item = node.item; return true; }
+ return false;
+ }
+
+ /// <summary>
+ /// Check if this collection contains an item equivalent according to the
+ /// itemequalityComparer to a particular value. If so, update the item in the collection
+ /// to with a binary copy of the supplied value. Will update a single item.
+ /// </summary>
+ /// <param name="item">Value to update.</param>
+ /// <returns>True if the item was found and hence updated.</returns>
+ [Tested]
+ public virtual bool Update(T item) { T olditem; return Update(item, out olditem); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ /// <param name="olditem"></param>
+ /// <returns></returns>
+ public virtual bool Update(T item, out T olditem)
+ {
+ updatecheck();
+ Node node;
+
+ if (contains(item, out node))
+ {
+ olditem = node.item;
+ node.item = item;
+#if HASHINDEX
+ //Avoid clinging onto a reference to olditem via dict!
+ dict.Update(item, node);
+#endif
+ (underlying ?? this).raiseForUpdate(item, olditem);
+ return true;
+ }
+
+ olditem = default(T);
+ return false;
+ }
+
+ /// <summary>
+ /// Check if this collection contains an item equivalent according to the
+ /// itemequalityComparer to a particular value. If so, return in the ref argument (a
+ /// binary copy of) the actual value found. Else, add the item to the collection.
+ /// </summary>
+ /// <param name="item">The value to look for.</param>
+ /// <returns>True if the item was found (hence not added).</returns>
+ [Tested]
+ public virtual bool FindOrAdd(ref T item)
+ {
+ updatecheck();
+#if HASHINDEX
+ //This is an extended myinsert:
+ Node node = new Node(item);
+ if (!dict.FindOrAdd(item, ref node))
+ {
+ insertNode(true, endsentinel, node);
+ (underlying ?? this).raiseForAdd(item);
+ return false;
+ }
+ if (!insideview(node))
+ throw new ArgumentException("Item alredy in indexed list but outside view");
+ item = node.item;
+ return true;
+#else
+ if (Find(ref item))
+ return true;
+
+ Add(item);
+ return false;
+#endif
+ }
+
+ /// <summary>
+ /// Check if this collection contains an item equivalent according to the
+ /// itemequalityComparer to a particular value. If so, update the item in the collection
+ /// to with a binary copy of the supplied value; else add the value to the collection.
+ /// </summary>
+ /// <param name="item">Value to add or update.</param>
+ /// <returns>True if the item was found and updated (hence not added).</returns>
+ [Tested]
+ public virtual bool UpdateOrAdd(T item) { T olditem; return UpdateOrAdd(item, out olditem); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ /// <param name="olditem"></param>
+ /// <returns></returns>
+ public virtual bool UpdateOrAdd(T item, out T olditem)
+ {
+ updatecheck();
+#if HASHINDEX
+ Node node = new Node(item);
+ //NOTE: it is hard to do this without double access to the dictionary
+ //in the update case
+ if (dict.FindOrAdd(item, ref node))
+ {
+ if (!insideview(node))
+ throw new ArgumentException("Item in indexed list but outside view");
+ olditem = node.item;
+ //Avoid clinging onto a reference to olditem via dict!
+ dict.Update(item, node);
+ node.item = item;
+ (underlying ?? this).raiseForUpdate(item, olditem);
+ return true;
+ }
+ insertNode(true, endsentinel, node);
+ (underlying ?? this).raiseForAdd(item);
+#else
+ if (Update(item, out olditem))
+ return true;
+ Add(item);
+#endif
+ olditem = default(T);
+ return false;
+ }
+
+ /// <summary>
+ /// Remove a particular item from this collection. Since the collection has bag
+ /// semantics only one copy equivalent to the supplied item is removed.
+ /// </summary>
+ /// <param name="item">The value to remove.</param>
+ /// <returns>True if the item was found (and removed).</returns>
+ [Tested]
+ public virtual bool Remove(T item)
+ {
+ updatecheck();
+ int i = 0;
+ Node node;
+#if HASHINDEX
+ if (!dictremove(item, out node))
+#else
+ node = fIFO ? startsentinel.next : endsentinel.prev;
+ if (!(fIFO ? find(item, ref node, ref i) : dnif(item, ref node, ref i)))
+#endif
+ return false;
+ T removeditem = remove(node, i);
+ (underlying ?? this).raiseForRemove(removeditem);
+ return true;
+ }
+
+ /// <summary>
+ /// Remove a particular item from this collection if found (only one copy).
+ /// If an item was removed, report a binary copy of the actual item removed in
+ /// the argument.
+ /// </summary>
+ /// <param name="item">The value to remove on input.</param>
+ /// <param name="removeditem">The value removed.</param>
+ /// <returns>True if the item was found (and removed).</returns>
+ [Tested]
+ public virtual bool Remove(T item, out T removeditem)
+ {
+ updatecheck();
+ int i = 0;
+ Node node;
+#if HASHINDEX
+ if (!dictremove(item, out node))
+#else
+ node = fIFO ? startsentinel.next : endsentinel.prev;
+ if (!(fIFO ? find(item, ref node, ref i) : dnif(item, ref node, ref i)))
+#endif
+ {
+ removeditem = default(T);
+ return false;
+ }
+ removeditem = node.item;
+ remove(node, i);
+ (underlying ?? this).raiseForRemove(removeditem);
+ return true;
+ }
+
+ /// <summary>
+ /// Remove all items in another collection from this one, taking multiplicities into account.
+ /// <para>Always removes from the front of the list.
+ /// </para>
+ /// <para>The asymptotic running time complexity of this method is <code>O(n+m+v*log(v))</code>,
+ /// where <code>n</code> is the size of this list, <code>m</code> is the size of the
+ /// <code>items</code> collection and <code>v</code> is the number of views.
+ /// The method will temporarily allocate memory of size <code>O(m+v)</code>.
+ /// </para>
+ /// </summary>
+ /// <typeparam name="U"></typeparam>
+ /// <param name="items">The items to remove.</param>
+ [Tested]
+ public virtual void RemoveAll<U>(SCG.IEnumerable<U> items) where U : T
+ {
+ updatecheck();
+ if (size == 0)
+ return;
+ RaiseForRemoveAllHandler raiseHandler = new RaiseForRemoveAllHandler(underlying ?? this);
+ bool mustFire = raiseHandler.MustFire;
+#if HASHINDEX
+ Node node;
+ foreach (T item in items)
+ if (dictremove(item, out node))
+ {
+ if (mustFire)
+ raiseHandler.Remove(node.item);
+ remove(node, 118);
+ }
+#else
+ HashBag<T> toremove = new HashBag<T>(itemequalityComparer);
+ toremove.AddAll(items);
+ ViewHandler viewHandler = new ViewHandler(this);
+ int index = 0, removed = 0, myoffset = Offset;
+ Node node = startsentinel.next;
+ while (node != endsentinel)
+ {
+ //pass by a stretch of nodes
+ while (node != endsentinel && !toremove.Contains(node.item))
+ {
+ node = node.next;
+ index++;
+ }
+ viewHandler.skipEndpoints(removed, myoffset + index);
+ //Remove a stretch of nodes
+ Node localend = node.prev; //Latest node not to be removed
+ while (node != endsentinel && toremove.Remove(node.item))
+ {
+ if (mustFire)
+ raiseHandler.Remove(node.item);
+ removed++;
+ node = node.next;
+ index++;
+ viewHandler.updateViewSizesAndCounts(removed, myoffset + index);
+ }
+ viewHandler.updateSentinels(myoffset + index, localend, node);
+ localend.next = node;
+ node.prev = localend;
+ }
+ index = underlying != null ? underlying.size + 1 - myoffset : size + 1 - myoffset;
+ viewHandler.updateViewSizesAndCounts(removed, myoffset + index);
+ size -= removed;
+ if (underlying != null)
+ underlying.size -= removed;
+#endif
+ raiseHandler.Raise();
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="predicate"></param>
+ void RemoveAll(Fun<T, bool> predicate)
+ {
+ updatecheck();
+ if (size == 0)
+ return;
+ RaiseForRemoveAllHandler raiseHandler = new RaiseForRemoveAllHandler(underlying ?? this);
+ bool mustFire = raiseHandler.MustFire;
+#if HASHINDEX
+ {
+ Node n = startsentinel.next;
+
+ while (n != endsentinel)
+ {
+ bool removeIt = predicate(n.item);
+ updatecheck();
+ if (removeIt)
+ {
+ dict.Remove(n.item);
+ remove(n, 119);
+ if (mustFire)
+ raiseHandler.Remove(n.item);
+ }
+
+ n = n.next;
+ }
+ }
+#else
+ ViewHandler viewHandler = new ViewHandler(this);
+ int index = 0, removed = 0, myoffset = Offset;
+ Node node = startsentinel.next;
+ while (node != endsentinel)
+ {
+ //pass by a stretch of nodes
+ while (node != endsentinel && !predicate(node.item))
+ {
+ updatecheck();
+ node = node.next;
+ index++;
+ }
+ updatecheck();
+ viewHandler.skipEndpoints(removed, myoffset + index);
+ //Remove a stretch of nodes
+ Node localend = node.prev; //Latest node not to be removed
+ while (node != endsentinel && predicate(node.item))
+ {
+ updatecheck();
+ if (mustFire)
+ raiseHandler.Remove(node.item);
+ removed++;
+ node = node.next;
+ index++;
+ viewHandler.updateViewSizesAndCounts(removed, myoffset + index);
+ }
+ updatecheck();
+ viewHandler.updateSentinels(myoffset + index, localend, node);
+ localend.next = node;
+ node.prev = localend;
+ }
+ index = underlying != null ? underlying.size + 1 - myoffset : size + 1 - myoffset;
+ viewHandler.updateViewSizesAndCounts(removed, myoffset + index);
+ size -= removed;
+ if (underlying != null)
+ underlying.size -= removed;
+#endif
+ raiseHandler.Raise();
+ }
+
+ /// <summary>
+ /// Remove all items from this collection.
+ /// </summary>
+ [Tested]
+ public virtual void Clear()
+ {
+ updatecheck();
+ if (size == 0)
+ return;
+ int oldsize = size;
+#if HASHINDEX
+ if (underlying == null)
+ dict.Clear();
+ else
+ foreach (T item in this)
+ dict.Remove(item);
+#endif
+ clear();
+ (underlying ?? this).raiseForRemoveInterval(Offset, oldsize);
+ }
+
+ void clear()
+ {
+ if (size == 0)
+ return;
+#if HASHINDEX
+ //TODO: mix with tag maintenance to only run through list once?
+ ViewHandler viewHandler = new ViewHandler(this);
+ if (viewHandler.viewCount > 0)
+ {
+ int removed = 0;
+ Node n = startsentinel.next;
+ viewHandler.skipEndpoints(0, n);
+ while (n != endsentinel)
+ {
+ removed++;
+ n = n.next;
+ viewHandler.updateViewSizesAndCounts(removed, n);
+ }
+ viewHandler.updateSentinels(endsentinel, startsentinel, endsentinel);
+ if (underlying != null)
+ viewHandler.updateViewSizesAndCounts(removed, underlying.endsentinel);
+ }
+#else
+ fixViewsBeforeRemove(Offset, size, startsentinel.next, endsentinel.prev);
+#endif
+#if HASHINDEX
+ if (underlying != null)
+ {
+ Node n = startsentinel.next;
+
+ while (n != endsentinel)
+ {
+ n.next.prev = startsentinel;
+ startsentinel.next = n.next;
+ removefromtaggroup(n);
+ n = n.next;
+ }
+ }
+ else
+ taggroups = 0;
+#endif
+ endsentinel.prev = startsentinel;
+ startsentinel.next = endsentinel;
+ if (underlying != null)
+ underlying.size -= size;
+ size = 0;
+ }
+
+ /// <summary>
+ /// Remove all items not in some other collection from this one, taking multiplicities into account.
+ /// <para>The asymptotic running time complexity of this method is <code>O(n+m+v*log(v))</code>,
+ /// where <code>n</code> is the size of this collection, <code>m</code> is the size of the
+ /// <code>items</code> collection and <code>v</code> is the number of views.
+ /// The method will temporarily allocate memory of size <code>O(m+v)</code>. The stated complexitiy
+ /// holds under the assumption that the itemequalityComparer of this list is well-behaved.
+ /// </para>
+ /// </summary>
+ /// <typeparam name="U"></typeparam>
+ /// <param name="items">The items to retain.</param>
+ [Tested]
+ public virtual void RetainAll<U>(SCG.IEnumerable<U> items) where U : T
+ {
+ updatecheck();
+ if (size == 0)
+ return;
+ RaiseForRemoveAllHandler raiseHandler = new RaiseForRemoveAllHandler(underlying ?? this);
+ bool mustFire = raiseHandler.MustFire;
+#if HASHINDEX
+ /*if (underlying == null)
+ {
+ HashDictionary<T, Node> newdict = new HashDictionary<T, Node>(itemequalityComparer);
+ foreach (T item in items)
+ {
+ Node node;
+
+ if (dict.Remove(item, out node))
+ newdict.Add(item, node);
+ }
+ foreach (KeyValuePair<T, Node> pair in dict)
+ {
+ Node n = pair.Value;
+ fixViewsBeforeSingleRemove(n, 117);
+ Node p = n.prev, s = n.next; s.prev = p; p.next = s;
+ removefromtaggroup(n);
+ }
+ dict = newdict;
+ size = dict.Count;
+ //For a small number of items to retain it might be faster to
+ //iterate through the list and splice out the chunks not needed
+ }
+ else*/
+ {
+ HashSet<T> toremove = new HashSet<T>(itemequalityComparer);
+
+ foreach (T item in this)
+ toremove.Add(item);
+
+ foreach (T item in items)
+ toremove.Remove(item);
+
+ Node n = startsentinel.next;
+
+ while (n != endsentinel && toremove.Count > 0)
+ {
+ if (toremove.Contains(n.item))
+ {
+ dict.Remove(n.item);
+ remove(n, 119);
+ if (mustFire)
+ raiseHandler.Remove(n.item);
+ }
+
+ n = n.next;
+ }
+ }
+#else
+ HashBag<T> toretain = new HashBag<T>(itemequalityComparer);
+ toretain.AddAll(items);
+ ViewHandler viewHandler = new ViewHandler(this);
+ int index = 0, removed = 0, myoffset = Offset;
+ Node node = startsentinel.next;
+ while (node != endsentinel)
+ {
+ //Skip a stretch of nodes
+ while (node != endsentinel && toretain.Remove(node.item))
+ {
+ node = node.next;
+ index++;
+ }
+ viewHandler.skipEndpoints(removed, myoffset + index);
+ //Remove a stretch of nodes
+ Node localend = node.prev; //Latest node not to be removed
+ while (node != endsentinel && !toretain.Contains(node.item))
+ {
+ if (mustFire)
+ raiseHandler.Remove(node.item);
+ removed++;
+ node = node.next;
+ index++;
+ viewHandler.updateViewSizesAndCounts(removed, myoffset + index);
+ }
+ viewHandler.updateSentinels(myoffset + index, localend, node);
+ localend.next = node;
+ node.prev = localend;
+ }
+ index = underlying != null ? underlying.size + 1 - myoffset : size + 1 - myoffset;
+ viewHandler.updateViewSizesAndCounts(removed, myoffset + index);
+ size -= removed;
+ if (underlying != null)
+ underlying.size -= removed;
+#endif
+ raiseHandler.Raise();
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="predicate"></param>
+ void RetainAll(Fun<T,bool> predicate)
+ {
+ updatecheck();
+ if (size == 0)
+ return;
+ RaiseForRemoveAllHandler raiseHandler = new RaiseForRemoveAllHandler(underlying ?? this);
+ bool mustFire = raiseHandler.MustFire;
+#if HASHINDEX
+ {
+ Node n = startsentinel.next;
+
+ while (n != endsentinel)
+ {
+ bool removeIt = !predicate(n.item);
+ updatecheck();
+ if (removeIt)
+ {
+ dict.Remove(n.item);
+ remove(n, 119);
+ if (mustFire)
+ raiseHandler.Remove(n.item);
+ }
+
+ n = n.next;
+ }
+ }
+#else
+ ViewHandler viewHandler = new ViewHandler(this);
+ int index = 0, removed = 0, myoffset = Offset;
+ Node node = startsentinel.next;
+ while (node != endsentinel)
+ {
+ //Skip a stretch of nodes
+ while (node != endsentinel && predicate(node.item))
+ {
+ updatecheck();
+ node = node.next;
+ index++;
+ }
+ updatecheck();
+ viewHandler.skipEndpoints(removed, myoffset + index);
+ //Remove a stretch of nodes
+ Node localend = node.prev; //Latest node not to be removed
+ while (node != endsentinel && !predicate(node.item))
+ {
+ updatecheck();
+ if (mustFire)
+ raiseHandler.Remove(node.item);
+ removed++;
+ node = node.next;
+ index++;
+ viewHandler.updateViewSizesAndCounts(removed, myoffset + index);
+ }
+ updatecheck();
+ viewHandler.updateSentinels(myoffset + index, localend, node);
+ localend.next = node;
+ node.prev = localend;
+ }
+ index = underlying != null ? underlying.size + 1 - myoffset : size + 1 - myoffset;
+ viewHandler.updateViewSizesAndCounts(removed, myoffset + index);
+ size -= removed;
+ if (underlying != null)
+ underlying.size -= removed;
+#endif
+ raiseHandler.Raise();
+ }
+
+ /// <summary>
+ /// Check if this collection contains all the values in another collection
+ /// with respect to multiplicities.
+ /// </summary>
+ /// <param name="items">The </param>
+ /// <typeparam name="U"></typeparam>
+ /// <returns>True if all values in <code>items</code>is in this collection.</returns>
+ [Tested]
+ public virtual bool ContainsAll<U>(SCG.IEnumerable<U> items) where U : T
+ {
+ validitycheck();
+#if HASHINDEX
+ Node node;
+ foreach (T item in items)
+ if (!contains(item, out node))
+ return false;
+ return true;
+#else
+ HashBag<T> tocheck = new HashBag<T>(itemequalityComparer);
+ tocheck.AddAll(items);
+ if (tocheck.Count > size)
+ return false;
+ Node node = startsentinel.next;
+ while (node != endsentinel)
+ {
+ tocheck.Remove(node.item);
+ node = node.next;
+ }
+ return tocheck.IsEmpty;
+#endif
+ }
+
+
+ /// <summary>
+ /// Create a new list consisting of the items of this list satisfying a
+ /// certain predicate.
+ /// </summary>
+ /// <param name="filter">The filter delegate defining the predicate.</param>
+ /// <returns>The new list.</returns>
+ [Tested]
+ public IList<T> FindAll(Fun<T, bool> filter)
+ {
+ validitycheck();
+ int stamp = this.stamp;
+ LinkedList<T> retval = new LinkedList<T>();
+ Node cursor = startsentinel.next;
+ Node mcursor = retval.startsentinel;
+#if HASHINDEX
+ double tagdelta = int.MaxValue / (size + 1.0);
+ int count = 1;
+ TagGroup taggroup = new TagGroup();
+ retval.taggroups = 1;
+#endif
+ while (cursor != endsentinel)
+ {
+ bool found = filter(cursor.item);
+ modifycheck(stamp);
+ if (found)
+ {
+ mcursor.next = new Node(cursor.item, mcursor, null);
+ mcursor = mcursor.next;
+ retval.size++;
+#if HASHINDEX
+ retval.dict.Add(cursor.item, mcursor);
+ mcursor.taggroup = taggroup;
+ mcursor.tag = (int)(tagdelta * count++);
+#endif
+ }
+ cursor = cursor.next;
+ }
+#if HASHINDEX
+ taggroup.count = retval.size;
+#endif
+ retval.endsentinel.prev = mcursor;
+ mcursor.next = retval.endsentinel;
+ return retval;
+ }
+
+
+ /// <summary>
+ /// Count the number of items of the collection equal to a particular value.
+ /// Returns 0 if and only if the value is not in the collection.
+ /// </summary>
+ /// <param name="item">The value to count.</param>
+ /// <returns>The number of copies found.</returns>
+ [Tested]
+ public virtual int ContainsCount(T item)
+ {
+#if HASHINDEX
+ return Contains(item) ? 1 : 0;
+#else
+ validitycheck();
+ int retval = 0;
+ Node node = startsentinel.next;
+ while (node != endsentinel)
+ {
+ if (itemequalityComparer.Equals(node.item, item))
+ retval++;
+ node = node.next;
+ }
+ return retval;
+#endif
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public virtual ICollectionValue<T> UniqueItems()
+ {
+#if HASHINDEX
+ return this;
+#else
+ HashBag<T> hashbag = new HashBag<T>(itemequalityComparer);
+ hashbag.AddAll(this);
+ return hashbag.UniqueItems();
+#endif
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public virtual ICollectionValue<KeyValuePair<T, int>> ItemMultiplicities()
+ {
+#if HASHINDEX
+ return new MultiplicityOne<T>(this);
+#else
+ HashBag<T> hashbag = new HashBag<T>(itemequalityComparer);
+ hashbag.AddAll(this);
+ return hashbag.ItemMultiplicities();
+#endif
+ }
+
+ /// <summary>
+ /// Remove all items equivalent to a given value.
+ /// <para>The asymptotic complexity of this method is <code>O(n+v*log(v))</code>,
+ /// where <code>n</code> is the size of the collection and <code>v</code>
+ /// is the number of views.
+ /// </para>
+ /// </summary>
+ /// <param name="item">The value to remove.</param>
+ [Tested]
+ public virtual void RemoveAllCopies(T item)
+ {
+#if HASHINDEX
+ Remove(item);
+#else
+ updatecheck();
+ if (size == 0)
+ return;
+ RaiseForRemoveAllHandler raiseHandler = new RaiseForRemoveAllHandler(underlying ?? this);
+ bool mustFire = raiseHandler.MustFire;
+ ViewHandler viewHandler = new ViewHandler(this);
+ int index = 0, removed = 0, myoffset = Offset;
+ //
+ Node node = startsentinel.next;
+ while (node != endsentinel)
+ {
+ //pass by a stretch of nodes
+ while (node != endsentinel && !itemequalityComparer.Equals(node.item, item))
+ {
+ node = node.next;
+ index++;
+ }
+ viewHandler.skipEndpoints(removed, myoffset + index);
+ //Remove a stretch of nodes
+ Node localend = node.prev; //Latest node not to be removed
+ while (node != endsentinel && itemequalityComparer.Equals(node.item, item))
+ {
+ if (mustFire)
+ raiseHandler.Remove(node.item);
+ removed++;
+ node = node.next;
+ index++;
+ viewHandler.updateViewSizesAndCounts(removed, myoffset + index);
+ }
+ viewHandler.updateSentinels(myoffset + index, localend, node);
+ localend.next = node;
+ node.prev = localend;
+ }
+ index = underlying != null ? underlying.size + 1 - myoffset : size + 1 - myoffset;
+ viewHandler.updateViewSizesAndCounts(removed, myoffset + index);
+ size -= removed;
+ if (underlying != null)
+ underlying.size -= removed;
+ raiseHandler.Raise();
+#endif
+ }
+
+ #endregion
+
+ #region ICollectionValue<T> Members
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>The number of items in this collection</value>
+ [Tested]
+ public override int Count { [Tested]get { validitycheck(); return size; } }
+
+ /// <summary>
+ /// Choose some item of this collection.
+ /// </summary>
+ /// <exception cref="NoSuchItemException">if collection is empty.</exception>
+ /// <returns></returns>
+ [Tested]
+ public override T Choose() { return First; }
+
+ /// <summary>
+ /// Create an enumerable, enumerating the items of this collection that satisfies
+ /// a certain condition.
+ /// </summary>
+ /// <param name="filter">The T->bool filter delegate defining the condition</param>
+ /// <returns>The filtered enumerable</returns>
+ public override SCG.IEnumerable<T> Filter(Fun<T, bool> filter) { validitycheck(); return base.Filter(filter); }
+
+ #endregion
+
+ #region IEnumerable<T> Members
+ /// <summary>
+ /// Create an enumerator for the collection
+ /// </summary>
+ /// <returns>The enumerator</returns>
+ [Tested]
+ public override SCG.IEnumerator<T> GetEnumerator()
+ {
+ validitycheck();
+ Node cursor = startsentinel.next;
+ int enumeratorstamp = underlying != null ? underlying.stamp : this.stamp;
+
+ while (cursor != endsentinel)
+ {
+ modifycheck(enumeratorstamp);
+ yield return cursor.item;
+ cursor = cursor.next;
+ }
+ }
+
+ #endregion
+
+ #region IExtensible<T> Members
+ /// <summary>
+ /// Add an item to this collection if possible.
+ /// </summary>
+ /// <param name="item">The item to add.</param>
+ /// <returns>True.</returns>
+ [Tested]
+ public virtual bool Add(T item)
+ {
+ updatecheck();
+#if HASHINDEX
+ Node node = new Node(item);
+ if (!dict.FindOrAdd(item, ref node))
+ {
+ insertNode(true, endsentinel, node);
+ (underlying ?? this).raiseForAdd(item);
+ return true;
+ }
+ return false;
+#else
+ insert(size, endsentinel, item);
+ (underlying ?? this).raiseForAdd(item);
+ return true;
+#endif
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>True since this collection has bag semantics.</value>
+ [Tested]
+ public virtual bool AllowsDuplicates
+ {
+ [Tested]
+ get
+ {
+#if HASHINDEX
+ return false;
+#else
+ return true;
+#endif
+ }
+ }
+
+ /// <summary>
+ /// By convention this is true for any collection with set semantics.
+ /// </summary>
+ /// <value>True if only one representative of a group of equal items
+ /// is kept in the collection together with the total count.</value>
+ public virtual bool DuplicatesByCounting
+ {
+ get
+ {
+#if HASHINDEX
+ return true;
+#else
+ return false;
+#endif
+ }
+ }
+
+ /// <summary>
+ /// Add the elements from another collection with a more specialized item type
+ /// to this collection.
+ /// </summary>
+ /// <typeparam name="U">The type of items to add</typeparam>
+ /// <param name="items">The items to add</param>
+ [Tested]
+ public virtual void AddAll<U>(SCG.IEnumerable<U> items) where U : T
+ {
+#if HASHINDEX
+ updatecheck();
+ int added = 0;
+ Node pred = endsentinel.prev;
+ foreach (U item in items)
+ {
+ Node node = new Node(item);
+ if (!dict.FindOrAdd(item, ref node))
+ {
+ insertNode(false, endsentinel, node);
+ added++;
+ }
+ }
+ if (added > 0)
+ {
+ fixViewsAfterInsert(endsentinel, pred, added, 0);
+ raiseForInsertAll(pred, size - added, added, false);
+ }
+#else
+ insertAll(size, items, false);
+#endif
+ }
+
+ #endregion
+
+#if HASHINDEX
+#else
+ #region IStack<T> Members
+
+ /// <summary>
+ /// Push an item to the top of the stack.
+ /// </summary>
+ /// <param name="item">The item</param>
+ [Tested]
+ public void Push(T item)
+ {
+ InsertLast(item);
+ }
+
+ /// <summary>
+ /// Pop the item at the top of the stack from the stack.
+ /// </summary>
+ /// <returns>The popped item.</returns>
+ [Tested]
+ public T Pop()
+ {
+ return RemoveLast();
+ }
+
+ #endregion
+
+ #region IQueue<T> Members
+
+ /// <summary>
+ /// Enqueue an item at the back of the queue.
+ /// </summary>
+ /// <param name="item">The item</param>
+ [Tested]
+ public virtual void Enqueue(T item)
+ {
+ InsertLast(item);
+ }
+
+ /// <summary>
+ /// Dequeue an item from the front of the queue.
+ /// </summary>
+ /// <returns>The item</returns>
+ [Tested]
+ public virtual T Dequeue()
+ {
+ return RemoveFirst();
+ }
+ #endregion
+#endif
+
+ #region Diagnostic
+
+ private bool checkViews()
+ {
+ if (underlying != null)
+ throw new InternalException(System.Reflection.MethodInfo.GetCurrentMethod() + " called on a view");
+ if (views == null)
+ return true;
+ bool retval = true;
+
+ Node[] nodes = new Node[size + 2];
+ int i = 0;
+ Node n = startsentinel;
+ while (n != null)
+ {
+ nodes[i++] = n;
+ n = n.next;
+ }
+ //Console.WriteLine("###");
+ foreach (LinkedList<T> view in views)
+ {
+ if (!view.isValid)
+ {
+ Console.WriteLine("Invalid view(hash {0}, offset {1}, size {2})",
+ view.GetHashCode(), view.offset, view.size);
+ retval = false;
+ continue;
+ }
+ if (view.Offset > size || view.Offset < 0)
+ {
+ Console.WriteLine("Bad view(hash {0}, offset {1}, size {2}), Offset > underlying.size ({2})",
+ view.GetHashCode(), view.offset, view.size, size);
+ retval = false;
+ }
+ else if (view.startsentinel != nodes[view.Offset])
+ {
+ Console.WriteLine("Bad view(hash {0}, offset {1}, size {2}), startsentinel {3} should be {4}",
+ view.GetHashCode(), view.offset, view.size,
+ view.startsentinel + " " + view.startsentinel.GetHashCode(),
+ nodes[view.Offset] + " " + nodes[view.Offset].GetHashCode());
+ retval = false;
+ }
+ if (view.Offset + view.size > size || view.Offset + view.size < 0)
+ {
+ Console.WriteLine("Bad view(hash {0}, offset {1}, size {2}), end index > underlying.size ({3})",
+ view.GetHashCode(), view.offset, view.size, size);
+ retval = false;
+ }
+ else if (view.endsentinel != nodes[view.Offset + view.size + 1])
+ {
+ Console.WriteLine("Bad view(hash {0}, offset {1}, size {2}), endsentinel {3} should be {4}",
+ view.GetHashCode(), view.offset, view.size,
+ view.endsentinel + " " + view.endsentinel.GetHashCode(),
+ nodes[view.Offset + view.size + 1] + " " + nodes[view.Offset + view.size + 1].GetHashCode());
+ retval = false;
+ }
+ if (view.views != views)
+ {
+ Console.WriteLine("Bad view(hash {0}, offset {1}, size {2}), wrong views list {3} <> {4}",
+ view.GetHashCode(), view.offset, view.size, view.views.GetHashCode(), views.GetHashCode());
+ retval = false;
+ }
+ if (view.underlying != this)
+ {
+ Console.WriteLine("Bad view(hash {0}, offset {1}, size {2}), wrong underlying {3} <> this {4}",
+ view.GetHashCode(), view.offset, view.size, view.underlying.GetHashCode(), GetHashCode());
+ retval = false;
+ }
+ if (view.stamp != stamp)
+ {
+ //Console.WriteLine("Bad view(hash {0}, offset {1}, size {2}), wrong stamp view:{2} underlying: {3}", view.GetHashCode(),view.offset, view.size, view.stamp, stamp);
+ //retval = false;
+ }
+ }
+ return retval;
+ }
+
+ /// <summary>
+ /// Check the sanity of this list
+ /// </summary>
+ /// <returns>true if sane</returns>
+ [Tested]
+ public virtual bool Check()
+ {
+ bool retval = true;
+
+ /*if (underlying != null && underlying.stamp != stamp)
+ {
+ Console.WriteLine("underlying != null && underlying.stamp({0}) != stamp({1})", underlying.stamp, stamp);
+ retval = false;
+ }*/
+
+ if (underlying != null)
+ {
+ //TODO: check that this view is included in viewsEndpoints tree
+ return underlying.Check();
+ }
+
+ if (startsentinel == null)
+ {
+ Console.WriteLine("startsentinel == null");
+ retval = false;
+ }
+
+ if (endsentinel == null)
+ {
+ Console.WriteLine("endsentinel == null");
+ retval = false;
+ }
+
+ if (size == 0)
+ {
+ if (startsentinel != null && startsentinel.next != endsentinel)
+ {
+ Console.WriteLine("size == 0 but startsentinel.next != endsentinel");
+ retval = false;
+ }
+
+ if (endsentinel != null && endsentinel.prev != startsentinel)
+ {
+ Console.WriteLine("size == 0 but endsentinel.prev != startsentinel");
+ retval = false;
+ }
+ }
+
+ if (startsentinel == null)
+ {
+ Console.WriteLine("NULL startsentinel");
+ return retval;
+ }
+
+ int count = 0;
+ Node node = startsentinel.next, prev = startsentinel;
+#if HASHINDEX
+ int taggroupsize = 0, oldtaggroupsize = losize + 1, seentaggroups = 0;
+ TagGroup oldtg = null;
+
+ if (underlying == null)
+ {
+ TagGroup tg = startsentinel.taggroup;
+
+ if (tg.count != 0 || tg.first != null || tg.last != null || tg.tag != int.MinValue)
+ {
+ Console.WriteLine("Bad startsentinel tag group: {0}", tg);
+ retval = false;
+ }
+
+ tg = endsentinel.taggroup;
+ if (tg.count != 0 || tg.first != null || tg.last != null || tg.tag != int.MaxValue)
+ {
+ Console.WriteLine("Bad endsentinel tag group: {0}", tg);
+ retval = false;
+ }
+ }
+#endif
+ while (node != endsentinel)
+ {
+ count++;
+ if (node.prev != prev)
+ {
+ Console.WriteLine("Bad backpointer at node {0}", count);
+ retval = false;
+ }
+#if HASHINDEX
+ if (underlying == null)
+ {
+ if (!node.prev.precedes(node))
+ {
+ Console.WriteLine("node.prev.tag ({0}, {1}) >= node.tag ({2}, {3}) at index={4} item={5} ", node.prev.taggroup.tag, node.prev.tag, node.taggroup.tag, node.tag, count, node.item);
+ retval = false;
+ }
+
+ if (node.taggroup != oldtg)
+ {
+ if (oldtg != null)
+ {
+ if (oldtg.count != taggroupsize)
+ {
+ Console.WriteLine("Bad taggroupsize: oldtg.count ({0}) != taggroupsize ({1}) at index={2} item={3}", oldtg.count, taggroupsize, count, node.item);
+ retval = false;
+ }
+
+ if (oldtaggroupsize <= losize && taggroupsize <= losize)
+ {
+ Console.WriteLine("Two small taggroups in a row: oldtaggroupsize ({0}), taggroupsize ({1}) at index={2} item={3}", oldtaggroupsize, taggroupsize, count, node.item);
+ retval = false;
+ }
+
+ oldtaggroupsize = taggroupsize;
+ }
+
+ seentaggroups++;
+ oldtg = node.taggroup;
+ taggroupsize = 1;
+ }
+ else
+ {
+ taggroupsize++;
+ }
+ }
+
+#endif
+ prev = node;
+ node = node.next;
+ if (node == null)
+ {
+ Console.WriteLine("Null next pointer at node {0}", count);
+ return false;
+ }
+ }
+
+#if HASHINDEX
+ if (underlying == null && size == 0 && taggroups != 0)
+ {
+ Console.WriteLine("Bad taggroups for empty list: size={0} taggroups={1}", size, taggroups);
+ retval = false;
+ }
+ if (underlying == null && size > 0)
+ {
+ oldtg = node.prev.taggroup;
+ if (oldtg != null)
+ {
+ if (oldtg.count != taggroupsize)
+ {
+ Console.WriteLine("Bad taggroupsize: oldtg.count ({0}) != taggroupsize ({1}) at index={2} item={3}", oldtg.count, taggroupsize, count, node.item);
+ retval = false;
+ }
+
+ if (oldtaggroupsize <= losize && taggroupsize <= losize)
+ {
+ Console.WriteLine("Two small taggroups in a row: oldtaggroupsize ({0}), taggroupsize ({1}) at index={2} item={3}", oldtaggroupsize, taggroupsize, count, node.item);
+ retval = false;
+ }
+ }
+
+ if (seentaggroups != taggroups)
+ {
+ Console.WriteLine("seentaggroups ({0}) != taggroups ({1}) (at size {2})", seentaggroups, taggroups, size);
+ retval = false;
+ }
+ }
+#endif
+ if (count != size)
+ {
+ Console.WriteLine("size={0} but enumeration gives {1} nodes ", size, count);
+ retval = false;
+ }
+
+ retval = checkViews() && retval;
+
+#if HASHINDEX
+ if (!retval)
+ return false;
+ if (underlying == null)
+ {
+ if (size != dict.Count)
+ {
+ Console.WriteLine("list.size ({0}) != dict.Count ({1})", size, dict.Count);
+ retval = false;
+ }
+ Node n = startsentinel.next, n2;
+ while (n != endsentinel)
+ {
+ if (!dict.Find(n.item, out n2))
+ {
+ Console.WriteLine("Item in list but not dict: {0}", n.item);
+ retval = false;
+ }
+ else if (n != n2)
+ {
+ Console.WriteLine("Wrong node in dict for item: {0}", n.item);
+ retval = false;
+ }
+ n = n.next;
+ }
+ }
+#endif
+ return retval;
+ }
+ #endregion
+
+ #region ICloneable Members
+
+ /// <summary>
+ /// Make a shallow copy of this LinkedList.
+ /// </summary>
+ /// <returns></returns>
+ public virtual object Clone()
+ {
+ LinkedList<T> clone = new LinkedList<T>(itemequalityComparer);
+ clone.AddAll(this);
+ return clone;
+ }
+
+ #endregion
+
+ }
+}
diff --git a/mcs/class/Mono.C5/C5/trees/.cvsignore b/mcs/class/Mono.C5/C5/trees/.cvsignore
new file mode 100644
index 00000000000..9577892f5d4
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/trees/.cvsignore
@@ -0,0 +1 @@
+RedBlackTreeBag.cs \ No newline at end of file
diff --git a/mcs/class/Mono.C5/C5/trees/RedBlackTreeDictionary.cs b/mcs/class/Mono.C5/C5/trees/RedBlackTreeDictionary.cs
new file mode 100644
index 00000000000..4e1bc61f81a
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/trees/RedBlackTreeDictionary.cs
@@ -0,0 +1,80 @@
+/*
+ Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+using System;
+using SCG = System.Collections.Generic;
+
+namespace C5
+{
+ /// <summary>
+ /// A sorted generic dictionary based on a red-black tree set.
+ /// </summary>
+ public class TreeDictionary<K, V> : SortedDictionaryBase<K, V>, IDictionary<K, V>, ISortedDictionary<K, V>
+ {
+
+ #region Constructors
+
+ /// <summary>
+ /// Create a red-black tree dictionary using the natural comparer for keys.
+ /// <exception cref="ArgumentException"/> if the key type K is not comparable.
+ /// </summary>
+ public TreeDictionary() : this(Comparer<K>.Default, EqualityComparer<K>.Default) { }
+
+ /// <summary>
+ /// Create a red-black tree dictionary using an external comparer for keys.
+ /// </summary>
+ /// <param name="comparer">The external comparer</param>
+ public TreeDictionary(SCG.IComparer<K> comparer) : this(comparer, new ComparerZeroHashCodeEqualityComparer<K>(comparer)) { }
+
+ TreeDictionary(SCG.IComparer<K> comparer, SCG.IEqualityComparer<K> equalityComparer) : base(comparer,equalityComparer)
+ {
+ pairs = sortedpairs = new TreeSet<KeyValuePair<K, V>>(new KeyValuePairComparer<K, V>(comparer));
+ }
+
+ #endregion
+
+ //TODO: put in interface
+ /// <summary>
+ /// Make a snapshot of the current state of this dictionary
+ /// </summary>
+ /// <returns>The snapshot</returns>
+ [Tested]
+ public SCG.IEnumerable<KeyValuePair<K, V>> Snapshot()
+ {
+ TreeDictionary<K, V> res = (TreeDictionary<K, V>)MemberwiseClone();
+
+ res.pairs = (TreeSet<KeyValuePair<K, V>>)((TreeSet<KeyValuePair<K, V>>)sortedpairs).Snapshot();
+ return res;
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public override object Clone()
+ {
+ TreeDictionary<K, V> clone = new TreeDictionary<K, V>(Comparer, EqualityComparer);
+ clone.sortedpairs.AddSorted(sortedpairs);
+ return clone;
+ }
+
+ }
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/C5/trees/RedBlackTreeSet.cs b/mcs/class/Mono.C5/C5/trees/RedBlackTreeSet.cs
new file mode 100644
index 00000000000..ac86cc6eaea
--- /dev/null
+++ b/mcs/class/Mono.C5/C5/trees/RedBlackTreeSet.cs
@@ -0,0 +1,4490 @@
+/*
+ Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+#define MAINTAIN_SIZE
+#define BAGnot
+#define NCP
+
+#if BAG
+#if !MAINTAIN_SIZE
+#error BAG defined without MAINTAIN_SIZE!
+#endif
+#endif
+
+
+using System;
+using SCG = System.Collections.Generic;
+
+// NOTE NOTE NOTE NOTE
+// This source file is used to produce both TreeSet<T> and TreeBag<T>
+// It should be copied to a file called TreeBag.cs in which all code mentions of
+// TreeSet is changed to TreeBag and the preprocessor symbol BAG is defined.
+// NOTE: there may be problems with documentation comments.
+
+namespace C5
+{
+#if BAG
+ /// <summary>
+ /// An implementation of Red-Black trees as an indexed, sorted collection with bag semantics,
+ /// cf. <a href="litterature.htm#CLRS">CLRS</a>. (<see cref="T:C5.TreeSet`1"/> for an
+ /// implementation with set semantics).
+ /// <br/>
+ /// The comparer (sorting order) may be either natural, because the item type is comparable
+ /// (generic: <see cref="T:C5.IComparable`1"/> or non-generic: System.IComparable) or it can
+ /// be external and supplied by the user in the constructor.
+ /// <br/>
+ /// Each distinct item is only kept in one place in the tree - together with the number
+ /// of times it is a member of the bag. Thus, if two items that are equal according
+ /// </summary>
+#else
+ /// <summary>
+ /// An implementation of Red-Black trees as an indexed, sorted collection with set semantics,
+ /// cf. <a href="litterature.htm#CLRS">CLRS</a>. <see cref="T:C5.TreeBag`1"/> for a version
+ /// with bag semantics. <see cref="T:C5.TreeDictionary`2"/> for a sorted dictionary
+ /// based on this tree implementation.
+ /// <i>
+ /// The comparer (sorting order) may be either natural, because the item type is comparable
+ /// (generic: <see cref="T:C5.IComparable`1"/> or non-generic: System.IComparable) or it can
+ /// be external and supplied by the user in the constructor.</i>
+ ///
+ /// <i>TODO: describe performance here</i>
+ /// <i>TODO: discuss persistence and its useful usage modes. Warn about the space
+ /// leak possible with other usage modes.</i>
+ /// </summary>
+#endif
+ [Serializable]
+ public class TreeSet<T> : SequencedBase<T>, IIndexedSorted<T>, IPersistentSorted<T>
+ {
+ #region Fields
+
+ SCG.IComparer<T> comparer;
+
+ Node root;
+
+ //TODO: wonder if we should remove that
+ int blackdepth = 0;
+
+ //We double these stacks for the iterative add and remove on demand
+ //TODO: refactor dirs[] into bool fields on Node (?)
+ private int[] dirs = new int[2];
+
+ private Node[] path = new Node[2];
+#if NCP
+ //TODO: refactor into separate class
+ bool isSnapShot = false;
+
+ int generation;
+
+ bool isValid = true;
+
+ SnapRef snapList;
+#endif
+ #endregion
+
+ #region Events
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public override EventTypeEnum ListenableEvents { get { return EventTypeEnum.Basic; } }
+
+ #endregion
+ #region Util
+
+ /// <summary>
+ /// Fetch the left child of n taking node-copying persistence into
+ /// account if relevant.
+ /// </summary>
+ /// <param name="n"></param>
+ /// <returns></returns>
+ private Node left(Node n)
+ {
+#if NCP
+ if (isSnapShot)
+ {
+#if SEPARATE_EXTRA
+ Node.Extra e = n.extra;
+
+ if (e != null && e.lastgeneration >= treegen && e.leftnode)
+ return e.oldref;
+#else
+ if (n.lastgeneration >= generation && n.leftnode)
+ return n.oldref;
+#endif
+ }
+#endif
+ return n.left;
+ }
+
+
+ private Node right(Node n)
+ {
+#if NCP
+ if (isSnapShot)
+ {
+#if SEPARATE_EXTRA
+ Node.Extra e = n.extra;
+
+ if (e != null && e.lastgeneration >= treegen && !e.leftnode)
+ return e.oldref;
+#else
+ if (n.lastgeneration >= generation && !n.leftnode)
+ return n.oldref;
+#endif
+ }
+#endif
+ return n.right;
+ }
+
+
+ //This method should be called by methods that use the internal
+ //traversal stack, unless certain that there is room enough
+ private void stackcheck()
+ {
+ while (dirs.Length < 2 * blackdepth)
+ {
+ dirs = new int[2 * dirs.Length];
+ path = new Node[2 * dirs.Length];
+ }
+ }
+
+ #endregion
+
+ #region Node nested class
+
+
+ /// <summary>
+ /// The type of node in a Red-Black binary tree
+ /// </summary>
+ [Serializable]
+ class Node
+ {
+ public bool red = true;
+
+ public T item;
+
+ public Node left;
+
+ public Node right;
+
+#if MAINTAIN_SIZE
+ public int size = 1;
+#endif
+
+#if BAG
+ public int items = 1;
+#endif
+
+#if NCP
+ //TODO: move everything into (separate) Extra
+ public int generation;
+#if SEPARATE_EXTRA
+ internal class Extra
+ {
+ public int lastgeneration;
+
+ public Node oldref;
+
+ public bool leftnode;
+
+ //public Node next;
+ }
+
+ public Extra extra;
+
+#else
+ public int lastgeneration = -1;
+
+ public Node oldref;
+
+ public bool leftnode;
+#endif
+
+ /// <summary>
+ /// Update a child pointer
+ /// </summary>
+ /// <param name="cursor"></param>
+ /// <param name="leftnode"></param>
+ /// <param name="child"></param>
+ /// <param name="maxsnapid"></param>
+ /// <param name="generation"></param>
+ /// <returns>True if node was *copied*</returns>
+ internal static bool update(ref Node cursor, bool leftnode, Node child, int maxsnapid, int generation)
+ {
+ Node oldref = leftnode ? cursor.left : cursor.right;
+
+ if (child == oldref)
+ return false;
+
+ bool retval = false;
+
+ if (cursor.generation <= maxsnapid)
+ {
+#if SEPARATE_EXTRA
+ if (cursor.extra == null)
+ {
+ Extra extra = cursor.extra = new Extra();
+
+ extra.leftnode = leftnode;
+ extra.lastgeneration = maxsnapid;
+ extra.oldref = oldref;
+ }
+ else if (cursor.extra.leftnode != leftnode || cursor.extra.lastgeneration < maxsnapid)
+#else
+ if (cursor.lastgeneration == -1)
+ {
+ cursor.leftnode = leftnode;
+ cursor.lastgeneration = maxsnapid;
+ cursor.oldref = oldref;
+ }
+ else if (cursor.leftnode != leftnode || cursor.lastgeneration < maxsnapid)
+#endif
+ {
+ CopyNode(ref cursor, maxsnapid, generation);
+ retval = true;
+ }
+ }
+
+ if (leftnode)
+ cursor.left = child;
+ else
+ cursor.right = child;
+
+ return retval;
+ }
+
+
+ //If cursor.extra.lastgeneration==maxsnapid, the extra pointer will
+ //always be used in the old copy of cursor. Therefore, after
+ //making the clone, we should update the old copy by restoring
+ //the child pointer and setting extra to null.
+ //OTOH then we cannot clean up unused Extra objects unless we link
+ //them together in a doubly linked list.
+ public static bool CopyNode(ref Node cursor, int maxsnapid, int generation)
+ {
+ if (cursor.generation <= maxsnapid)
+ {
+ cursor = (Node)(cursor.MemberwiseClone());
+ cursor.generation = generation;
+#if SEPARATE_EXTRA
+ cursor.extra = null;
+#else
+ cursor.lastgeneration = -1;
+#endif
+ return true;
+ }
+ else
+ return false;
+ }
+
+#endif
+ }
+
+ #endregion
+
+ #region Constructors
+
+ /// <summary>
+ /// Create a red-black tree collection with natural comparer and item equalityComparer.
+ /// We assume that if <code>T</code> is comparable, its default equalityComparer
+ /// will be compatible with the comparer.
+ /// </summary>
+ /// <exception cref="NotComparableException">If <code>T</code> is not comparable.
+ /// </exception>
+ public TreeSet() : this(Comparer<T>.Default, EqualityComparer<T>.Default) { }
+
+
+ /// <summary>
+ /// Create a red-black tree collection with an external comparer.
+ /// <para>The itemequalityComparer will be a compatible
+ /// <see cref="T:C5.ComparerZeroHashCodeEqualityComparer`1"/> since the
+ /// default equalityComparer for T (<see cref="P:C5.EqualityComparer`1.Default"/>)
+ /// is unlikely to be compatible with the external comparer. This makes the
+ /// tree inadequate for use as item in a collection of unsequenced or sequenced sets or bags
+ /// (<see cref="T:C5.ICollection`1"/> and <see cref="T:C5.ISequenced`1"/>)
+ /// </para>
+ /// </summary>
+ /// <param name="comparer">The external comparer</param>
+ public TreeSet(SCG.IComparer<T> comparer) : this(comparer, new ComparerZeroHashCodeEqualityComparer<T>(comparer)) { }
+
+ /// <summary>
+ /// Create a red-black tree collection with an external comparer and an external
+ /// item equalityComparer, assumed consistent.
+ /// </summary>
+ /// <param name="comparer">The external comparer</param>
+ /// <param name="equalityComparer">The external item equalityComparer</param>
+ public TreeSet(SCG.IComparer<T> comparer, SCG.IEqualityComparer<T> equalityComparer)
+ : base(equalityComparer)
+ {
+ if (comparer == null)
+ throw new NullReferenceException("Item comparer cannot be null");
+ this.comparer = comparer;
+ }
+
+ #endregion
+
+ #region TreeSet.Enumerator nested class
+
+ /// <summary>
+ /// An enumerator for a red-black tree collection. Based on an explicit stack
+ /// of subtrees waiting to be enumerated. Currently only used for the tree set
+ /// enumerators (tree bag enumerators use an iterator block based enumerator).
+ /// </summary>
+ internal class Enumerator : SCG.IEnumerator<T>
+ {
+ #region Private Fields
+ TreeSet<T> tree;
+
+ bool valid = false;
+
+ int stamp;
+
+ T current;
+
+ Node cursor;
+
+ Node[] path; // stack of nodes
+
+ int level = 0;
+ #endregion
+ /// <summary>
+ /// Create a tree enumerator
+ /// </summary>
+ /// <param name="tree">The red-black tree to enumerate</param>
+ public Enumerator(TreeSet<T> tree)
+ {
+ this.tree = tree;
+ stamp = tree.stamp;
+ path = new Node[2 * tree.blackdepth];
+ cursor = new Node();
+ cursor.right = tree.root;
+ }
+
+
+ /// <summary>
+ /// Undefined if enumerator is not valid (MoveNext hash been called returning true)
+ /// </summary>
+ /// <value>The current item of the enumerator.</value>
+ [Tested]
+ public T Current
+ {
+ [Tested]
+ get
+ {
+ if (valid)
+ return current;
+ else
+ throw new InvalidOperationException();
+ }
+ }
+
+
+ //Maintain a stack of nodes that are roots of
+ //subtrees not completely exported yet. Invariant:
+ //The stack nodes together with their right subtrees
+ //consists of exactly the items we have not passed
+ //yet (the top of the stack holds current item).
+ /// <summary>
+ /// Move enumerator to next item in tree, or the first item if
+ /// this is the first call to MoveNext.
+ /// <exception cref="CollectionModifiedException"/> if underlying tree was modified.
+ /// </summary>
+ /// <returns>True if enumerator is valid now</returns>
+ [Tested]
+ public bool MoveNext()
+ {
+ tree.modifycheck(stamp);
+ if (cursor.right != null)
+ {
+ path[level] = cursor = cursor.right;
+ while (cursor.left != null)
+ path[++level] = cursor = cursor.left;
+ }
+ else if (level == 0)
+ return valid = false;
+ else
+ cursor = path[--level];
+
+ current = cursor.item;
+ return valid = true;
+ }
+
+
+ #region IDisposable Members for Enumerator
+
+ bool disposed;
+
+
+ /// <summary>
+ /// Call Dispose(true) and then suppress finalization of this enumerator.
+ /// </summary>
+ [Tested]
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+
+ /// <summary>
+ /// Remove the internal data (notably the stack array).
+ /// </summary>
+ /// <param name="disposing">True if called from Dispose(),
+ /// false if called from the finalizer</param>
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!disposed)
+ {
+ if (disposing)
+ {
+ }
+
+ current = default(T);
+ cursor = null;
+ path = null;
+ disposed = true;
+ }
+ }
+
+
+ /// <summary>
+ /// Finalizer for enumerator
+ /// </summary>
+ ~Enumerator()
+ {
+ Dispose(false);
+ }
+ #endregion
+
+
+ #region IEnumerator Members
+
+ object System.Collections.IEnumerator.Current
+ {
+ get { return Current; }
+ }
+
+ bool System.Collections.IEnumerator.MoveNext()
+ {
+ return MoveNext();
+ }
+
+ void System.Collections.IEnumerator.Reset()
+ {
+ throw new Exception("The method or operation is not implemented.");
+ }
+
+ #endregion
+ }
+#if NCP
+ /// <summary>
+ /// An enumerator for a snapshot of a node copy persistent red-black tree
+ /// collection.
+ /// </summary>
+ internal class SnapEnumerator : SCG.IEnumerator<T>
+ {
+ #region Private Fields
+ TreeSet<T> tree;
+
+ bool valid = false;
+
+ int stamp;
+#if BAG
+ int togo;
+#endif
+
+ T current;
+
+ Node cursor;
+
+ Node[] path; // stack of nodes
+
+ int level;
+ #endregion
+
+ /// <summary>
+ /// Creta an enumerator for a snapshot of a node copy persistent red-black tree
+ /// collection
+ /// </summary>
+ /// <param name="tree">The snapshot</param>
+ public SnapEnumerator(TreeSet<T> tree)
+ {
+ this.tree = tree;
+ stamp = tree.stamp;
+ path = new Node[2 * tree.blackdepth];
+ cursor = new Node();
+ cursor.right = tree.root;
+ }
+
+
+ #region SCG.IEnumerator<T> Members
+
+ /// <summary>
+ /// Move enumerator to next item in tree, or the first item if
+ /// this is the first call to MoveNext.
+ /// <exception cref="CollectionModifiedException"/> if underlying tree was modified.
+ /// </summary>
+ /// <returns>True if enumerator is valid now</returns>
+ [Tested]
+ public bool MoveNext()
+ {
+ tree.modifycheck(stamp);//???
+
+#if BAG
+ if (--togo > 0)
+ return true;
+#endif
+ Node next = tree.right(cursor);
+
+ if (next != null)
+ {
+ path[level] = cursor = next;
+ next = tree.left(cursor);
+ while (next != null)
+ {
+ path[++level] = cursor = next;
+ next = tree.left(cursor);
+ }
+ }
+ else if (level == 0)
+ return valid = false;
+ else
+ cursor = path[--level];
+
+#if BAG
+ togo = cursor.items;
+#endif
+ current = cursor.item;
+ return valid = true;
+ }
+
+
+ /// <summary>
+ /// Undefined if enumerator is not valid (MoveNext hash been called returning true)
+ /// </summary>
+ /// <value>The current value of the enumerator.</value>
+ [Tested]
+ public T Current
+ {
+ [Tested]
+ get
+ {
+ if (valid)
+ return current;
+ else
+ throw new InvalidOperationException();
+ }
+ }
+
+ #endregion
+
+ #region IDisposable Members
+
+ [Tested]
+ void System.IDisposable.Dispose()
+ {
+ tree = null;
+ valid = false;
+ current = default(T);
+ cursor = null;
+ path = null;
+ }
+
+ #endregion
+
+ #region IEnumerator Members
+
+ object System.Collections.IEnumerator.Current
+ {
+ get { return Current; }
+ }
+
+ bool System.Collections.IEnumerator.MoveNext()
+ {
+ return MoveNext();
+ }
+
+ void System.Collections.IEnumerator.Reset()
+ {
+ throw new Exception("The method or operation is not implemented.");
+ }
+
+ #endregion
+ }
+#endif
+ #endregion
+
+ #region IEnumerable<T> Members
+
+ private SCG.IEnumerator<T> getEnumerator(Node node, int origstamp)
+ {
+ if (node == null)
+ yield break;
+
+ if (node.left != null)
+ {
+ SCG.IEnumerator<T> child = getEnumerator(node.left, origstamp);
+
+ while (child.MoveNext())
+ {
+ modifycheck(origstamp);
+ yield return child.Current;
+ }
+ }
+#if BAG
+ int togo = node.items;
+ while (togo-- > 0)
+ {
+ modifycheck(origstamp);
+ yield return node.item;
+ }
+#else
+ modifycheck(origstamp);
+ yield return node.item;
+#endif
+ if (node.right != null)
+ {
+ SCG.IEnumerator<T> child = getEnumerator(node.right, origstamp);
+
+ while (child.MoveNext())
+ {
+ modifycheck(origstamp);
+ yield return child.Current;
+ }
+ }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <exception cref="NoSuchItemException">If tree is empty</exception>
+ /// <returns></returns>
+ [Tested]
+ public override T Choose()
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+
+ if (size == 0)
+ throw new NoSuchItemException();
+ return root.item;
+ }
+
+
+ /// <summary>
+ /// Create an enumerator for this tree
+ /// </summary>
+ /// <returns>The enumerator</returns>
+ [Tested]
+ public override SCG.IEnumerator<T> GetEnumerator()
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+#if NCP
+ if (isSnapShot)
+ return new SnapEnumerator(this);
+#endif
+#if BAG
+ return getEnumerator(root, stamp);
+#else
+ return new Enumerator(this);
+#endif
+ }
+
+ #endregion
+
+ #region ISink<T> Members
+
+ /// <summary>
+ /// Add item to tree. If already there, return the found item in the second argument.
+ /// </summary>
+ /// <param name="item">Item to add</param>
+ /// <param name="founditem">item found</param>
+ /// <param name="update">whether item in node should be updated</param>
+ /// <param name="wasfound">true if found in bag, false if not found or tre is a set</param>
+ /// <returns>True if item was added</returns>
+ bool addIterative(T item, ref T founditem, bool update, out bool wasfound)
+ {
+ wasfound = false;
+ if (root == null)
+ {
+ root = new Node();
+ root.red = false;
+ blackdepth = 1;
+ root.item = item;
+#if NCP
+ root.generation = generation;
+#endif
+ return true;
+ }
+
+ stackcheck();
+
+ int level = 0;
+ Node cursor = root;
+
+ while (true)
+ {
+ int comp = comparer.Compare(cursor.item, item);
+
+ if (comp == 0)
+ {
+ founditem = cursor.item;
+#if BAG
+ wasfound = true;
+ bool nodeWasUpdated = true;
+#if NCP
+ Node.CopyNode(ref cursor, maxsnapid, generation);
+#endif
+ if (update)
+ cursor.item = item;
+ else
+ {
+ cursor.items++;
+ cursor.size++;
+ }
+#else
+ bool nodeWasUpdated = update;
+ if (update)
+ {
+#if NCP
+ Node.CopyNode(ref cursor, maxsnapid, generation);
+#endif
+ cursor.item = item;
+ }
+#endif
+
+ while (level-- > 0)
+ {
+ if (nodeWasUpdated)
+ {
+ Node kid = cursor;
+
+ cursor = path[level];
+#if NCP
+ Node.update(ref cursor, dirs[level] > 0, kid, maxsnapid, generation);
+#endif
+#if BAG
+ if (!update)
+ cursor.size++;
+#endif
+ }
+
+ path[level] = null;
+ }
+#if BAG
+ return !update;
+#else
+ if (update)
+ root = cursor;
+
+ return false;
+#endif
+ }
+
+ //else
+ Node child = comp > 0 ? cursor.left : cursor.right;
+
+ if (child == null)
+ {
+ child = new Node();
+ child.item = item;
+#if NCP
+ child.generation = generation;
+ Node.update(ref cursor, comp > 0, child, maxsnapid, generation);
+#else
+ if (comp > 0) { cursor.left = child; }
+ else { cursor.right = child; }
+#endif
+#if MAINTAIN_SIZE
+ cursor.size++;
+#endif
+ dirs[level] = comp;
+ break;
+ }
+ else
+ {
+ dirs[level] = comp;
+ path[level++] = cursor;
+ cursor = child;
+ }
+ }
+
+ //We have just added the red node child to "cursor"
+ while (cursor.red)
+ {
+ //take one step up:
+ Node child = cursor;
+
+ cursor = path[--level];
+ path[level] = null;
+#if NCP
+ Node.update(ref cursor, dirs[level] > 0, child, maxsnapid, generation);
+#endif
+#if MAINTAIN_SIZE
+ cursor.size++;
+#endif
+ int comp = dirs[level];
+ Node childsibling = comp > 0 ? cursor.right : cursor.left;
+
+ if (childsibling != null && childsibling.red)
+ {
+ //Promote
+ child.red = false;
+#if NCP
+ Node.update(ref cursor, comp < 0, childsibling, maxsnapid, generation);
+#endif
+ childsibling.red = false;
+
+ //color cursor red & take one step up the tree unless at root
+ if (level == 0)
+ {
+ root = cursor;
+ blackdepth++;
+ return true;
+ }
+ else
+ {
+ cursor.red = true;
+#if NCP
+ child = cursor;
+ cursor = path[--level];
+ Node.update(ref cursor, dirs[level] > 0, child, maxsnapid, generation);
+#endif
+ path[level] = null;
+#if MAINTAIN_SIZE
+ cursor.size++;
+#endif
+ }
+ }
+ else
+ {
+ //ROTATE!!!
+ int childcomp = dirs[level + 1];
+
+ cursor.red = true;
+ if (comp > 0)
+ {
+ if (childcomp > 0)
+ {//zagzag
+#if NCP
+ Node.update(ref cursor, true, child.right, maxsnapid, generation);
+ Node.update(ref child, false, cursor, maxsnapid, generation);
+#else
+ cursor.left = child.right;
+ child.right = cursor;
+#endif
+ cursor = child;
+ }
+ else
+ {//zagzig
+ Node badgrandchild = child.right;
+#if NCP
+ Node.update(ref cursor, true, badgrandchild.right, maxsnapid, generation);
+ Node.update(ref child, false, badgrandchild.left, maxsnapid, generation);
+ Node.CopyNode(ref badgrandchild, maxsnapid, generation);
+#else
+ cursor.left = badgrandchild.right;
+ child.right = badgrandchild.left;
+#endif
+ badgrandchild.left = child;
+ badgrandchild.right = cursor;
+ cursor = badgrandchild;
+ }
+ }
+ else
+ {//comp < 0
+ if (childcomp < 0)
+ {//zigzig
+#if NCP
+ Node.update(ref cursor, false, child.left, maxsnapid, generation);
+ Node.update(ref child, true, cursor, maxsnapid, generation);
+#else
+ cursor.right = child.left;
+ child.left = cursor;
+#endif
+ cursor = child;
+ }
+ else
+ {//zigzag
+ Node badgrandchild = child.left;
+#if NCP
+ Node.update(ref cursor, false, badgrandchild.left, maxsnapid, generation);
+ Node.update(ref child, true, badgrandchild.right, maxsnapid, generation);
+ Node.CopyNode(ref badgrandchild, maxsnapid, generation);
+#else
+ cursor.right = badgrandchild.left;
+ child.left = badgrandchild.right;
+#endif
+ badgrandchild.right = child;
+ badgrandchild.left = cursor;
+ cursor = badgrandchild;
+ }
+ }
+
+ cursor.red = false;
+
+#if MAINTAIN_SIZE
+ Node n;
+
+#if BAG
+ n = cursor.right;
+ cursor.size = n.size = (n.left == null ? 0 : n.left.size) + (n.right == null ? 0 : n.right.size) + n.items;
+ n = cursor.left;
+ n.size = (n.left == null ? 0 : n.left.size) + (n.right == null ? 0 : n.right.size) + n.items;
+ cursor.size += n.size + cursor.items;
+#else
+ n = cursor.right;
+ cursor.size = n.size = (n.left == null ? 0 : n.left.size) + (n.right == null ? 0 : n.right.size) + 1;
+ n = cursor.left;
+ n.size = (n.left == null ? 0 : n.left.size) + (n.right == null ? 0 : n.right.size) + 1;
+ cursor.size += n.size + 1;
+#endif
+#endif
+ if (level == 0)
+ {
+ root = cursor;
+ return true;
+ }
+ else
+ {
+ child = cursor;
+ cursor = path[--level];
+ path[level] = null;
+#if NCP
+ Node.update(ref cursor, dirs[level] > 0, child, maxsnapid, generation);
+#else
+ if (dirs[level] > 0)
+ cursor.left = child;
+ else
+ cursor.right = child;
+#endif
+#if MAINTAIN_SIZE
+ cursor.size++;
+#endif
+ break;
+ }
+ }
+ }
+#if NCP
+ bool stillmore = true;
+#endif
+ while (level > 0)
+ {
+ Node child = cursor;
+
+ cursor = path[--level];
+ path[level] = null;
+#if NCP
+ if (stillmore)
+ stillmore = Node.update(ref cursor, dirs[level] > 0, child, maxsnapid, generation);
+#endif
+#if MAINTAIN_SIZE
+ cursor.size++;
+#endif
+ }
+
+ root = cursor;
+ return true;
+ }
+
+
+ /// <summary>
+ /// Add an item to this collection if possible. If this collection has set
+ /// semantics, the item will be added if not already in the collection. If
+ /// bag semantics, the item will always be added.
+ /// </summary>
+ /// <param name="item">The item to add.</param>
+ /// <returns>True if item was added.</returns>
+ [Tested]
+ public bool Add(T item)
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ updatecheck();
+
+ //Note: blackdepth of the tree is set inside addIterative
+ T jtem = default(T);
+ if (!add(item, ref jtem))
+ return false;
+ if (ActiveEvents != 0)
+ raiseForAdd(jtem);
+ return true;
+ }
+
+ private bool add(T item, ref T j)
+ {
+ bool wasFound;
+
+ if (addIterative(item, ref j, false, out wasFound))
+ {
+ size++;
+ if (!wasFound)
+ j = item;
+ return true;
+ }
+ else
+ return false;
+ }
+
+ /// <summary>
+ /// Add the elements from another collection with a more specialized item type
+ /// to this collection. If this
+ /// collection has set semantics, only items not already in the collection
+ /// will be added.
+ /// </summary>
+ /// <typeparam name="U">The type of items to add</typeparam>
+ /// <param name="items">The items to add</param>
+ [Tested]
+ public void AddAll<U>(SCG.IEnumerable<U> items) where U : T
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ updatecheck();
+
+ int c = 0;
+ T j = default(T);
+ bool tmp;
+
+ bool raiseAdded = (ActiveEvents & EventTypeEnum.Added) != 0;
+ CircularQueue<T> wasAdded = raiseAdded ? new CircularQueue<T>() : null;
+
+ foreach (T i in items)
+ if (addIterative(i, ref j, false, out tmp))
+ {
+ c++;
+ if (raiseAdded)
+ wasAdded.Enqueue(tmp ? j : i);
+ }
+ if (c == 0)
+ return;
+
+ size += c;
+ //TODO: implement a RaiseForAddAll() method
+ if (raiseAdded)
+ foreach (T item in wasAdded)
+ raiseItemsAdded(item, 1);
+ if (((ActiveEvents & EventTypeEnum.Changed) != 0))
+ raiseCollectionChanged();
+ }
+
+
+ /// <summary>
+ /// Add all the items from another collection with an enumeration order that
+ /// is increasing in the items. <para>The idea is that the implementation may use
+ /// a faster algorithm to merge the two collections.</para>
+ /// <exception cref="ArgumentException"/> if the enumerated items turns out
+ /// not to be in increasing order.
+ /// </summary>
+ /// <param name="items">The collection to add.</param>
+ /// <typeparam name="U"></typeparam>
+ [Tested]
+ public void AddSorted<U>(SCG.IEnumerable<U> items) where U : T
+ {
+ if (size > 0)
+ AddAll(items);
+ else
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ updatecheck();
+ addSorted(items, true, true);
+ }
+ }
+
+ #region add-sorted helpers
+
+ //Create a RB tree from x+2^h-1 (x < 2^h, h>=1) nodes taken from a
+ //singly linked list of red nodes using only the right child refs.
+ //The x nodes at depth h+1 will be red, the rest black.
+ //(h is the blackdepth of the resulting tree)
+ static Node maketreer(ref Node rest, int blackheight, int maxred, int red)
+ {
+ if (blackheight == 1)
+ {
+ Node top = rest;
+
+ rest = rest.right;
+ if (red > 0)
+ {
+ top.right = null;
+ rest.left = top;
+ top = rest;
+#if BAG
+ top.size += top.left.size;
+#elif MAINTAIN_SIZE
+ top.size = 1 + red;
+#endif
+ rest = rest.right;
+ red--;
+ }
+
+ if (red > 0)
+ {
+#if BAG
+ top.size += rest.size;
+#endif
+ top.right = rest;
+ rest = rest.right;
+ top.right.right = null;
+ }
+ else
+ top.right = null;
+
+ top.red = false;
+ return top;
+ }
+ else
+ {
+ maxred >>= 1;
+
+ int lred = red > maxred ? maxred : red;
+ Node left = maketreer(ref rest, blackheight - 1, maxred, lred);
+ Node top = rest;
+
+ rest = rest.right;
+ top.left = left;
+ top.red = false;
+ top.right = maketreer(ref rest, blackheight - 1, maxred, red - lred);
+#if BAG
+ top.size = top.items + top.left.size + top.right.size;
+#elif MAINTAIN_SIZE
+ top.size = (maxred << 1) - 1 + red;
+#endif
+ return top;
+ }
+ }
+
+
+ void addSorted<U>(SCG.IEnumerable<U> items, bool safe, bool raise) where U : T
+ {
+ SCG.IEnumerator<U> e = items.GetEnumerator(); ;
+ if (size > 0)
+ throw new InternalException("This can't happen");
+
+ if (!e.MoveNext())
+ return;
+
+ //To count theCollect
+ Node head = new Node(), tail = head;
+ int z = 1;
+ T lastitem = tail.item = e.Current;
+#if BAG
+ int ec = 0;
+#endif
+
+ while (e.MoveNext())
+ {
+#if BAG
+ T thisitem = e.Current;
+ int comp = comparer.Compare(lastitem, thisitem);
+ if (comp > 0)
+ throw new ArgumentException("Argument not sorted");
+ if (comp == 0)
+ {
+ tail.items++;
+ ec++;
+ }
+ else
+ {
+ tail.size = tail.items;
+ z++;
+ tail.right = new Node();
+ tail = tail.right;
+ lastitem = tail.item = thisitem;
+#if NCP
+ tail.generation = generation;
+#endif
+ }
+#else
+ z++;
+ tail.right = new Node();
+ tail = tail.right;
+ tail.item = e.Current;
+ if (safe)
+ {
+ if (comparer.Compare(lastitem, tail.item) >= 0)
+ throw new ArgumentException("Argument not sorted");
+
+ lastitem = tail.item;
+ }
+#if NCP
+ tail.generation = generation;
+#endif
+#endif
+ }
+#if BAG
+ tail.size = tail.items;
+#endif
+ int blackheight = 0, red = z, maxred = 1;
+
+ while (maxred <= red)
+ {
+ red -= maxred;
+ maxred <<= 1;
+ blackheight++;
+ }
+
+ root = TreeSet<T>.maketreer(ref head, blackheight, maxred, red);
+ blackdepth = blackheight;
+ size = z;
+#if BAG
+ size += ec;
+#endif
+
+ if (raise)
+ {
+ if ((ActiveEvents & EventTypeEnum.Added) != 0)
+ {
+ CircularQueue<T> wasAdded = new CircularQueue<T>();
+ foreach (T item in this)
+ wasAdded.Enqueue(item);
+ foreach (T item in wasAdded)
+ raiseItemsAdded(item, 1);
+ }
+ if ((ActiveEvents & EventTypeEnum.Changed) != 0)
+ raiseCollectionChanged();
+ }
+ return;
+ }
+
+ #endregion
+
+#if BAG
+ /// <summary></summary>
+ /// <value>True since this collection has bag semantics.</value>
+ [Tested]
+ public bool AllowsDuplicates { [Tested]get { return true; } }
+#else
+ /// <summary></summary>
+ /// <value>False since this tree has set semantics.</value>
+ [Tested]
+ public bool AllowsDuplicates { [Tested]get { return false; } }
+#endif
+ /// <summary>
+ /// By convention this is true for any collection with set semantics.
+ /// </summary>
+ /// <value>True if only one representative of a group of equal items
+ /// is kept in the collection together with the total count.</value>
+ public virtual bool DuplicatesByCounting { get { return true; } }
+
+ #endregion
+
+ #region IEditableCollection<T> Members
+
+
+ /// <summary>
+ /// The value is symbolic indicating the type of asymptotic complexity
+ /// in terms of the size of this collection (worst-case or amortized as
+ /// relevant).
+ /// </summary>
+ /// <value>Speed.Log</value>
+ [Tested]
+ public Speed ContainsSpeed { [Tested]get { return Speed.Log; } }
+
+ /// <summary>
+ /// Check if this collection contains (an item equivalent to according to the
+ /// itemequalityComparer) a particular value.
+ /// </summary>
+ /// <param name="item">The value to check for.</param>
+ /// <returns>True if the items is in this collection.</returns>
+ [Tested]
+ public bool Contains(T item)
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ Node next; int comp = 0;
+
+ next = root;
+ while (next != null)
+ {
+ comp = comparer.Compare(next.item, item);
+ if (comp == 0)
+ return true;
+
+ next = comp < 0 ? right(next) : left(next);
+ }
+
+ return false;
+ }
+
+
+ //Variant for dictionary use
+ //Will return the actual matching item in the ref argument.
+ /// <summary>
+ /// Check if this collection contains an item equivalent according to the
+ /// itemequalityComparer to a particular value. If so, return in the ref argument (a
+ /// binary copy of) the actual value found.
+ /// </summary>
+ /// <param name="item">The value to look for.</param>
+ /// <returns>True if the items is in this collection.</returns>
+ [Tested]
+ public bool Find(ref T item)
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ Node next; int comp = 0;
+
+ next = root;
+ while (next != null)
+ {
+ comp = comparer.Compare(next.item, item);
+ if (comp == 0)
+ {
+ item = next.item;
+ return true;
+ }
+
+ next = comp < 0 ? right(next) : left(next);
+ }
+
+ return false;
+ }
+
+
+ /// <summary>
+ /// Find or add the item to the tree. If the tree does not contain
+ /// an item equivalent to this item add it, else return the exisiting
+ /// one in the ref argument.
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ /// <returns>True if item was found</returns>
+ [Tested]
+ public bool FindOrAdd(ref T item)
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ updatecheck();
+ bool wasfound;
+
+ //Note: blackdepth of the tree is set inside addIterative
+ if (addIterative(item, ref item, false, out wasfound))
+ {
+ size++;
+ if (ActiveEvents != 0 && !wasfound)
+ raiseForAdd(item);
+ return wasfound;
+ }
+ else
+ return true;
+
+ }
+
+
+ //For dictionary use.
+ //If found, the matching entry will be updated with the new item.
+ /// <summary>
+ /// Check if this collection contains an item equivalent according to the
+ /// itemequalityComparer to a particular value. If so, update the item in the collection
+ /// to with a binary copy of the supplied value. If the collection has bag semantics,
+ /// this updates all equivalent copies in
+ /// the collection.
+ /// </summary>
+ /// <param name="item">Value to update.</param>
+ /// <returns>True if the item was found and hence updated.</returns>
+ [Tested]
+ public bool Update(T item)
+ {
+ T olditem = item;
+ return Update(item, out olditem);
+ }
+
+ /// <summary>
+ /// Check if this collection contains an item equivalent according to the
+ /// itemequalityComparer to a particular value. If so, update the item in the collection
+ /// with a binary copy of the supplied value. If the collection has bag semantics,
+ /// this updates all equivalent copies in
+ /// the collection.
+ /// </summary>
+ /// <param name="item"></param>
+ /// <param name="olditem"></param>
+ /// <returns></returns>
+ public bool Update(T item, out T olditem)
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ updatecheck();
+#if NCP
+ stackcheck();
+
+ int level = 0;
+#endif
+ Node cursor = root;
+ int comp = 0;
+
+ while (cursor != null)
+ {
+ comp = comparer.Compare(cursor.item, item);
+ if (comp == 0)
+ {
+#if NCP
+ Node.CopyNode(ref cursor, maxsnapid, generation);
+#endif
+ olditem = cursor.item;
+#if BAG
+ int items = cursor.items;
+#endif
+ cursor.item = item;
+#if NCP
+ while (level > 0)
+ {
+ Node child = cursor;
+
+ cursor = path[--level];
+ path[level] = null;
+#if NCP
+ Node.update(ref cursor, dirs[level] > 0, child, maxsnapid, generation);
+#else
+ if (Node.CopyNode(maxsnapid, ref cursor, generation))
+ {
+ if (dirs[level] > 0)
+ cursor.left = child;
+ else
+ cursor.right = child;
+ }
+#endif
+ }
+
+ root = cursor;
+#endif
+#if BAG
+ if (ActiveEvents != 0)
+ raiseForUpdate(item, olditem, items);
+#else
+ if (ActiveEvents != 0)
+ raiseForUpdate(item, olditem);
+#endif
+ return true;
+ }
+#if NCP
+ dirs[level] = comp;
+ path[level++] = cursor;
+#endif
+ cursor = comp < 0 ? cursor.right : cursor.left;
+ }
+
+ olditem = default(T);
+ return false;
+ }
+
+
+ /// <summary>
+ /// Check if this collection contains an item equivalent according to the
+ /// itemequalityComparer to a particular value. If so, update the item in the collection
+ /// with a binary copy of the supplied value; else add the value to the collection.
+ ///
+ /// <i>NOTE: the bag implementation is currently wrong! ?????</i>
+ /// </summary>
+ /// <param name="item">Value to add or update.</param>
+ /// <returns>True if the item was found and updated (hence not added).</returns>
+ [Tested]
+ public bool UpdateOrAdd(T item)
+ { T olditem; return UpdateOrAdd(item, out olditem); }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item"></param>
+ /// <param name="olditem"></param>
+ /// <returns></returns>
+ public bool UpdateOrAdd(T item, out T olditem)
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ updatecheck();
+ bool wasfound;
+ olditem = default(T);
+
+
+ //Note: blackdepth of the tree is set inside addIterative
+ if (addIterative(item, ref olditem, true, out wasfound))
+ {
+ size++;
+ if (ActiveEvents != 0)
+ raiseForAdd(wasfound ? olditem : item);
+ return wasfound;
+ }
+ else
+ {
+#warning for bag implementation: count is wrong
+ if (ActiveEvents != 0)
+ raiseForUpdate(item, olditem, 1);
+ return true;
+ }
+ }
+
+
+ /// <summary>
+ /// Remove a particular item from this collection. If the collection has bag
+ /// semantics only one copy equivalent to the supplied item is removed.
+ /// </summary>
+ /// <param name="item">The value to remove.</param>
+ /// <returns>True if the item was found (and removed).</returns>
+ [Tested]
+ public bool Remove(T item)
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ updatecheck();
+ if (root == null)
+ return false;
+
+ int junk;
+ bool retval = removeIterative(ref item, false, out junk);
+ if (ActiveEvents != 0 && retval)
+ raiseForRemove(item);
+ return retval;
+ }
+
+ /// <summary>
+ /// Remove a particular item from this collection if found. If the collection
+ /// has bag semantics only one copy equivalent to the supplied item is removed,
+ /// which one is implementation dependent.
+ /// If an item was removed, report a binary copy of the actual item removed in
+ /// the argument.
+ /// </summary>
+ /// <param name="item">The value to remove.</param>
+ /// <param name="removeditem">The removed value.</param>
+ /// <returns>True if the item was found (and removed).</returns>
+ [Tested]
+ public bool Remove(T item, out T removeditem)
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ updatecheck();
+ removeditem = item;
+ if (root == null)
+ return false;
+
+ int junk;
+ bool retval = removeIterative(ref removeditem, false, out junk);
+ if (ActiveEvents != 0 && retval)
+ raiseForRemove(item);
+ return retval;
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="item">input: item to remove; output: item actually removed</param>
+ /// <param name="all">If true, remove all copies</param>
+ /// <param name="wasRemoved"></param>
+ /// <returns></returns>
+ private bool removeIterative(ref T item, bool all, out int wasRemoved)
+ {
+ wasRemoved = 0;
+ //Stage 1: find item
+ stackcheck();
+
+ int level = 0, comp;
+ Node cursor = root;
+
+ while (true)
+ {
+ comp = comparer.Compare(cursor.item, item);
+ if (comp == 0)
+ {
+ item = cursor.item;
+#if BAG
+ if (!all && cursor.items > 1)
+ {
+#if NCP
+ Node.CopyNode(ref cursor, maxsnapid, generation);
+#endif
+ cursor.items--;
+ cursor.size--;
+ while (level-- > 0)
+ {
+ Node kid = cursor;
+
+ cursor = path[level];
+#if NCP
+ Node.update(ref cursor, dirs[level] > 0, kid, maxsnapid, generation);
+#endif
+ cursor.size--;
+ path[level] = null;
+ }
+ size--;
+ wasRemoved = 1;
+ return true;
+ }
+ wasRemoved = cursor.items;
+#else
+ wasRemoved = 1;
+#endif
+ break;
+ }
+
+ Node child = comp > 0 ? cursor.left : cursor.right;
+
+ if (child == null)
+ return false;
+
+ dirs[level] = comp;
+ path[level++] = cursor;
+ cursor = child;
+ }
+
+ return removeIterativePhase2(cursor, level);
+ }
+
+
+ private bool removeIterativePhase2(Node cursor, int level)
+ {
+ if (size == 1)
+ {
+ clear();
+ return true;
+ }
+
+#if BAG
+ int removedcount = cursor.items;
+ size -= removedcount;
+#else
+ //We are certain to remove one node:
+ size--;
+#endif
+ //Stage 2: if item's node has no null child, find predecessor
+ int level_of_item = level;
+
+ if (cursor.left != null && cursor.right != null)
+ {
+ dirs[level] = 1;
+ path[level++] = cursor;
+ cursor = cursor.left;
+ while (cursor.right != null)
+ {
+ dirs[level] = -1;
+ path[level++] = cursor;
+ cursor = cursor.right;
+ }
+#if NCP
+ Node.CopyNode(ref path[level_of_item], maxsnapid, generation);
+#endif
+ path[level_of_item].item = cursor.item;
+#if BAG
+ path[level_of_item].items = cursor.items;
+#endif
+ }
+
+ //Stage 3: splice out node to be removed
+ Node newchild = cursor.right == null ? cursor.left : cursor.right;
+ bool demote_or_rotate = newchild == null && !cursor.red;
+
+ //assert newchild.red
+ if (newchild != null)
+ {
+ newchild.red = false;
+ }
+
+ if (level == 0)
+ {
+ root = newchild;
+ return true;
+ }
+
+ level--;
+ cursor = path[level];
+ path[level] = null;
+
+ int comp = dirs[level];
+ Node childsibling;
+#if NCP
+ Node.update(ref cursor, comp > 0, newchild, maxsnapid, generation);
+#else
+ if (comp > 0)
+ cursor.left = newchild;
+ else
+ cursor.right = newchild;
+#endif
+ childsibling = comp > 0 ? cursor.right : cursor.left;
+#if BAG
+ cursor.size -= removedcount;
+#elif MAINTAIN_SIZE
+ cursor.size--;
+#endif
+
+ //Stage 4: demote till we must rotate
+ Node farnephew = null, nearnephew = null;
+
+ while (demote_or_rotate)
+ {
+ if (childsibling.red)
+ break; //rotate 2+?
+
+ farnephew = comp > 0 ? childsibling.right : childsibling.left;
+ if (farnephew != null && farnephew.red)
+ break; //rotate 1b
+
+ nearnephew = comp > 0 ? childsibling.left : childsibling.right;
+ if (nearnephew != null && nearnephew.red)
+ break; //rotate 1c
+
+ //demote cursor
+ childsibling.red = true;
+ if (level == 0)
+ {
+ cursor.red = false;
+ blackdepth--;
+#if NCP
+ root = cursor;
+#endif
+ return true;
+ }
+ else if (cursor.red)
+ {
+ cursor.red = false;
+ demote_or_rotate = false;
+ break; //No rotation
+ }
+ else
+ {
+ Node child = cursor;
+
+ cursor = path[--level];
+ path[level] = null;
+ comp = dirs[level];
+ childsibling = comp > 0 ? cursor.right : cursor.left;
+#if NCP
+ Node.update(ref cursor, comp > 0, child, maxsnapid, generation);
+#endif
+#if BAG
+ cursor.size -= removedcount;
+#elif MAINTAIN_SIZE
+ cursor.size--;
+#endif
+ }
+ }
+
+ //Stage 5: rotate
+ if (demote_or_rotate)
+ {
+ //At start:
+ //parent = cursor (temporary for swapping nodes)
+ //childsibling is the sibling of the updated child (x)
+ //cursor is always the top of the subtree
+ Node parent = cursor;
+
+ if (childsibling.red)
+ {//Case 2 and perhaps more.
+ //The y.rank == px.rank >= x.rank+2 >=2 so both nephews are != null
+ //(and black). The grandnephews are children of nearnephew
+ Node neargrandnephew, fargrandnephew;
+
+ if (comp > 0)
+ {
+ nearnephew = childsibling.left;
+ farnephew = childsibling.right;
+ neargrandnephew = nearnephew.left;
+ fargrandnephew = nearnephew.right;
+ }
+ else
+ {
+ nearnephew = childsibling.right;
+ farnephew = childsibling.left;
+ neargrandnephew = nearnephew.right;
+ fargrandnephew = nearnephew.left;
+ }
+
+ if (fargrandnephew != null && fargrandnephew.red)
+ {//Case 2+1b
+#if NCP
+ Node.CopyNode(ref nearnephew, maxsnapid, generation);
+
+ //The end result of this will always be e copy of parent
+ Node.update(ref parent, comp < 0, neargrandnephew, maxsnapid, generation);
+ Node.update(ref childsibling, comp > 0, nearnephew, maxsnapid, generation);
+#endif
+ if (comp > 0)
+ {
+ nearnephew.left = parent;
+ parent.right = neargrandnephew;
+ }
+ else
+ {
+ nearnephew.right = parent;
+ parent.left = neargrandnephew;
+ }
+
+ cursor = childsibling;
+ childsibling.red = false;
+ nearnephew.red = true;
+ fargrandnephew.red = false;
+#if BAG
+ cursor.size = parent.size;
+ nearnephew.size = cursor.size - cursor.items - farnephew.size;
+ parent.size = nearnephew.size - nearnephew.items - fargrandnephew.size;
+#elif MAINTAIN_SIZE
+ cursor.size = parent.size;
+ nearnephew.size = cursor.size - 1 - farnephew.size;
+ parent.size = nearnephew.size - 1 - fargrandnephew.size;
+#endif
+ }
+ else if (neargrandnephew != null && neargrandnephew.red)
+ {//Case 2+1c
+#if NCP
+ Node.CopyNode(ref neargrandnephew, maxsnapid, generation);
+#endif
+ if (comp > 0)
+ {
+#if NCP
+ Node.update(ref childsibling, true, neargrandnephew, maxsnapid, generation);
+ Node.update(ref nearnephew, true, neargrandnephew.right, maxsnapid, generation);
+ Node.update(ref parent, false, neargrandnephew.left, maxsnapid, generation);
+#else
+ childsibling.left = neargrandnephew;
+ nearnephew.left = neargrandnephew.right;
+ parent.right = neargrandnephew.left;
+#endif
+ neargrandnephew.left = parent;
+ neargrandnephew.right = nearnephew;
+ }
+ else
+ {
+#if NCP
+ Node.update(ref childsibling, false, neargrandnephew, maxsnapid, generation);
+ Node.update(ref nearnephew, false, neargrandnephew.left, maxsnapid, generation);
+ Node.update(ref parent, true, neargrandnephew.right, maxsnapid, generation);
+#else
+ childsibling.right = neargrandnephew;
+ nearnephew.right = neargrandnephew.left;
+ parent.left = neargrandnephew.right;
+#endif
+ neargrandnephew.right = parent;
+ neargrandnephew.left = nearnephew;
+ }
+
+ cursor = childsibling;
+ childsibling.red = false;
+#if BAG
+ cursor.size = parent.size;
+ parent.size = parent.items + (parent.left == null ? 0 : parent.left.size) + (parent.right == null ? 0 : parent.right.size);
+ nearnephew.size = nearnephew.items + (nearnephew.left == null ? 0 : nearnephew.left.size) + (nearnephew.right == null ? 0 : nearnephew.right.size);
+ neargrandnephew.size = neargrandnephew.items + parent.size + nearnephew.size;
+#elif MAINTAIN_SIZE
+ cursor.size = parent.size;
+ parent.size = 1 + (parent.left == null ? 0 : parent.left.size) + (parent.right == null ? 0 : parent.right.size);
+ nearnephew.size = 1 + (nearnephew.left == null ? 0 : nearnephew.left.size) + (nearnephew.right == null ? 0 : nearnephew.right.size);
+ neargrandnephew.size = 1 + parent.size + nearnephew.size;
+#endif
+ }
+ else
+ {//Case 2 only
+#if NCP
+ Node.update(ref parent, comp < 0, nearnephew, maxsnapid, generation);
+ Node.update(ref childsibling, comp > 0, parent, maxsnapid, generation);
+#else
+ if (comp > 0)
+ {
+ childsibling.left = parent;
+ parent.right = nearnephew;
+ }
+ else
+ {
+ childsibling.right = parent;
+ parent.left = nearnephew;
+ }
+#endif
+ cursor = childsibling;
+ childsibling.red = false;
+ nearnephew.red = true;
+#if BAG
+ cursor.size = parent.size;
+ parent.size -= farnephew.size + cursor.items;
+#elif MAINTAIN_SIZE
+ cursor.size = parent.size;
+ parent.size -= farnephew.size + 1;
+#endif
+ }
+ }
+ else if (farnephew != null && farnephew.red)
+ {//Case 1b
+ nearnephew = comp > 0 ? childsibling.left : childsibling.right;
+#if NCP
+ Node.update(ref parent, comp < 0, nearnephew, maxsnapid, generation);
+ Node.CopyNode(ref childsibling, maxsnapid, generation);
+ if (comp > 0)
+ {
+ childsibling.left = parent;
+ childsibling.right = farnephew;
+ }
+ else
+ {
+ childsibling.right = parent;
+ childsibling.left = farnephew;
+ }
+#else
+ if (comp > 0)
+ {
+ childsibling.left = parent;
+ parent.right = nearnephew;
+ }
+ else
+ {
+ childsibling.right = parent;
+ parent.left = nearnephew;
+ }
+#endif
+ cursor = childsibling;
+ cursor.red = parent.red;
+ parent.red = false;
+ farnephew.red = false;
+
+#if BAG
+ cursor.size = parent.size;
+ parent.size -= farnephew.size + cursor.items;
+#elif MAINTAIN_SIZE
+ cursor.size = parent.size;
+ parent.size -= farnephew.size + 1;
+#endif
+ }
+ else if (nearnephew != null && nearnephew.red)
+ {//Case 1c
+#if NCP
+ Node.CopyNode(ref nearnephew, maxsnapid, generation);
+#endif
+ if (comp > 0)
+ {
+#if NCP
+ Node.update(ref childsibling, true, nearnephew.right, maxsnapid, generation);
+ Node.update(ref parent, false, nearnephew.left, maxsnapid, generation);
+#else
+ childsibling.left = nearnephew.right;
+ parent.right = nearnephew.left;
+#endif
+ nearnephew.left = parent;
+ nearnephew.right = childsibling;
+ }
+ else
+ {
+#if NCP
+ Node.update(ref childsibling, false, nearnephew.left, maxsnapid, generation);
+ Node.update(ref parent, true, nearnephew.right, maxsnapid, generation);
+#else
+ childsibling.right = nearnephew.left;
+ parent.left = nearnephew.right;
+#endif
+ nearnephew.right = parent;
+ nearnephew.left = childsibling;
+ }
+
+ cursor = nearnephew;
+ cursor.red = parent.red;
+ parent.red = false;
+#if BAG
+ cursor.size = parent.size;
+ parent.size = parent.items + (parent.left == null ? 0 : parent.left.size) + (parent.right == null ? 0 : parent.right.size);
+ childsibling.size = childsibling.items + (childsibling.left == null ? 0 : childsibling.left.size) + (childsibling.right == null ? 0 : childsibling.right.size);
+#elif MAINTAIN_SIZE
+ cursor.size = parent.size;
+ parent.size = 1 + (parent.left == null ? 0 : parent.left.size) + (parent.right == null ? 0 : parent.right.size);
+ childsibling.size = 1 + (childsibling.left == null ? 0 : childsibling.left.size) + (childsibling.right == null ? 0 : childsibling.right.size);
+#endif
+ }
+ else
+ {//Case 1a can't happen
+ throw new InternalException("Case 1a can't happen here");
+ }
+
+ //Resplice cursor:
+ if (level == 0)
+ {
+ root = cursor;
+ }
+ else
+ {
+ Node swap = cursor;
+
+ cursor = path[--level];
+ path[level] = null;
+#if NCP
+ Node.update(ref cursor, dirs[level] > 0, swap, maxsnapid, generation);
+#else
+
+ if (dirs[level] > 0)
+ cursor.left = swap;
+ else
+ cursor.right = swap;
+#endif
+#if BAG
+ cursor.size -= removedcount;
+#elif MAINTAIN_SIZE
+ cursor.size--;
+#endif
+ }
+ }
+
+ //Stage 6: fixup to the root
+ while (level > 0)
+ {
+ Node child = cursor;
+
+ cursor = path[--level];
+ path[level] = null;
+#if NCP
+ if (child != (dirs[level] > 0 ? cursor.left : cursor.right))
+ Node.update(ref cursor, dirs[level] > 0, child, maxsnapid, generation);
+#endif
+#if BAG
+ cursor.size -= removedcount;
+#elif MAINTAIN_SIZE
+ cursor.size--;
+#endif
+ }
+
+#if NCP
+ root = cursor;
+#endif
+ return true;
+ }
+
+
+ /// <summary>
+ /// Remove all items from this collection.
+ /// </summary>
+ [Tested]
+ public void Clear()
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ updatecheck();
+ if (size == 0)
+ return;
+ int oldsize = size;
+ clear();
+ if ((ActiveEvents & EventTypeEnum.Cleared) != 0)
+ raiseCollectionCleared(true, oldsize);
+ if ((ActiveEvents & EventTypeEnum.Changed) != 0)
+ raiseCollectionChanged();
+ }
+
+
+ private void clear()
+ {
+ size = 0;
+ root = null;
+ blackdepth = 0;
+ }
+
+
+ /// <summary>
+ /// Remove all items in another collection from this one. If this collection
+ /// has bag semantics, take multiplicities into account.
+ /// </summary>
+ /// <typeparam name="U"></typeparam>
+ /// <param name="items">The items to remove.</param>
+ [Tested]
+ public void RemoveAll<U>(SCG.IEnumerable<U> items) where U : T
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ updatecheck();
+
+ T jtem;
+
+ bool mustRaise = (ActiveEvents & (EventTypeEnum.Removed | EventTypeEnum.Changed)) != 0;
+ RaiseForRemoveAllHandler raiseHandler = mustRaise ? new RaiseForRemoveAllHandler(this) : null;
+
+ foreach (T item in items)
+ {
+ if (root == null)
+ break;
+
+ jtem = item;
+ int junk;
+ if (removeIterative(ref jtem, false, out junk) && mustRaise)
+ raiseHandler.Remove(jtem);
+ }
+ if (mustRaise)
+ raiseHandler.Raise();
+ }
+
+ /// <summary>
+ /// Remove all items not in some other collection from this one. If this collection
+ /// has bag semantics, take multiplicities into account.
+ /// </summary>
+ /// <typeparam name="U"></typeparam>
+ /// <param name="items">The items to retain.</param>
+ [Tested]
+ public void RetainAll<U>(SCG.IEnumerable<U> items) where U : T
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ updatecheck();
+
+ //A much more efficient version is possible if items is sorted like this.
+ //Well, it is unclear how efficient it would be.
+ //We could use a marking method!?
+#warning how does this work together with persistence?
+ TreeSet<T> t = (TreeSet<T>)MemberwiseClone();
+
+ T jtem = default(T);
+ t.clear();
+ foreach (T item in items)
+ if (ContainsCount(item) > t.ContainsCount(item))
+ {
+ t.add(item, ref jtem);
+ }
+ if (size == t.size)
+ return;
+
+#warning improve (mainly for bag) by usig a Node iterator instead of ItemMultiplicities()
+ CircularQueue<KeyValuePair<T, int>> wasRemoved = null;
+ if ((ActiveEvents & EventTypeEnum.Removed) != 0)
+ {
+ wasRemoved = new CircularQueue<KeyValuePair<T, int>>();
+ SCG.IEnumerator<KeyValuePair<T, int>> ie = ItemMultiplicities().GetEnumerator();
+ foreach (KeyValuePair<T, int> p in t.ItemMultiplicities())
+ {
+ //We know p.Key is in this!
+ while (ie.MoveNext())
+ {
+ if (comparer.Compare(ie.Current.Key, p.Key) == 0)
+ {
+#if BAG
+ int removed = ie.Current.Value - p.Value;
+ if (removed > 0)
+ wasRemoved.Enqueue(new KeyValuePair<T,int>(p.Key, removed));
+#endif
+ break;
+ }
+ else
+ wasRemoved.Enqueue(ie.Current);
+ }
+ }
+ while (ie.MoveNext())
+ wasRemoved.Enqueue(ie.Current);
+ }
+
+ root = t.root;
+ size = t.size;
+ blackdepth = t.blackdepth;
+ if (wasRemoved != null)
+ foreach (KeyValuePair<T, int> p in wasRemoved)
+ raiseItemsRemoved(p.Key, p.Value);
+ if ((ActiveEvents & EventTypeEnum.Changed) != 0)
+ raiseCollectionChanged();
+ }
+
+ /// <summary>
+ /// Check if this collection contains all the values in another collection.
+ /// If this collection has bag semantics (<code>AllowsDuplicates==true</code>)
+ /// the check is made with respect to multiplicities, else multiplicities
+ /// are not taken into account.
+ /// </summary>
+ /// <param name="items">The </param>
+ /// <typeparam name="U"></typeparam>
+ /// <returns>True if all values in <code>items</code>is in this collection.</returns>
+ [Tested]
+ public bool ContainsAll<U>(SCG.IEnumerable<U> items) where U : T
+ {
+ //TODO: fix bag implementation
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ //This is worst-case O(m*logn)
+ foreach (T item in items)
+ if (!Contains(item)) return false;
+
+ return true;
+ }
+
+
+ //Higher order:
+ /// <summary>
+ /// Create a new indexed sorted collection consisting of the items of this
+ /// indexed sorted collection satisfying a certain predicate.
+ /// </summary>
+ /// <param name="filter">The filter delegate defining the predicate.</param>
+ /// <returns>The new indexed sorted collection.</returns>
+ [Tested]
+ public IIndexedSorted<T> FindAll(Fun<T, bool> filter)
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ TreeSet<T> res = new TreeSet<T>(comparer);
+ SCG.IEnumerator<T> e = GetEnumerator();
+ Node head = null, tail = null;
+ int z = 0;
+#if BAG
+ int ec = 0;
+#endif
+ while (e.MoveNext())
+ {
+ T thisitem = e.Current;
+#if BAG
+ //We could document that filter will only be called
+ //once on each unique item. That might even be good for the user!
+ if (tail != null && comparer.Compare(thisitem, tail.item) == 0)
+ {
+ tail.items++;
+ ec++;
+ continue;
+ }
+#endif
+ if (filter(thisitem))
+ {
+ if (head == null)
+ {
+ head = tail = new Node();
+ }
+ else
+ {
+#if BAG
+ tail.size = tail.items;
+#endif
+ tail.right = new Node();
+ tail = tail.right;
+ }
+
+ tail.item = thisitem;
+ z++;
+ }
+ }
+#if BAG
+ if (tail != null)
+ tail.size = tail.items;
+#endif
+
+ if (z == 0)
+ return res;
+
+ int blackheight = 0, red = z, maxred = 1;
+
+ while (maxred <= red)
+ {
+ red -= maxred;
+ maxred <<= 1;
+ blackheight++;
+ }
+
+ res.root = TreeSet<T>.maketreer(ref head, blackheight, maxred, red);
+ res.blackdepth = blackheight;
+ res.size = z;
+#if BAG
+ res.size += ec;
+#endif
+ return res;
+ }
+
+
+ /// <summary>
+ /// Create a new indexed sorted collection consisting of the results of
+ /// mapping all items of this list.
+ /// <exception cref="ArgumentException"/> if the map is not increasing over
+ /// the items of this collection (with respect to the two given comparison
+ /// relations).
+ /// </summary>
+ /// <param name="mapper">The delegate definging the map.</param>
+ /// <param name="c">The comparion relation to use for the result.</param>
+ /// <returns>The new sorted collection.</returns>
+ [Tested]
+ public IIndexedSorted<V> Map<V>(Fun<T, V> mapper, SCG.IComparer<V> c)
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ TreeSet<V> res = new TreeSet<V>(c);
+
+ if (size == 0)
+ return res;
+
+ SCG.IEnumerator<T> e = GetEnumerator();
+ TreeSet<V>.Node head = null, tail = null;
+ V oldv = default(V);
+ int z = 0;
+#if BAG
+ T lastitem = default(T);
+#endif
+ while (e.MoveNext())
+ {
+ T thisitem = e.Current;
+#if BAG
+ //We could document that mapper will only be called
+ //once on each unique item. That might even be good for the user!
+ if (tail != null && comparer.Compare(thisitem, lastitem) == 0)
+ {
+ tail.items++;
+ continue;
+ }
+#endif
+ V newv = mapper(thisitem);
+
+ if (head == null)
+ {
+ head = tail = new TreeSet<V>.Node();
+ z++;
+ }
+ else
+ {
+ int comp = c.Compare(oldv, newv);
+#if BAG
+ if (comp == 0)
+ {
+ tail.items++;
+ continue;
+ }
+ if (comp > 0)
+#else
+ if (comp >= 0)
+#endif
+ throw new ArgumentException("mapper not monotonic");
+#if BAG
+ tail.size = tail.items;
+#endif
+ tail.right = new TreeSet<V>.Node();
+ tail = tail.right;
+ z++;
+ }
+#if BAG
+ lastitem = thisitem;
+#endif
+ tail.item = oldv = newv;
+ }
+
+#if BAG
+ tail.size = tail.items;
+#endif
+
+ int blackheight = 0, red = z, maxred = 1;
+
+ while (maxred <= red)
+ {
+ red -= maxred;
+ maxred <<= 1;
+ blackheight++;
+ }
+
+ res.root = TreeSet<V>.maketreer(ref head, blackheight, maxred, red);
+ res.blackdepth = blackheight;
+ res.size = size;
+ return res;
+ }
+
+
+ //below is the bag utility stuff
+ /// <summary>
+ /// Count the number of items of the collection equal to a particular value.
+ /// Returns 0 if and only if the value is not in the collection.
+ /// </summary>
+ /// <param name="item">The value to count.</param>
+ /// <returns>The number of copies found.</returns>
+ [Tested]
+ public int ContainsCount(T item)
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+#if BAG
+ Node next; int comp = 0;
+
+ next = root;
+ while (next != null)
+ {
+ comp = comparer.Compare(next.item, item);
+ if (comp == 0)
+ return next.items;
+
+ next = comp < 0 ? right(next) : left(next);
+ }
+
+ return 0;
+#else
+ //Since we are strictly not AllowsDuplicates we just do
+ return Contains(item) ? 1 : 0;
+#endif
+ }
+
+#if BAG
+ //TODO: make work with snapshots
+ class Multiplicities : CollectionValueBase<KeyValuePair<T, int>>, ICollectionValue<KeyValuePair<T, int>>
+ {
+ TreeBag<T> treebag;
+ int origstamp;
+ internal Multiplicities(TreeBag<T> treebag) { this.treebag = treebag; this.origstamp = treebag.stamp; }
+ public override KeyValuePair<T, int> Choose() { return new KeyValuePair<T, int>(treebag.root.item, treebag.root.items); }
+
+ public override SCG.IEnumerator<KeyValuePair<T, int>> GetEnumerator()
+ {
+ return getEnumerator(treebag.root, origstamp); //TODO: NBNBNB
+ }
+
+ private SCG.IEnumerator<KeyValuePair<T, int>> getEnumerator(Node node, int origstamp)
+ {
+ if (node == null)
+ yield break;
+
+ if (node.left != null)
+ {
+ SCG.IEnumerator<KeyValuePair<T, int>> child = getEnumerator(node.left, origstamp);
+
+ while (child.MoveNext())
+ {
+ treebag.modifycheck(origstamp);
+ yield return child.Current;
+ }
+ }
+ yield return new KeyValuePair<T, int>(node.item, node.items);
+ if (node.right != null)
+ {
+ SCG.IEnumerator<KeyValuePair<T, int>> child = getEnumerator(node.right, origstamp);
+
+ while (child.MoveNext())
+ {
+ treebag.modifycheck(origstamp);
+ yield return child.Current;
+ }
+ }
+ }
+
+ public override bool IsEmpty { get { return treebag.IsEmpty; } }
+ public override int Count { get { int i = 0; foreach (KeyValuePair<T, int> p in this) i++; return i; } } //TODO: make better
+ public override Speed CountSpeed { get { return Speed.Linear; } } //TODO: make better
+ }
+#endif
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public virtual ICollectionValue<T> UniqueItems()
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+#if BAG
+ return new DropMultiplicity<T>(ItemMultiplicities());
+#else
+ return this;
+#endif
+ }
+
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public virtual ICollectionValue<KeyValuePair<T, int>> ItemMultiplicities()
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+#if BAG
+ return new Multiplicities(this);
+#else
+ return new MultiplicityOne<T>(this);
+#endif
+ }
+
+ /// <summary>
+ /// Remove all items equivalent to a given value.
+ /// </summary>
+ /// <param name="item">The value to remove.</param>
+ [Tested]
+ public void RemoveAllCopies(T item)
+ {
+#if BAG
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ updatecheck();
+ int removed;
+ if (removeIterative(ref item, true, out removed) && ActiveEvents != 0)
+ {
+ raiseForRemove(item, removed);
+ }
+#else
+ Remove(item);
+#endif
+ }
+
+
+ #endregion
+
+ #region IIndexed<T> Members
+
+ private Node findNode(int i)
+ {
+#if NCP
+ if (isSnapShot)
+ throw new NotSupportedException("Indexing not supported for snapshots");
+#endif
+#if MAINTAIN_SIZE
+ Node next = root;
+
+ if (i >= 0 && i < size)
+ while (true)
+ {
+ int j = next.left == null ? 0 : next.left.size;
+
+ if (i > j)
+ {
+#if BAG
+ i -= j + next.items;
+ if (i < 0)
+ return next;
+#else
+ i -= j + 1;
+#endif
+ next = next.right;
+ }
+ else if (i == j)
+ return next;
+ else
+ next = next.left;
+ }
+
+ throw new IndexOutOfRangeException();
+#else
+ throw new NotSupportedException();
+#endif
+ }
+
+
+ /// <summary>
+ /// <exception cref="IndexOutOfRangeException"/> if i is negative or
+ /// &gt;= the size of the collection.
+ /// </summary>
+ /// <value>The i'th item of this list.</value>
+ /// <param name="i">the index to lookup</param>
+ [Tested]
+ public T this[int i] { [Tested] get { return findNode(i).item; } }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value></value>
+ public virtual Speed IndexingSpeed { get { return Speed.Log; } }
+
+
+ //TODO: return -upper instead of -1 in case of not found
+ /// <summary>
+ /// Searches for an item in this indexed collection going forwards from the start.
+ /// </summary>
+ /// <param name="item">Item to search for.</param>
+ /// <returns>Index of first occurrence from start of the item
+ /// if found, else the two-complement
+ /// (always negative) of the index at which the item would be put if it was added.</returns>
+ [Tested]
+ public int IndexOf(T item)
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ int upper;
+ return indexOf(item, out upper);
+ }
+
+
+ private int indexOf(T item, out int upper)
+ {
+#if NCP
+ if (isSnapShot)
+ throw new NotSupportedException("Indexing not supported for snapshots");
+#endif
+#if MAINTAIN_SIZE
+ int ind = 0; Node next = root;
+
+ while (next != null)
+ {
+ int comp = comparer.Compare(item, next.item);
+
+ if (comp < 0)
+ next = next.left;
+ else
+ {
+ int leftcnt = next.left == null ? 0 : next.left.size;
+
+ if (comp == 0)
+ {
+#if BAG
+ upper = ind + leftcnt + next.items - 1;
+ return ind + leftcnt;
+#else
+ return upper = ind + leftcnt;
+#endif
+ }
+ else
+ {
+#if BAG
+ ind = ind + next.items + leftcnt;
+#else
+ ind = ind + 1 + leftcnt;
+#endif
+ next = next.right;
+ }
+ }
+ }
+#endif
+ upper = ~ind;
+ return ~ind;
+ }
+
+
+ /// <summary>
+ /// Searches for an item in the tree going backwords from the end.
+ /// </summary>
+ /// <param name="item">Item to search for.</param>
+ /// <returns>Index of last occurrence from the end of item if found,
+ /// else the two-complement (always negative) of the index at which
+ /// the item would be put if it was added.</returns>
+ [Tested]
+ public int LastIndexOf(T item)
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+#if BAG
+ int res;
+ indexOf(item, out res);
+ return res;
+#else
+ //We have AllowsDuplicates==false for the set
+ return IndexOf(item);
+#endif
+ }
+
+
+ /// <summary>
+ /// Remove the item at a specific position of the list.
+ /// <exception cref="IndexOutOfRangeException"/> if i is negative or
+ /// &gt;= the size of the collection.
+ /// </summary>
+ /// <param name="i">The index of the item to remove.</param>
+ /// <returns>The removed item.</returns>
+ [Tested]
+ public T RemoveAt(int i)
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ updatecheck();
+ T retval = removeAt(i);
+ if (ActiveEvents != 0)
+ raiseForRemove(retval);
+ return retval;
+ }
+
+ T removeAt(int i)
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ updatecheck();
+#if MAINTAIN_SIZE
+ if (i < 0 || i >= size)
+ throw new IndexOutOfRangeException("Index out of range for sequenced collectionvalue");
+
+ //We must follow the pattern of removeIterative()
+ while (dirs.Length < 2 * blackdepth)
+ {
+ dirs = new int[2 * dirs.Length];
+ path = new Node[2 * dirs.Length];
+ }
+
+ int level = 0;
+ Node cursor = root;
+
+ while (true)
+ {
+ int j = cursor.left == null ? 0 : cursor.left.size;
+
+ if (i > j)
+ {
+#if BAG
+ i -= j + cursor.items;
+ if (i < 0)
+ break;
+#else
+ i -= j + 1;
+#endif
+ dirs[level] = -1;
+ path[level++] = cursor;
+ cursor = cursor.right;
+ }
+ else if (i == j)
+ break;
+ else
+ {
+ dirs[level] = 1;
+ path[level++] = cursor;
+ cursor = cursor.left;
+ }
+ }
+
+ T retval = cursor.item;
+
+#if BAG
+ if (cursor.items > 1)
+ {
+ resplicebag(level, cursor);
+ size--;
+ return retval;
+ }
+#endif
+ removeIterativePhase2(cursor, level);
+ return retval;
+#else
+ throw new NotSupportedException();
+#endif
+ }
+
+#if BAG
+ private void resplicebag(int level, Node cursor)
+ {
+#if NCP
+ Node.CopyNode(ref cursor, maxsnapid, generation);
+#endif
+ cursor.items--;
+ cursor.size--;
+ while (level-- > 0)
+ {
+ Node kid = cursor;
+
+ cursor = path[level];
+#if NCP
+ Node.update(ref cursor, dirs[level] > 0, kid, maxsnapid, generation);
+#endif
+ cursor.size--;
+ path[level] = null;
+ }
+ }
+#endif
+ /// <summary>
+ /// Remove all items in an index interval.
+ /// <exception cref="IndexOutOfRangeException"/>???.
+ /// </summary>
+ /// <param name="start">The index of the first item to remove.</param>
+ /// <param name="count">The number of items to remove.</param>
+ [Tested]
+ public void RemoveInterval(int start, int count)
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ if (start < 0 || count < 0 || start + count > this.size)
+ throw new ArgumentOutOfRangeException();
+
+ updatecheck();
+
+ if (count == 0)
+ return;
+
+ //This is terrible for large count. We should split the tree at
+ //the endpoints of the range and fuse the parts!
+ //We really need good internal destructive split and catenate functions!
+ //Alternative for large counts: rebuild tree using maketree()
+ for (int i = 0; i < count; i++)
+ removeAt(start);
+
+ if ((ActiveEvents & EventTypeEnum.Cleared) != 0)
+ raiseCollectionCleared(false, count);
+ if ((ActiveEvents & EventTypeEnum.Changed) != 0)
+ raiseCollectionChanged();
+ }
+
+
+ /// <summary>
+ /// <exception cref="IndexOutOfRangeException"/>.
+ /// </summary>
+ /// <value>The directed collection of items in a specific index interval.</value>
+ /// <param name="start">The low index of the interval (inclusive).</param>
+ /// <param name="end">The high index of the interval (exclusive).</param>
+ [Tested]
+ public IDirectedCollectionValue<T> this[int start, int end]
+ {
+ [Tested]
+ get
+ {
+ checkRange(start, end - start);
+ return new Interval(this, start, end - start, true);
+ }
+ }
+
+ #region Interval nested class
+ class Interval : DirectedCollectionValueBase<T>, IDirectedCollectionValue<T>
+ {
+ int start, length, stamp;
+
+ bool forwards;
+
+ TreeSet<T> tree;
+
+
+ internal Interval(TreeSet<T> tree, int start, int count, bool forwards)
+ {
+#if NCP
+ if (tree.isSnapShot)
+ throw new NotSupportedException("Indexing not supported for snapshots");
+#endif
+ this.start = start; this.length = count; this.forwards = forwards;
+ this.tree = tree; this.stamp = tree.stamp;
+ }
+
+ public override bool IsEmpty { get { return length == 0; } }
+
+ [Tested]
+ public override int Count { [Tested]get { return length; } }
+
+
+ public override Speed CountSpeed { get { return Speed.Constant; } }
+
+
+ public override T Choose()
+ {
+ if (length == 0)
+ throw new NoSuchItemException();
+ return tree[start];
+ }
+
+ [Tested]
+ public override SCG.IEnumerator<T> GetEnumerator()
+ {
+#if MAINTAIN_SIZE
+ tree.modifycheck(stamp);
+#if BAG
+ int togo;
+#endif
+ Node cursor = tree.root;
+ Node[] path = new Node[2 * tree.blackdepth];
+ int level = 0, totaltogo = length;
+
+ if (totaltogo == 0)
+ yield break;
+
+ if (forwards)
+ {
+ int i = start;
+
+ while (true)
+ {
+ int j = cursor.left == null ? 0 : cursor.left.size;
+
+ if (i > j)
+ {
+#if BAG
+ i -= j + cursor.items;
+ if (i < 0)
+ {
+ togo = cursor.items + i;
+ break;
+ }
+#else
+ i -= j + 1;
+#endif
+ cursor = cursor.right;
+ }
+ else if (i == j)
+ {
+#if BAG
+ togo = cursor.items;
+#endif
+ break;
+ }
+ else
+ {
+ path[level++] = cursor;
+ cursor = cursor.left;
+ }
+ }
+
+ T current = cursor.item;
+
+ while (totaltogo-- > 0)
+ {
+ yield return current;
+ tree.modifycheck(stamp);
+#if BAG
+ if (--togo > 0)
+ continue;
+#endif
+ if (cursor.right != null)
+ {
+ path[level] = cursor = cursor.right;
+ while (cursor.left != null)
+ path[++level] = cursor = cursor.left;
+ }
+ else if (level == 0)
+ yield break;
+ else
+ cursor = path[--level];
+
+ current = cursor.item;
+#if BAG
+ togo = cursor.items;
+#endif
+ }
+ }
+ else
+ {
+ int i = start + length - 1;
+
+ while (true)
+ {
+ int j = cursor.left == null ? 0 : cursor.left.size;
+
+ if (i > j)
+ {
+#if BAG
+ if (i - j < cursor.items)
+ {
+ togo = i - j + 1;
+ break;
+ }
+ i -= j + cursor.items;
+#else
+ i -= j + 1;
+#endif
+ path[level++] = cursor;
+ cursor = cursor.right;
+ }
+ else if (i == j)
+ {
+#if BAG
+ togo = 1;
+#endif
+ break;
+ }
+ else
+ {
+ cursor = cursor.left;
+ }
+ }
+
+ T current = cursor.item;
+
+ while (totaltogo-- > 0)
+ {
+ yield return current;
+ tree.modifycheck(stamp);
+#if BAG
+ if (--togo > 0)
+ continue;
+#endif
+ if (cursor.left != null)
+ {
+ path[level] = cursor = cursor.left;
+ while (cursor.right != null)
+ path[++level] = cursor = cursor.right;
+ }
+ else if (level == 0)
+ yield break;
+ else
+ cursor = path[--level];
+
+ current = cursor.item;
+#if BAG
+ togo = cursor.items;
+#endif
+ }
+ }
+
+#else
+ throw new NotSupportedException();
+#endif
+ }
+
+
+ [Tested]
+ public override IDirectedCollectionValue<T> Backwards()
+ { return new Interval(tree, start, length, !forwards); }
+
+
+ [Tested]
+ IDirectedEnumerable<T> C5.IDirectedEnumerable<T>.Backwards()
+ { return Backwards(); }
+
+
+ [Tested]
+ public override EnumerationDirection Direction
+ {
+ [Tested]
+ get
+ {
+ return forwards ? EnumerationDirection.Forwards : EnumerationDirection.Backwards;
+ }
+ }
+ }
+ #endregion
+
+ /// <summary>
+ /// Create a collection containing the same items as this collection, but
+ /// whose enumerator will enumerate the items backwards. The new collection
+ /// will become invalid if the original is modified. Method typicaly used as in
+ /// <code>foreach (T x in coll.Backwards()) {...}</code>
+ /// </summary>
+ /// <returns>The backwards collection.</returns>
+ [Tested]
+ public override IDirectedCollectionValue<T> Backwards() { return RangeAll().Backwards(); }
+
+
+ [Tested]
+ IDirectedEnumerable<T> IDirectedEnumerable<T>.Backwards() { return Backwards(); }
+
+ #endregion
+
+ #region PriorityQueue Members
+
+ /// <summary>
+ /// The comparer object supplied at creation time for this collection
+ /// </summary>
+ /// <value>The comparer</value>
+ public SCG.IComparer<T> Comparer { get { return comparer; } }
+
+
+ /// <summary>
+ /// Find the current least item of this priority queue.
+ /// </summary>
+ /// <returns>The least item.</returns>
+ [Tested]
+ public T FindMin()
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ if (size == 0)
+ throw new NoSuchItemException();
+ Node cursor = root, next = left(cursor);
+
+ while (next != null)
+ {
+ cursor = next;
+ next = left(cursor);
+ }
+
+ return cursor.item;
+ }
+
+
+ /// <summary>
+ /// Remove the least item from this priority queue.
+ /// </summary>
+ /// <returns>The removed item.</returns>
+ [Tested]
+ public T DeleteMin()
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ updatecheck();
+
+ //persistence guard?
+ if (size == 0)
+ throw new NoSuchItemException();
+
+ //We must follow the pattern of removeIterative()
+ stackcheck();
+
+ T retval = deleteMin();
+ if (ActiveEvents != 0)
+ {
+ raiseItemsRemoved(retval, 1);
+ raiseCollectionChanged();
+ }
+ return retval;
+ }
+
+ private T deleteMin()
+ {
+ int level = 0;
+ Node cursor = root;
+
+ while (cursor.left != null)
+ {
+ dirs[level] = 1;
+ path[level++] = cursor;
+ cursor = cursor.left;
+ }
+
+ T retval = cursor.item;
+
+#if BAG
+ if (cursor.items > 1)
+ {
+ resplicebag(level, cursor);
+ size--;
+ return retval;
+ }
+#endif
+ removeIterativePhase2(cursor, level);
+ return retval;
+ }
+
+
+ /// <summary>
+ /// Find the current largest item of this priority queue.
+ /// </summary>
+ /// <returns>The largest item.</returns>
+ [Tested]
+ public T FindMax()
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ if (size == 0)
+ throw new NoSuchItemException();
+
+ Node cursor = root, next = right(cursor);
+
+ while (next != null)
+ {
+ cursor = next;
+ next = right(cursor);
+ }
+
+ return cursor.item;
+ }
+
+
+ /// <summary>
+ /// Remove the largest item from this priority queue.
+ /// </summary>
+ /// <returns>The removed item.</returns>
+ [Tested]
+ public T DeleteMax()
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ //persistence guard?
+ updatecheck();
+ if (size == 0)
+ throw new NoSuchItemException();
+
+ //We must follow the pattern of removeIterative()
+ stackcheck();
+
+ T retval = deleteMax();
+ if (ActiveEvents != 0)
+ {
+ raiseItemsRemoved(retval, 1);
+ raiseCollectionChanged();
+ }
+ return retval;
+ }
+
+ private T deleteMax()
+ {
+ int level = 0;
+ Node cursor = root;
+
+ while (cursor.right != null)
+ {
+ dirs[level] = -1;
+ path[level++] = cursor;
+ cursor = cursor.right;
+ }
+
+ T retval = cursor.item;
+
+#if BAG
+ if (cursor.items > 1)
+ {
+ resplicebag(level, cursor);
+ size--;
+ return retval;
+ }
+#endif
+ removeIterativePhase2(cursor, level);
+ return retval;
+ }
+ #endregion
+
+ #region IPredecesorStructure<T> Members
+
+ /// <summary>
+ /// Find the strict predecessor in the sorted collection of a particular value,
+ /// i.e. the largest item in the collection less than the supplied value.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if no such element exists (the
+ /// supplied value is less than or equal to the minimum of this collection.)</exception>
+ /// <param name="item">The item to find the predecessor for.</param>
+ /// <returns>The predecessor.</returns>
+ [Tested]
+ public T Predecessor(T item)
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ Node cursor = root, bestsofar = null;
+
+ while (cursor != null)
+ {
+ int comp = comparer.Compare(cursor.item, item);
+
+ if (comp < 0)
+ {
+ bestsofar = cursor;
+ cursor = right(cursor);
+ }
+ else if (comp == 0)
+ {
+ cursor = left(cursor);
+ while (cursor != null)
+ {
+ bestsofar = cursor;
+ cursor = right(cursor);
+ }
+ }
+ else
+ cursor = left(cursor);
+ }
+
+ if (bestsofar != null)
+ return bestsofar.item;
+ else
+ throw new NoSuchItemException();
+ }
+
+
+ /// <summary>
+ /// Find the weak predecessor in the sorted collection of a particular value,
+ /// i.e. the largest item in the collection less than or equal to the supplied value.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if no such element exists (the
+ /// supplied value is less than the minimum of this collection.)</exception>
+ /// <param name="item">The item to find the weak predecessor for.</param>
+ /// <returns>The weak predecessor.</returns>
+ [Tested]
+ public T WeakPredecessor(T item)
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ Node cursor = root, bestsofar = null;
+
+ while (cursor != null)
+ {
+ int comp = comparer.Compare(cursor.item, item);
+
+ if (comp < 0)
+ {
+ bestsofar = cursor;
+ cursor = right(cursor);
+ }
+ else if (comp == 0)
+ return cursor.item;
+ else
+ cursor = left(cursor);
+ }
+
+ if (bestsofar != null)
+ return bestsofar.item;
+ else
+ throw new NoSuchItemException();
+ }
+
+
+ /// <summary>
+ /// Find the strict successor in the sorted collection of a particular value,
+ /// i.e. the least item in the collection greater than the supplied value.
+ /// </summary>
+ /// <exception cref="NoSuchItemException"> if no such element exists (the
+ /// supplied value is greater than or equal to the maximum of this collection.)</exception>
+ /// <param name="item">The item to find the successor for.</param>
+ /// <returns>The successor.</returns>
+ [Tested]
+ public T Successor(T item)
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ Node cursor = root, bestsofar = null;
+
+ while (cursor != null)
+ {
+ int comp = comparer.Compare(cursor.item, item);
+
+ if (comp > 0)
+ {
+ bestsofar = cursor;
+ cursor = left(cursor);
+ }
+ else if (comp == 0)
+ {
+ cursor = right(cursor);
+ while (cursor != null)
+ {
+ bestsofar = cursor;
+ cursor = left(cursor);
+ }
+ }
+ else
+ cursor = right(cursor);
+ }
+
+ if (bestsofar != null)
+ return bestsofar.item;
+ else
+ throw new NoSuchItemException();
+ }
+
+
+ /// <summary>
+ /// Find the weak successor in the sorted collection of a particular value,
+ /// i.e. the least item in the collection greater than or equal to the supplied value.
+ /// <exception cref="NoSuchItemException"> if no such element exists (the
+ /// supplied value is greater than the maximum of this collection.)</exception>
+ /// </summary>
+ /// <param name="item">The item to find the weak successor for.</param>
+ /// <returns>The weak successor.</returns>
+ [Tested]
+ public T WeakSuccessor(T item)
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ Node cursor = root, bestsofar = null;
+
+ while (cursor != null)
+ {
+ int comp = comparer.Compare(cursor.item, item);
+
+ if (comp == 0)
+ return cursor.item;
+ else if (comp > 0)
+ {
+ bestsofar = cursor;
+ cursor = left(cursor);
+ }
+ else
+ cursor = right(cursor);
+ }
+
+ if (bestsofar != null)
+ return bestsofar.item;
+ else
+ throw new NoSuchItemException();
+ }
+
+ #endregion
+
+ #region ISorted<T> Members
+
+ /// <summary>
+ /// Query this sorted collection for items greater than or equal to a supplied value.
+ /// </summary>
+ /// <param name="bot">The lower bound (inclusive).</param>
+ /// <returns>The result directed collection.</returns>
+ [Tested]
+ public IDirectedCollectionValue<T> RangeFrom(T bot)
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ return new Range(this, true, bot, false, default(T), EnumerationDirection.Forwards);
+ }
+
+
+ /// <summary>
+ /// Query this sorted collection for items between two supplied values.
+ /// </summary>
+ /// <param name="bot">The lower bound (inclusive).</param>
+ /// <param name="top">The upper bound (exclusive).</param>
+ /// <returns>The result directed collection.</returns>
+ [Tested]
+ public IDirectedCollectionValue<T> RangeFromTo(T bot, T top)
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ return new Range(this, true, bot, true, top, EnumerationDirection.Forwards);
+ }
+
+
+ /// <summary>
+ /// Query this sorted collection for items less than a supplied value.
+ /// </summary>
+ /// <param name="top">The upper bound (exclusive).</param>
+ /// <returns>The result directed collection.</returns>
+ [Tested]
+ public IDirectedCollectionValue<T> RangeTo(T top)
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ return new Range(this, false, default(T), true, top, EnumerationDirection.Forwards);
+ }
+
+
+ /// <summary>
+ /// Create a directed collection with the same items as this collection.
+ /// </summary>
+ /// <returns>The result directed collection.</returns>
+ [Tested]
+ public IDirectedCollectionValue<T> RangeAll()
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ return new Range(this, false, default(T), false, default(T), EnumerationDirection.Forwards);
+ }
+
+
+ [Tested]
+ IDirectedEnumerable<T> ISorted<T>.RangeFrom(T bot) { return RangeFrom(bot); }
+
+
+ [Tested]
+ IDirectedEnumerable<T> ISorted<T>.RangeFromTo(T bot, T top) { return RangeFromTo(bot, top); }
+
+
+ [Tested]
+ IDirectedEnumerable<T> ISorted<T>.RangeTo(T top) { return RangeTo(top); }
+
+
+ //Utility for CountXxxx. Actually always called with strict = true.
+ private int countTo(T item, bool strict)
+ {
+#if NCP
+ if (isSnapShot)
+ throw new NotSupportedException("Indexing not supported for snapshots");
+#endif
+#if MAINTAIN_SIZE
+ int ind = 0, comp = 0; Node next = root;
+
+ while (next != null)
+ {
+ comp = comparer.Compare(item, next.item);
+ if (comp < 0)
+ next = next.left;
+ else
+ {
+ int leftcnt = next.left == null ? 0 : next.left.size;
+#if BAG
+ if (comp == 0)
+ return strict ? ind + leftcnt : ind + leftcnt + next.items;
+ else
+ {
+ ind = ind + next.items + leftcnt;
+ next = next.right;
+ }
+#else
+ if (comp == 0)
+ return strict ? ind + leftcnt : ind + leftcnt + 1;
+ else
+ {
+ ind = ind + 1 + leftcnt;
+ next = next.right;
+ }
+#endif
+ }
+ }
+
+ //if we get here, we are at the same side of the whole collection:
+ return ind;
+#else
+ throw new NotSupportedException("Code compiled w/o size!");
+#endif
+ }
+
+
+ /// <summary>
+ /// Perform a search in the sorted collection for the ranges in which a
+ /// non-increasing (i.e. weakly decrerasing) function from the item type to
+ /// <code>int</code> is
+ /// negative, zero respectively positive. If the supplied cut function is
+ /// not non-increasing, the result of this call is undefined.
+ /// </summary>
+ /// <param name="c">The cut function <code>T</code> to <code>int</code>, given
+ /// as an <code>IComparable&lt;T&gt;</code> object, where the cut function is
+ /// the <code>c.CompareTo(T that)</code> method.</param>
+ /// <param name="low">Returns the largest item in the collection, where the
+ /// cut function is positive (if any).</param>
+ /// <param name="lowIsValid">True if the cut function is positive somewhere
+ /// on this collection.</param>
+ /// <param name="high">Returns the least item in the collection, where the
+ /// cut function is negative (if any).</param>
+ /// <param name="highIsValid">True if the cut function is negative somewhere
+ /// on this collection.</param>
+ /// <returns></returns>
+ [Tested]
+ public bool Cut(IComparable<T> c, out T low, out bool lowIsValid, out T high, out bool highIsValid)
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ Node cursor = root, lbest = null, rbest = null;
+ bool res = false;
+
+ while (cursor != null)
+ {
+ int comp = c.CompareTo(cursor.item);
+
+ if (comp > 0)
+ {
+ lbest = cursor;
+ cursor = right(cursor);
+ }
+ else if (comp < 0)
+ {
+ rbest = cursor;
+ cursor = left(cursor);
+ }
+ else
+ {
+ res = true;
+
+ Node tmp = left(cursor);
+
+ while (tmp != null && c.CompareTo(tmp.item) == 0)
+ tmp = left(tmp);
+
+ if (tmp != null)
+ {
+ lbest = tmp;
+ tmp = right(tmp);
+ while (tmp != null)
+ {
+ if (c.CompareTo(tmp.item) > 0)
+ {
+ lbest = tmp;
+ tmp = right(tmp);
+ }
+ else
+ tmp = left(tmp);
+ }
+ }
+
+ tmp = right(cursor);
+ while (tmp != null && c.CompareTo(tmp.item) == 0)
+ tmp = right(tmp);
+
+ if (tmp != null)
+ {
+ rbest = tmp;
+ tmp = left(tmp);
+ while (tmp != null)
+ {
+ if (c.CompareTo(tmp.item) < 0)
+ {
+ rbest = tmp;
+ tmp = left(tmp);
+ }
+ else
+ tmp = right(tmp);
+ }
+ }
+
+ break;
+ }
+ }
+
+ if (highIsValid = (rbest != null))
+ high = rbest.item;
+ else
+ high = default(T);
+
+ if (lowIsValid = (lbest != null))
+ low = lbest.item;
+ else
+ low = default(T);
+
+ return res;
+ }
+
+
+ /// <summary>
+ /// Determine the number of items at or above a supplied threshold.
+ /// </summary>
+ /// <param name="bot">The lower bound (inclusive)</param>
+ /// <returns>The number of matcing items.</returns>
+ [Tested]
+ public int CountFrom(T bot)
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ return size - countTo(bot, true);
+ }
+
+
+ /// <summary>
+ /// Determine the number of items between two supplied thresholds.
+ /// </summary>
+ /// <param name="bot">The lower bound (inclusive)</param>
+ /// <param name="top">The upper bound (exclusive)</param>
+ /// <returns>The number of matcing items.</returns>
+ [Tested]
+ public int CountFromTo(T bot, T top)
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ if (comparer.Compare(bot, top) >= 0)
+ return 0;
+
+ return countTo(top, true) - countTo(bot, true);
+ }
+
+
+ /// <summary>
+ /// Determine the number of items below a supplied threshold.
+ /// </summary>
+ /// <param name="top">The upper bound (exclusive)</param>
+ /// <returns>The number of matcing items.</returns>
+ [Tested]
+ public int CountTo(T top)
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ return countTo(top, true);
+ }
+
+
+ /// <summary>
+ /// Remove all items of this collection above or at a supplied threshold.
+ /// </summary>
+ /// <param name="low">The lower threshold (inclusive).</param>
+ [Tested]
+ public void RemoveRangeFrom(T low)
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ updatecheck();
+
+ int count = CountFrom(low);
+
+ if (count == 0)
+ return;
+
+ stackcheck();
+ CircularQueue<T> wasRemoved = (ActiveEvents & EventTypeEnum.Removed) != 0 ? new CircularQueue<T>() : null;
+
+ for (int i = 0; i < count; i++)
+ {
+ T item = deleteMax();
+ if (wasRemoved != null)
+ wasRemoved.Enqueue(item);
+ }
+ if (wasRemoved != null)
+ raiseForRemoveAll(wasRemoved);
+ else if ((ActiveEvents & EventTypeEnum.Changed) != 0)
+ raiseCollectionChanged();
+ }
+
+
+ /// <summary>
+ /// Remove all items of this collection between two supplied thresholds.
+ /// </summary>
+ /// <param name="low">The lower threshold (inclusive).</param>
+ /// <param name="hi">The upper threshold (exclusive).</param>
+ [Tested]
+ public void RemoveRangeFromTo(T low, T hi)
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ updatecheck();
+
+ int count = CountFromTo(low, hi);
+
+ if (count == 0)
+ return;
+
+ CircularQueue<T> wasRemoved = (ActiveEvents & EventTypeEnum.Removed) != 0 ? new CircularQueue<T>() : null;
+ int junk;
+ for (int i = 0; i < count; i++)
+ {
+ T item = Predecessor(hi);
+ removeIterative(ref item, false, out junk);
+ if (wasRemoved != null)
+ wasRemoved.Enqueue(item);
+ }
+ if (wasRemoved != null)
+ raiseForRemoveAll(wasRemoved);
+ else if ((ActiveEvents & EventTypeEnum.Changed) != 0)
+ raiseCollectionChanged();
+ }
+
+
+ /// <summary>
+ /// Remove all items of this collection below a supplied threshold.
+ /// </summary>
+ /// <param name="hi">The upper threshold (exclusive).</param>
+ [Tested]
+ public void RemoveRangeTo(T hi)
+ {
+ if (!isValid)
+ throw new ViewDisposedException("Snapshot has been disposed");
+ updatecheck();
+
+ int count = CountTo(hi);
+
+ if (count == 0)
+ return;
+
+ stackcheck();
+ CircularQueue<T> wasRemoved = (ActiveEvents & EventTypeEnum.Removed) != 0 ? new CircularQueue<T>() : null;
+
+ for (int i = 0; i < count; i++)
+ {
+ T item = deleteMin();
+ if (wasRemoved != null)
+ wasRemoved.Enqueue(item);
+ }
+ if (wasRemoved != null)
+ raiseForRemoveAll(wasRemoved);
+ else if ((ActiveEvents & EventTypeEnum.Changed) != 0)
+ raiseCollectionChanged();
+ }
+
+ #endregion
+
+ #region IPersistent<T> Members
+#if NCP
+ int maxsnapid { get { return snapList == null ? -1 : findLastLiveSnapShot(); } }
+
+ int findLastLiveSnapShot()
+ {
+ if (snapList == null)
+ return -1;
+ SnapRef lastLiveSnapRef = snapList.Prev;
+ object _snapshot = null;
+ while (lastLiveSnapRef != null && (_snapshot = lastLiveSnapRef.Tree.Target) == null)
+ lastLiveSnapRef = lastLiveSnapRef.Prev;
+ if (lastLiveSnapRef == null)
+ {
+ snapList = null;
+ return -1;
+ }
+ if (snapList.Prev != lastLiveSnapRef)
+ {
+ snapList.Prev = lastLiveSnapRef;
+ lastLiveSnapRef.Next = snapList;
+ }
+ return ((TreeSet<T>)_snapshot).generation;
+ }
+
+ [Serializable]
+ class SnapRef
+ {
+ public SnapRef Prev, Next;
+ public WeakReference Tree;
+ public SnapRef(TreeSet<T> tree) { Tree = new WeakReference(tree); }
+ public void Dispose()
+ {
+ Next.Prev = Prev;
+ if (Prev != null)
+ Prev.Next = Next;
+ Next = Prev = null;
+ }
+ }
+#endif
+
+ /// <summary>
+ /// If this tree is a snapshot, remove registration in base tree
+ /// </summary>
+ [Tested]
+ public void Dispose()
+ {
+#if NCP
+ if (!isValid)
+ return;
+ if (isSnapShot)
+ {
+ snapList.Dispose();
+ snapDispose();
+ }
+ else
+ {
+ if (snapList != null)
+ {
+ SnapRef someSnapRef = snapList.Prev;
+ while (someSnapRef != null)
+ {
+ TreeSet<T> lastsnap;
+ if ((lastsnap = someSnapRef.Tree.Target as TreeSet<T>) != null)
+ lastsnap.snapDispose();
+ someSnapRef = someSnapRef.Prev;
+ }
+ }
+ snapList = null;
+ Clear();
+ }
+#else
+ Clear();
+#endif
+ }
+
+ private void snapDispose()
+ {
+ root = null;
+ dirs = null;
+ path = null;
+ comparer = null;
+ isValid = false;
+ snapList = null;
+ }
+
+ /// <summary>
+ /// Make a (read-only) snapshot of this collection.
+ /// </summary>
+ /// <returns>The snapshot.</returns>
+ [Tested]
+ public ISorted<T> Snapshot()
+ {
+#if NCP
+ if (isSnapShot)
+ throw new InvalidOperationException("Cannot snapshot a snapshot");
+
+ TreeSet<T> res = (TreeSet<T>)MemberwiseClone();
+ SnapRef newSnapRef = new SnapRef(res);
+ res.isReadOnly = true;
+ res.isSnapShot = true;
+ res.snapList = newSnapRef;
+
+ findLastLiveSnapShot();
+ if (snapList == null)
+ snapList = new SnapRef(this);
+ SnapRef lastLiveSnapRef = snapList.Prev;
+
+ newSnapRef.Prev = lastLiveSnapRef;
+ if (lastLiveSnapRef != null)
+ lastLiveSnapRef.Next = newSnapRef;
+ newSnapRef.Next = snapList;
+ snapList.Prev = newSnapRef;
+
+ generation++;
+
+ return res;
+#endif
+ }
+
+ #endregion
+
+ #region TreeSet.Range nested class
+
+ internal class Range : DirectedCollectionValueBase<T>, IDirectedCollectionValue<T>
+ {
+ //We actually need exclusive upper and lower bounds, and flags to
+ //indicate whether the bound is present (we canot rely on default(T))
+ private int stamp, size;
+
+ private TreeSet<T> basis;
+
+ private T lowend, highend;
+
+ private bool haslowend, hashighend;
+
+ EnumerationDirection direction;
+
+
+ [Tested]
+ public Range(TreeSet<T> basis, bool haslowend, T lowend, bool hashighend, T highend, EnumerationDirection direction)
+ {
+ this.basis = basis;
+ stamp = basis.stamp;
+
+ //lowind will be const; should we cache highind?
+ this.lowend = lowend; //Inclusive
+ this.highend = highend;//Exclusive
+ this.haslowend = haslowend;
+ this.hashighend = hashighend;
+ this.direction = direction;
+ if (!basis.isSnapShot)
+ size = haslowend ?
+ (hashighend ? basis.CountFromTo(lowend, highend) : basis.CountFrom(lowend)) :
+ (hashighend ? basis.CountTo(highend) : basis.Count);
+ }
+
+ #region IEnumerable<T> Members
+
+
+ #region TreeSet.Range.Enumerator nested class
+
+ internal class Enumerator : SCG.IEnumerator<T>
+ {
+ #region Private Fields
+ private bool valid = false, ready = true;
+
+ private SCG.IComparer<T> comparer;
+
+ private T current;
+#if BAG
+ int togo;
+#endif
+
+ private Node cursor;
+
+ private Node[] path; // stack of nodes
+
+ private int level = 0;
+
+ private Range range;
+
+ private bool forwards;
+
+ #endregion
+ [Tested]
+ public Enumerator(Range range)
+ {
+ comparer = range.basis.comparer;
+ path = new Node[2 * range.basis.blackdepth];
+ this.range = range;
+ forwards = range.direction == EnumerationDirection.Forwards;
+ cursor = new Node();
+ if (forwards)
+ cursor.right = range.basis.root;
+ else
+ cursor.left = range.basis.root;
+ range.basis.modifycheck(range.stamp);
+ }
+
+
+ int compare(T i1, T i2) { return comparer.Compare(i1, i2); }
+
+
+ /// <summary>
+ /// Undefined if enumerator is not valid (MoveNext hash been called returning true)
+ /// </summary>
+ /// <value>The current value of the enumerator.</value>
+ [Tested]
+ public T Current
+ {
+ [Tested]
+ get
+ {
+ if (valid)
+ return current;
+ else
+ throw new InvalidOperationException();
+ }
+ }
+
+
+ //Maintain a stack of nodes that are roots of
+ //subtrees not completely exported yet. Invariant:
+ //The stack nodes together with their right subtrees
+ //consists of exactly the items we have not passed
+ //yet (the top of the stack holds current item).
+ /// <summary>
+ /// Move enumerator to next item in tree, or the first item if
+ /// this is the first call to MoveNext.
+ /// <exception cref="CollectionModifiedException"/> if underlying tree was modified.
+ /// </summary>
+ /// <returns>True if enumerator is valid now</returns>
+ [Tested]
+ public bool MoveNext()
+ {
+ range.basis.modifycheck(range.stamp);
+ if (!ready)
+ return false;
+#if BAG
+ if (--togo > 0)
+ return true;
+#endif
+ if (forwards)
+ {
+ if (!valid && range.haslowend)
+ {
+ cursor = cursor.right;
+ while (cursor != null)
+ {
+ int comp = compare(cursor.item, range.lowend);
+
+ if (comp > 0)
+ {
+ path[level++] = cursor;
+#if NCP
+ cursor = range.basis.left(cursor);
+#else
+ cursor = cursor.left;
+#endif
+ }
+ else if (comp < 0)
+ {
+#if NCP
+ cursor = range.basis.right(cursor);
+#else
+ cursor = cursor.right;
+#endif
+ }
+ else
+ {
+ path[level] = cursor;
+ break;
+ }
+ }
+
+ if (cursor == null)
+ {
+ if (level == 0)
+ return valid = ready = false;
+ else
+ cursor = path[--level];
+ }
+ }
+#if NCP
+ else if (range.basis.right(cursor) != null)
+ {
+ path[level] = cursor = range.basis.right(cursor);
+
+ Node next = range.basis.left(cursor);
+
+ while (next != null)
+ {
+ path[++level] = cursor = next;
+ next = range.basis.left(cursor);
+ }
+ }
+#else
+ else if (cursor.right != null)
+ {
+ path[level] = cursor = cursor.right;
+ while (cursor.left != null)
+ path[++level] = cursor = cursor.left;
+ }
+#endif
+ else if (level == 0)
+ return valid = ready = false;
+ else
+ cursor = path[--level];
+
+ current = cursor.item;
+ if (range.hashighend && compare(current, range.highend) >= 0)
+ return valid = ready = false;
+
+#if BAG
+ togo = cursor.items;
+#endif
+ return valid = true;
+ }
+ else
+ {
+ if (!valid && range.hashighend)
+ {
+ cursor = cursor.left;
+ while (cursor != null)
+ {
+ int comp = compare(cursor.item, range.highend);
+
+ if (comp < 0)
+ {
+ path[level++] = cursor;
+#if NCP
+ cursor = range.basis.right(cursor);
+#else
+ cursor = cursor.right;
+#endif
+ }
+ else
+ {
+#if NCP
+ cursor = range.basis.left(cursor);
+#else
+ cursor = cursor.left;
+#endif
+ }
+ }
+
+ if (cursor == null)
+ {
+ if (level == 0)
+ return valid = ready = false;
+ else
+ cursor = path[--level];
+ }
+ }
+#if NCP
+ else if (range.basis.left(cursor) != null)
+ {
+ path[level] = cursor = range.basis.left(cursor);
+
+ Node next = range.basis.right(cursor);
+
+ while (next != null)
+ {
+ path[++level] = cursor = next;
+ next = range.basis.right(cursor);
+ }
+ }
+#else
+ else if (cursor.left != null)
+ {
+ path[level] = cursor = cursor.left;
+ while (cursor.right != null)
+ path[++level] = cursor = cursor.right;
+ }
+#endif
+ else if (level == 0)
+ return valid = ready = false;
+ else
+ cursor = path[--level];
+
+ current = cursor.item;
+ if (range.haslowend && compare(current, range.lowend) < 0)
+ return valid = ready = false;
+
+#if BAG
+ togo = cursor.items;
+#endif
+ return valid = true;
+ }
+ }
+
+
+ [Tested]
+ public void Dispose()
+ {
+ comparer = null;
+ current = default(T);
+ cursor = null;
+ path = null;
+ range = null;
+ }
+
+ #region IEnumerator Members
+
+ object System.Collections.IEnumerator.Current
+ {
+ get { return Current; }
+ }
+
+ bool System.Collections.IEnumerator.MoveNext()
+ {
+ return MoveNext();
+ }
+
+ void System.Collections.IEnumerator.Reset()
+ {
+ throw new Exception("The method or operation is not implemented.");
+ }
+
+ #endregion
+ }
+
+ #endregion
+
+
+ public override T Choose()
+ {
+ if (size == 0) throw new NoSuchItemException();
+ return lowend;
+ }
+
+ [Tested]
+ public override SCG.IEnumerator<T> GetEnumerator() { return new Enumerator(this); }
+
+
+ [Tested]
+ public override EnumerationDirection Direction { [Tested]get { return direction; } }
+
+
+ #endregion
+
+ #region Utility
+
+ bool inside(T item)
+ {
+ return (!haslowend || basis.comparer.Compare(item, lowend) >= 0) && (!hashighend || basis.comparer.Compare(item, highend) < 0);
+ }
+
+
+ void checkstamp()
+ {
+ if (stamp < basis.stamp)
+ throw new CollectionModifiedException();
+ }
+
+
+ void syncstamp() { stamp = basis.stamp; }
+
+ #endregion
+
+ [Tested]
+ public override IDirectedCollectionValue<T> Backwards()
+ {
+ Range b = (Range)MemberwiseClone();
+
+ b.direction = direction == EnumerationDirection.Forwards ? EnumerationDirection.Backwards : EnumerationDirection.Forwards;
+ return b;
+ }
+
+
+ [Tested]
+ IDirectedEnumerable<T> IDirectedEnumerable<T>.Backwards() { return Backwards(); }
+
+
+ public override bool IsEmpty { get { return size == 0; } }
+
+ [Tested]
+ public override int Count { [Tested] get { return size; } }
+
+ //TODO: check that this is correct
+ public override Speed CountSpeed { get { return Speed.Constant; } }
+
+ }
+
+ #endregion
+
+ #region Diagnostics
+ /// <summary>
+ /// Display this node on the console, and recursively its subnodes.
+ /// </summary>
+ /// <param name="n">Node to display</param>
+ /// <param name="space">Indentation</param>
+ private void minidump(Node n, string space)
+ {
+ if (n == null)
+ {
+ // System.Console.WriteLine(space + "null");
+ }
+ else
+ {
+ minidump(n.right, space + " ");
+ Console.WriteLine(String.Format("{0} {4} (size={1}, items={8}, h={2}, gen={3}, id={6}){7}", space + n.item,
+#if MAINTAIN_SIZE
+ n.size,
+#else
+ 0,
+#endif
+ 0,
+#if NCP
+ n.generation,
+#endif
+ n.red ? "RED" : "BLACK",
+ 0,
+ 0,
+#if NCP
+#if SEPARATE_EXTRA
+ n.extra == null ? "" : String.Format(" [extra: lg={0}, c={1}, i={2}]", n.extra.lastgeneration, n.extra.leftnode ? "L" : "R", n.extra.oldref == null ? "()" : "" + n.extra.oldref.item),
+#else
+ n.lastgeneration == -1 ? "" : String.Format(" [extra: lg={0}, c={1}, i={2}]", n.lastgeneration, n.leftnode ? "L" : "R", n.oldref == null ? "()" : "" + n.oldref.item),
+#endif
+#else
+ "",
+#endif
+#if BAG
+ n.items
+#else
+ 1
+#endif
+));
+ minidump(n.left, space + " ");
+ }
+ }
+
+
+ /// <summary>
+ /// Print the tree structure to the console stdout.
+ /// </summary>
+ [Tested(via = "Sawtooth")]
+ public void dump() { dump(""); }
+
+
+ /// <summary>
+ /// Print the tree structure to the console stdout.
+ /// </summary>
+ [Tested(via = "Sawtooth")]
+ public void dump(string msg)
+ {
+ Console.WriteLine(String.Format(">>>>>>>>>>>>>>>>>>> dump {0} (count={1}, blackdepth={2}, depth={3}, gen={4})", msg, size, blackdepth,
+ 0
+ ,
+#if NCP
+ generation
+#endif
+));
+ minidump(root, "");
+ check("", Console.Out); Console.WriteLine("<<<<<<<<<<<<<<<<<<<");
+ }
+
+
+ /// <summary>
+ /// Display this tree on the console.
+ /// </summary>
+ /// <param name="msg">Identifying string of this call to dump</param>
+ /// <param name="err">Extra (error)message to include</param>
+ void dump(string msg, string err)
+ {
+ Console.WriteLine(String.Format(">>>>>>>>>>>>>>>>>>> dump {0} (count={1}, blackdepth={2}, depth={3}, gen={4})", msg, size, blackdepth,
+ 0
+ ,
+#if NCP
+ generation
+#endif
+));
+ minidump(root, ""); Console.Write(err);
+ Console.WriteLine("<<<<<<<<<<<<<<<<<<<");
+ }
+
+
+ /// <summary>
+ /// Print warning m on o if b is false.
+ /// </summary>
+ /// <param name="b">Condition that should hold</param>
+ /// <param name="n">Place (used for id display)</param>
+ /// <param name="m">Message</param>
+ /// <param name="o">Output stream</param>
+ /// <returns>b</returns>
+ bool massert(bool b, Node n, string m, System.IO.TextWriter o)
+ {
+ if (!b) o.WriteLine("*** Node (item={0}, id={1}): {2}", n.item,
+ 0
+ , m);
+
+ return b;
+ }
+
+
+ bool rbminicheck(Node n, bool redp, System.IO.TextWriter o, out T min, out T max, out int blackheight, int maxgen)
+ {//Red-Black invariant
+ bool res = true;
+
+ res = massert(!(n.red && redp), n, "RED parent of RED node", o) && res;
+ res = massert(n.left == null || n.right != null || n.left.red, n, "Left child black, but right child empty", o) && res;
+ res = massert(n.right == null || n.left != null || n.right.red, n, "Right child black, but left child empty", o) && res;
+#if BAG
+ bool sb = n.size == (n.left == null ? 0 : n.left.size) + (n.right == null ? 0 : n.right.size) + n.items;
+
+ res = massert(sb, n, "Bad size", o) && res;
+#elif MAINTAIN_SIZE
+ bool sb = n.size == (n.left == null ? 0 : n.left.size) + (n.right == null ? 0 : n.right.size) + 1;
+
+ res = massert(sb, n, "Bad size", o) && res;
+#endif
+ min = max = n.item;
+
+ T otherext;
+ int lbh = 0, rbh = 0;
+
+ if (n.left != null)
+ {
+ res = rbminicheck(n.left, n.red, o, out min, out otherext, out lbh, generation) && res;
+ res = massert(comparer.Compare(n.item, otherext) > 0, n, "Value not > all left children", o) && res;
+ }
+
+ if (n.right != null)
+ {
+ res = rbminicheck(n.right, n.red, o, out otherext, out max, out rbh, generation) && res;
+ res = massert(comparer.Compare(n.item, otherext) < 0, n, "Value not < all right children", o) && res;
+ }
+
+ res = massert(rbh == lbh, n, "Different blackheights of children", o) && res;
+ blackheight = n.red ? rbh : rbh + 1;
+ return res;
+ }
+
+
+
+
+#if NCP
+
+ bool rbminisnapcheck(Node n, System.IO.TextWriter o, out int size, out T min, out T max)
+ {
+ bool res = true;
+
+ min = max = n.item;
+
+ int lsz = 0, rsz = 0;
+ T otherext;
+#if SEPARATE_EXTRA
+ Node.Extra extra = n.extra;
+ Node child = (extra != null && extra.lastgeneration >= treegen && extra.leftnode) ? extra.oldref : n.left;
+#else
+ Node child = (n.lastgeneration >= generation && n.leftnode) ? n.oldref : n.left;
+#endif
+ if (child != null)
+ {
+ res = rbminisnapcheck(child, o, out lsz, out min, out otherext) && res;
+ res = massert(comparer.Compare(n.item, otherext) > 0, n, "Value not > all left children", o) && res;
+ }
+
+#if SEPARATE_EXTRA
+ child = (extra != null && extra.lastgeneration >= treegen && !extra.leftnode) ? extra.oldref : n.right;
+#else
+ child = (n.lastgeneration >= generation && !n.leftnode) ? n.oldref : n.right;
+#endif
+ if (child != null)
+ {
+ res = rbminisnapcheck(child, o, out rsz, out otherext, out max) && res;
+ res = massert(comparer.Compare(n.item, otherext) < 0, n, "Value not < all right children", o) && res;
+ }
+#if BAG
+ size = n.items + lsz + rsz;
+#else
+ size = 1 + lsz + rsz;
+#endif
+ return res;
+ }
+#endif
+
+ /// <summary>
+ /// Checks red-black invariant. Dumps tree to console if bad
+ /// </summary>
+ /// <param name="name">Title of dump</param>
+ /// <returns>false if invariant violation</returns>
+ [Tested(via = "Sawtooth")]
+ public bool Check(string name)
+ {
+ System.Text.StringBuilder e = new System.Text.StringBuilder();
+ System.IO.TextWriter o = new System.IO.StringWriter(e);
+
+ if (!check(name, o))
+ return true;
+ else
+ {
+ dump(name, e.ToString());
+ return false;
+ }
+ }
+
+
+ /// <summary>
+ /// Checks red-black invariant. Dumps tree to console if bad
+ /// </summary>
+ /// <returns>false if invariant violation</returns>
+ [Tested]
+ public bool Check()
+ {
+ //return check("", System.IO.TextWriter.Null);
+ //Console.WriteLine("bamse");
+ if (!isValid)
+ return true;
+ return Check("-");
+ }
+
+
+ bool check(string msg, System.IO.TextWriter o)
+ {
+ if (root != null)
+ {
+ T max, min;
+ int blackheight;
+#if NCP
+ if (isSnapShot)
+ {
+ //Console.WriteLine("Im'a snapshot");
+ int thesize;
+ bool rv = rbminisnapcheck(root, o, out thesize, out min, out max);
+
+ rv = massert(size == thesize, root, "bad snapshot size", o) && rv;
+ return !rv;
+ }
+#endif
+ bool res = rbminicheck(root, false, o, out min, out max, out blackheight, generation);
+ res = massert(blackheight == blackdepth, root, "bad blackh/d", o) && res;
+ res = massert(!root.red, root, "root is red", o) && res;
+#if MAINTAIN_SIZE
+ res = massert(root.size == size, root, "count!=root.size", o) && res;
+#endif
+ return !res;
+ }
+ else
+ return false;
+ }
+ #endregion
+
+ #region ICloneable Members
+
+ /// <summary>
+ /// Make a shallow copy of this TreeSet.
+ /// </summary>
+ /// <returns></returns>
+ public virtual object Clone()
+ {
+ TreeSet<T> clone = new TreeSet<T>(comparer, EqualityComparer);
+ //TODO: make sure the TreeBag AddSorted copies tree bags smartly!!!
+ clone.AddSorted(this);
+ return clone;
+ }
+
+ #endregion
+
+ }
+}
+