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 16:47:31 +0300
committerMartin Baulig <martin@novell.com>2006-02-16 16:47:31 +0300
commit74d1c624f1851c55c53c599b906a3ce3768f42f3 (patch)
tree346430632812ac3c0379aa10a242070e0ec2deb8 /mcs/class/Mono.C5
parent459dcc48fa18e2001d2bbc408739e2c8104f72da (diff)
Bringing C5 1.0 into the main branch.
svn path=/trunk/mcs/; revision=56928
Diffstat (limited to 'mcs/class/Mono.C5')
-rw-r--r--mcs/class/Mono.C5/1.0/BUILD.txt20
-rw-r--r--mcs/class/Mono.C5/1.0/C5.sln77
-rw-r--r--mcs/class/Mono.C5/1.0/C5/AssemblyInfo.cs79
-rw-r--r--mcs/class/Mono.C5/1.0/C5/Attributes.cs48
-rw-r--r--mcs/class/Mono.C5/1.0/C5/Builtin.cs186
-rw-r--r--mcs/class/Mono.C5/1.0/C5/C5.csproj128
-rw-r--r--mcs/class/Mono.C5/1.0/C5/ClsdiagWork.pngbin0 -> 17212 bytes
-rw-r--r--mcs/class/Mono.C5/1.0/C5/Collections.cs1520
-rw-r--r--mcs/class/Mono.C5/1.0/C5/Comparer.cs152
-rw-r--r--mcs/class/Mono.C5/1.0/C5/Delegates.cs131
-rw-r--r--mcs/class/Mono.C5/1.0/C5/Dictionaries.cs1295
-rw-r--r--mcs/class/Mono.C5/1.0/C5/Enums.cs98
-rw-r--r--mcs/class/Mono.C5/1.0/C5/Events.cs532
-rw-r--r--mcs/class/Mono.C5/1.0/C5/Exceptions.cs244
-rw-r--r--mcs/class/Mono.C5/1.0/C5/Formatting.cs247
-rw-r--r--mcs/class/Mono.C5/1.0/C5/Hashers.cs489
-rw-r--r--mcs/class/Mono.C5/1.0/C5/Interfaces.cs1884
-rw-r--r--mcs/class/Mono.C5/1.0/C5/MappedEnumerators.cs145
-rw-r--r--mcs/class/Mono.C5/1.0/C5/Random.cs172
-rw-r--r--mcs/class/Mono.C5/1.0/C5/Records.cs510
-rw-r--r--mcs/class/Mono.C5/1.0/C5/Sorting.cs239
-rw-r--r--mcs/class/Mono.C5/1.0/C5/ViewSupport.cs101
-rw-r--r--mcs/class/Mono.C5/1.0/C5/WrappedArray.cs871
-rw-r--r--mcs/class/Mono.C5/1.0/C5/Wrappers.cs2233
-rw-r--r--mcs/class/Mono.C5/1.0/C5/arrays/ArrayList.cs2536
-rw-r--r--mcs/class/Mono.C5/1.0/C5/arrays/CircularQueue.cs334
-rw-r--r--mcs/class/Mono.C5/1.0/C5/arrays/SortedArray.cs1266
-rw-r--r--mcs/class/Mono.C5/1.0/C5/hashing/HashBag.cs678
-rw-r--r--mcs/class/Mono.C5/1.0/C5/hashing/HashDictionary.cs77
-rw-r--r--mcs/class/Mono.C5/1.0/C5/hashing/HashTable.cs1600
-rw-r--r--mcs/class/Mono.C5/1.0/C5/heaps/IntervalHeap.cs1100
-rw-r--r--mcs/class/Mono.C5/1.0/C5/linkedlists/LinkedList.cs3782
-rw-r--r--mcs/class/Mono.C5/1.0/C5/trees/.cvsignore1
-rw-r--r--mcs/class/Mono.C5/1.0/C5/trees/RedBlackTreeDictionary.cs80
-rw-r--r--mcs/class/Mono.C5/1.0/C5/trees/RedBlackTreeSet.cs4490
-rw-r--r--mcs/class/Mono.C5/1.0/LICENSE.txt19
-rw-r--r--mcs/class/Mono.C5/1.0/PreProcess/PreProcess.csproj30
-rw-r--r--mcs/class/Mono.C5/1.0/PreProcess/Program.cs72
-rw-r--r--mcs/class/Mono.C5/1.0/Test/AssemblyInfo.cs79
-rw-r--r--mcs/class/Mono.C5/1.0/Test/BasesTest.cs419
-rw-r--r--mcs/class/Mono.C5/1.0/Test/Records.cs119
-rw-r--r--mcs/class/Mono.C5/1.0/Test/Sorting.cs268
-rw-r--r--mcs/class/Mono.C5/1.0/Test/SupportClasses.cs493
-rw-r--r--mcs/class/Mono.C5/1.0/Test/WrappersTest.cs857
-rw-r--r--mcs/class/Mono.C5/1.0/Test/arrays/ArrayListTest.cs3821
-rw-r--r--mcs/class/Mono.C5/1.0/Test/arrays/CircularQueueTest.cs214
-rw-r--r--mcs/class/Mono.C5/1.0/Test/arrays/HashedArrayListTest.cs3405
-rw-r--r--mcs/class/Mono.C5/1.0/Test/arrays/SortedArrayTests.cs2356
-rw-r--r--mcs/class/Mono.C5/1.0/Test/hashing/HashBagTests.cs599
-rw-r--r--mcs/class/Mono.C5/1.0/Test/hashing/HashDictionaryTests.cs324
-rw-r--r--mcs/class/Mono.C5/1.0/Test/hashing/HashTableTests.cs1095
-rw-r--r--mcs/class/Mono.C5/1.0/Test/heaps/HeapTests.cs551
-rw-r--r--mcs/class/Mono.C5/1.0/Test/linkedlists/HashedLinkedListTest.cs2841
-rw-r--r--mcs/class/Mono.C5/1.0/Test/linkedlists/LinkedListTest.cs3411
-rw-r--r--mcs/class/Mono.C5/1.0/Test/nunit.csproj118
-rw-r--r--mcs/class/Mono.C5/1.0/Test/templates/Clone.cs117
-rw-r--r--mcs/class/Mono.C5/1.0/Test/templates/Events.cs928
-rw-r--r--mcs/class/Mono.C5/1.0/Test/templates/GenericCollectionTester.cs87
-rw-r--r--mcs/class/Mono.C5/1.0/Test/templates/List.cs40
-rw-r--r--mcs/class/Mono.C5/1.0/Test/trees/Bag.cs2931
-rw-r--r--mcs/class/Mono.C5/1.0/Test/trees/Dictionary.cs311
-rw-r--r--mcs/class/Mono.C5/1.0/Test/trees/RedBlackTreeSetTests.cs2855
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/AnagramHashBag.cs158
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/AnagramStrings.cs159
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/AnagramTreeBag.cs163
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/Anagrams.cs177
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/Antipatterns.cs103
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/Cloning.cs45
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/CollectionCollection.cs125
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/CollectionSanity.cs65
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/EventPatterns.cs213
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/Fileindex.cs82
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/GCHForm.cs271
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/GCHForm.resx120
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/GConvexHull.cs178
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/GNfaToDfa.cs666
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/GettingStarted.cs50
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/Graph.cs1679
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/HashCodes.cs106
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/Jobqueue.cs147
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/KeywordRecognition.cs177
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/ListPatterns.cs141
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/Locking.cs97
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/Makefile27
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/MultiCollection.cs131
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/MultiDictionary.cs308
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/PointLocation.cs774
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/RandomSelection.cs86
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/ReadOnlyPatterns.cs96
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/Sets.cs175
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/SortedIterationPatterns.cs247
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/SortingPermutation.cs80
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/TestSortedArray.cs37
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/ThisFun.cs46
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/Toposort.cs139
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/TreeTraversal.cs107
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/Try.cs64
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/UserGuideExamples.csproj90
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/ViewPatterns.cs340
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/Views.cs160
-rw-r--r--mcs/class/Mono.C5/1.0/UserGuideExamples/WrappedArray.cs191
-rw-r--r--mcs/class/Mono.C5/1.0/doc/AssemblyInfo.cs79
-rw-r--r--mcs/class/Mono.C5/1.0/doc/Test.cs137
-rw-r--r--mcs/class/Mono.C5/1.0/doc/Timer.cs84
-rw-r--r--mcs/class/Mono.C5/1.0/doc/docNet.csproj83
-rw-r--r--mcs/class/Mono.C5/1.0/doc/docbuild/banner.htm13
-rw-r--r--mcs/class/Mono.C5/1.0/doc/docbuild/docnet.css131
-rw-r--r--mcs/class/Mono.C5/1.0/doc/docbuild/frames.htm12
-rw-r--r--mcs/class/Mono.C5/1.0/doc/docbuild/litterature.htm61
-rw-r--r--mcs/class/Mono.C5/1.0/doc/docbuild/userguide.htm2519
-rw-r--r--mcs/class/Mono.C5/1.0/doc/docnet.cs772
-rw-r--r--mcs/class/Mono.C5/1.0/doc/dodoc.cmd2
-rw-r--r--mcs/class/Mono.C5/1.0/doc/mkcurrent.cmd10
-rw-r--r--mcs/class/Mono.C5/1.0/doc/overview.xslt65
-rw-r--r--mcs/class/Mono.C5/1.0/doc/tolatex.xslt43
-rw-r--r--mcs/class/Mono.C5/1.0/doc/trans.xslt591
116 files changed, 68327 insertions, 0 deletions
diff --git a/mcs/class/Mono.C5/1.0/BUILD.txt b/mcs/class/Mono.C5/1.0/BUILD.txt
new file mode 100644
index 00000000000..85b189c6cbf
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/BUILD.txt
@@ -0,0 +1,20 @@
+The C5 library can be built by opening the solution file C5.sln in the
+current directory with Microsoft Visual Studio 2005 or
+Microsoft Visual C# 2005 Express Edition and performing a build all.
+This will build C5.dll to the fileC5\C5\bin\Debug\C5.dll.
+
+Building all in the C5.sln solution will also build the projects
+* 'PreProcess' which does some preprocessing of the C5 sources and is an
+ integral part of the C5 build process.
+* 'docNet' for generation of on-line documentation
+* 'UserGuideExample' containing the examples from the User's Guide.
+
+The build should complete with a few compilation warnings.
+
+To build the 'nunit' project you need to have NUnit 2.0 installed, else an enormous
+number of compilation errors will result. The project is configured for NUnit
+version 2.2.6 and tested with that version.
+The NUnit tests should pass except for a single one due to missing implementation
+of events on the class SortedArray.
+
+ \ No newline at end of file
diff --git a/mcs/class/Mono.C5/1.0/C5.sln b/mcs/class/Mono.C5/1.0/C5.sln
new file mode 100644
index 00000000000..53c169d1750
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/C5.sln
@@ -0,0 +1,77 @@
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "C5", "C5\C5.csproj", "{D70489CD-ABDA-48FF-BD1E-BE3F7495BE71}"
+ ProjectSection(ProjectDependencies) = postProject
+ {6222CA51-7D1A-4D42-B6A7-B5CE9608C18F} = {6222CA51-7D1A-4D42-B6A7-B5CE9608C18F}
+ EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "nunit", "nunit\nunit.csproj", "{08CBFDEB-A2E2-4F0E-A4E1-B996B05569DE}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "docNet", "docNet\docNet.csproj", "{42811A81-6A99-4C7A-A6DA-DF104C767B72}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UserGuideExamples", "UserGuideExamples\UserGuideExamples.csproj", "{B2A29FF2-A5C5-4F07-8CE7-FF5D744D7562}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PreProcess", "PreProcess\PreProcess.csproj", "{6222CA51-7D1A-4D42-B6A7-B5CE9608C18F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|Mixed platforms = Debug|Mixed platforms
+ Debug|Win32 = Debug|Win32
+ Release|Any CPU = Release|Any CPU
+ Release|Mixed platforms = Release|Mixed platforms
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {D70489CD-ABDA-48FF-BD1E-BE3F7495BE71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D70489CD-ABDA-48FF-BD1E-BE3F7495BE71}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D70489CD-ABDA-48FF-BD1E-BE3F7495BE71}.Debug|Mixed platforms.ActiveCfg = Debug|Any CPU
+ {D70489CD-ABDA-48FF-BD1E-BE3F7495BE71}.Debug|Mixed platforms.Build.0 = Debug|Any CPU
+ {D70489CD-ABDA-48FF-BD1E-BE3F7495BE71}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {D70489CD-ABDA-48FF-BD1E-BE3F7495BE71}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D70489CD-ABDA-48FF-BD1E-BE3F7495BE71}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D70489CD-ABDA-48FF-BD1E-BE3F7495BE71}.Release|Mixed platforms.ActiveCfg = Release|Any CPU
+ {D70489CD-ABDA-48FF-BD1E-BE3F7495BE71}.Release|Mixed platforms.Build.0 = Release|Any CPU
+ {D70489CD-ABDA-48FF-BD1E-BE3F7495BE71}.Release|Win32.ActiveCfg = Release|Any CPU
+ {08CBFDEB-A2E2-4F0E-A4E1-B996B05569DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {08CBFDEB-A2E2-4F0E-A4E1-B996B05569DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {08CBFDEB-A2E2-4F0E-A4E1-B996B05569DE}.Debug|Mixed platforms.ActiveCfg = Debug|Any CPU
+ {08CBFDEB-A2E2-4F0E-A4E1-B996B05569DE}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {08CBFDEB-A2E2-4F0E-A4E1-B996B05569DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {08CBFDEB-A2E2-4F0E-A4E1-B996B05569DE}.Release|Mixed platforms.ActiveCfg = Release|Any CPU
+ {08CBFDEB-A2E2-4F0E-A4E1-B996B05569DE}.Release|Mixed platforms.Build.0 = Release|Any CPU
+ {08CBFDEB-A2E2-4F0E-A4E1-B996B05569DE}.Release|Win32.ActiveCfg = Release|Any CPU
+ {42811A81-6A99-4C7A-A6DA-DF104C767B72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {42811A81-6A99-4C7A-A6DA-DF104C767B72}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {42811A81-6A99-4C7A-A6DA-DF104C767B72}.Debug|Mixed platforms.ActiveCfg = Debug|Any CPU
+ {42811A81-6A99-4C7A-A6DA-DF104C767B72}.Debug|Mixed platforms.Build.0 = Debug|Any CPU
+ {42811A81-6A99-4C7A-A6DA-DF104C767B72}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {42811A81-6A99-4C7A-A6DA-DF104C767B72}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {42811A81-6A99-4C7A-A6DA-DF104C767B72}.Release|Mixed platforms.ActiveCfg = Release|Any CPU
+ {42811A81-6A99-4C7A-A6DA-DF104C767B72}.Release|Mixed platforms.Build.0 = Release|Any CPU
+ {42811A81-6A99-4C7A-A6DA-DF104C767B72}.Release|Win32.ActiveCfg = Release|Any CPU
+ {B2A29FF2-A5C5-4F07-8CE7-FF5D744D7562}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B2A29FF2-A5C5-4F07-8CE7-FF5D744D7562}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B2A29FF2-A5C5-4F07-8CE7-FF5D744D7562}.Debug|Mixed platforms.ActiveCfg = Debug|Any CPU
+ {B2A29FF2-A5C5-4F07-8CE7-FF5D744D7562}.Debug|Mixed platforms.Build.0 = Debug|Any CPU
+ {B2A29FF2-A5C5-4F07-8CE7-FF5D744D7562}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {B2A29FF2-A5C5-4F07-8CE7-FF5D744D7562}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B2A29FF2-A5C5-4F07-8CE7-FF5D744D7562}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B2A29FF2-A5C5-4F07-8CE7-FF5D744D7562}.Release|Mixed platforms.ActiveCfg = Release|Any CPU
+ {B2A29FF2-A5C5-4F07-8CE7-FF5D744D7562}.Release|Mixed platforms.Build.0 = Release|Any CPU
+ {B2A29FF2-A5C5-4F07-8CE7-FF5D744D7562}.Release|Win32.ActiveCfg = Release|Any CPU
+ {6222CA51-7D1A-4D42-B6A7-B5CE9608C18F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6222CA51-7D1A-4D42-B6A7-B5CE9608C18F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6222CA51-7D1A-4D42-B6A7-B5CE9608C18F}.Debug|Mixed platforms.ActiveCfg = Debug|Any CPU
+ {6222CA51-7D1A-4D42-B6A7-B5CE9608C18F}.Debug|Mixed platforms.Build.0 = Debug|Any CPU
+ {6222CA51-7D1A-4D42-B6A7-B5CE9608C18F}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {6222CA51-7D1A-4D42-B6A7-B5CE9608C18F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6222CA51-7D1A-4D42-B6A7-B5CE9608C18F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6222CA51-7D1A-4D42-B6A7-B5CE9608C18F}.Release|Mixed platforms.ActiveCfg = Release|Any CPU
+ {6222CA51-7D1A-4D42-B6A7-B5CE9608C18F}.Release|Mixed platforms.Build.0 = Release|Any CPU
+ {6222CA51-7D1A-4D42-B6A7-B5CE9608C18F}.Release|Win32.ActiveCfg = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/mcs/class/Mono.C5/1.0/C5/AssemblyInfo.cs b/mcs/class/Mono.C5/1.0/C5/AssemblyInfo.cs
new file mode 100644
index 00000000000..a649742b511
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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/1.0/C5/Attributes.cs b/mcs/class/Mono.C5/1.0/C5/Attributes.cs
new file mode 100644
index 00000000000..9302996aa0d
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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/1.0/C5/Builtin.cs b/mcs/class/Mono.C5/1.0/C5/Builtin.cs
new file mode 100644
index 00000000000..3b6a4b017f4
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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/1.0/C5/C5.csproj b/mcs/class/Mono.C5/1.0/C5/C5.csproj
new file mode 100644
index 00000000000..eb0c5b0ebdc
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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/1.0/C5/ClsdiagWork.png b/mcs/class/Mono.C5/1.0/C5/ClsdiagWork.png
new file mode 100644
index 00000000000..9a1866653a8
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/C5/ClsdiagWork.png
Binary files differ
diff --git a/mcs/class/Mono.C5/1.0/C5/Collections.cs b/mcs/class/Mono.C5/1.0/C5/Collections.cs
new file mode 100644
index 00000000000..98acf96dd5a
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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/1.0/C5/Comparer.cs b/mcs/class/Mono.C5/1.0/C5/Comparer.cs
new file mode 100644
index 00000000000..784b015e51a
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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/1.0/C5/Delegates.cs b/mcs/class/Mono.C5/1.0/C5/Delegates.cs
new file mode 100644
index 00000000000..36792d8555b
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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/1.0/C5/Dictionaries.cs b/mcs/class/Mono.C5/1.0/C5/Dictionaries.cs
new file mode 100644
index 00000000000..4370461c7ea
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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/1.0/C5/Enums.cs b/mcs/class/Mono.C5/1.0/C5/Enums.cs
new file mode 100644
index 00000000000..a92301d83e2
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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/1.0/C5/Events.cs b/mcs/class/Mono.C5/1.0/C5/Events.cs
new file mode 100644
index 00000000000..4a5d8d7d1b3
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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/1.0/C5/Exceptions.cs b/mcs/class/Mono.C5/1.0/C5/Exceptions.cs
new file mode 100644
index 00000000000..2480b22c6df
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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/1.0/C5/Formatting.cs b/mcs/class/Mono.C5/1.0/C5/Formatting.cs
new file mode 100644
index 00000000000..5d4a1449f42
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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/1.0/C5/Hashers.cs b/mcs/class/Mono.C5/1.0/C5/Hashers.cs
new file mode 100644
index 00000000000..70778c57e0c
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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/1.0/C5/Interfaces.cs b/mcs/class/Mono.C5/1.0/C5/Interfaces.cs
new file mode 100644
index 00000000000..3ae5abe85d4
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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/1.0/C5/MappedEnumerators.cs b/mcs/class/Mono.C5/1.0/C5/MappedEnumerators.cs
new file mode 100644
index 00000000000..580a34d0d1e
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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/1.0/C5/Random.cs b/mcs/class/Mono.C5/1.0/C5/Random.cs
new file mode 100644
index 00000000000..28df260b85f
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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/1.0/C5/Records.cs b/mcs/class/Mono.C5/1.0/C5/Records.cs
new file mode 100644
index 00000000000..47adaa9c070
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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/1.0/C5/Sorting.cs b/mcs/class/Mono.C5/1.0/C5/Sorting.cs
new file mode 100644
index 00000000000..d40003dd232
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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/1.0/C5/ViewSupport.cs b/mcs/class/Mono.C5/1.0/C5/ViewSupport.cs
new file mode 100644
index 00000000000..ca2a6d72d30
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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/1.0/C5/WrappedArray.cs b/mcs/class/Mono.C5/1.0/C5/WrappedArray.cs
new file mode 100644
index 00000000000..b0aac9e111c
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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/1.0/C5/Wrappers.cs b/mcs/class/Mono.C5/1.0/C5/Wrappers.cs
new file mode 100644
index 00000000000..9d594e0b064
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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/1.0/C5/arrays/ArrayList.cs b/mcs/class/Mono.C5/1.0/C5/arrays/ArrayList.cs
new file mode 100644
index 00000000000..4ff7084ebc1
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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/1.0/C5/arrays/CircularQueue.cs b/mcs/class/Mono.C5/1.0/C5/arrays/CircularQueue.cs
new file mode 100644
index 00000000000..05fe2163d4d
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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/1.0/C5/arrays/SortedArray.cs b/mcs/class/Mono.C5/1.0/C5/arrays/SortedArray.cs
new file mode 100644
index 00000000000..b7bc75339c5
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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/1.0/C5/hashing/HashBag.cs b/mcs/class/Mono.C5/1.0/C5/hashing/HashBag.cs
new file mode 100644
index 00000000000..e8ad80a137a
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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/1.0/C5/hashing/HashDictionary.cs b/mcs/class/Mono.C5/1.0/C5/hashing/HashDictionary.cs
new file mode 100644
index 00000000000..84adde2c458
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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/1.0/C5/hashing/HashTable.cs b/mcs/class/Mono.C5/1.0/C5/hashing/HashTable.cs
new file mode 100644
index 00000000000..0db8f66f6af
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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/1.0/C5/heaps/IntervalHeap.cs b/mcs/class/Mono.C5/1.0/C5/heaps/IntervalHeap.cs
new file mode 100644
index 00000000000..bf5f0d91e3f
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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/1.0/C5/linkedlists/LinkedList.cs b/mcs/class/Mono.C5/1.0/C5/linkedlists/LinkedList.cs
new file mode 100644
index 00000000000..322a4c0cb3d
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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/1.0/C5/trees/.cvsignore b/mcs/class/Mono.C5/1.0/C5/trees/.cvsignore
new file mode 100644
index 00000000000..9577892f5d4
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/C5/trees/.cvsignore
@@ -0,0 +1 @@
+RedBlackTreeBag.cs \ No newline at end of file
diff --git a/mcs/class/Mono.C5/1.0/C5/trees/RedBlackTreeDictionary.cs b/mcs/class/Mono.C5/1.0/C5/trees/RedBlackTreeDictionary.cs
new file mode 100644
index 00000000000..4e1bc61f81a
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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/1.0/C5/trees/RedBlackTreeSet.cs b/mcs/class/Mono.C5/1.0/C5/trees/RedBlackTreeSet.cs
new file mode 100644
index 00000000000..ac86cc6eaea
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/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
+
+ }
+}
+
diff --git a/mcs/class/Mono.C5/1.0/LICENSE.txt b/mcs/class/Mono.C5/1.0/LICENSE.txt
new file mode 100644
index 00000000000..50e744c9f8a
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/LICENSE.txt
@@ -0,0 +1,19 @@
+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.
diff --git a/mcs/class/Mono.C5/1.0/PreProcess/PreProcess.csproj b/mcs/class/Mono.C5/1.0/PreProcess/PreProcess.csproj
new file mode 100644
index 00000000000..282f96dbfe8
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/PreProcess/PreProcess.csproj
@@ -0,0 +1,30 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>8.0.40607</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{6222CA51-7D1A-4D42-B6A7-B5CE9608C18F}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <RootNamespace>PreProcess</RootNamespace>
+ <AssemblyName>PreProcess</AssemblyName>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>.\bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugSymbols>false</DebugSymbols>
+ <Optimize>true</Optimize>
+ <OutputPath>.\bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="Program.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSHARP.Targets" />
+</Project> \ No newline at end of file
diff --git a/mcs/class/Mono.C5/1.0/PreProcess/Program.cs b/mcs/class/Mono.C5/1.0/PreProcess/Program.cs
new file mode 100644
index 00000000000..ca3e9f2c0f0
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/PreProcess/Program.cs
@@ -0,0 +1,72 @@
+/*
+ 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.IO;
+
+namespace PreProcess
+{
+ class Program
+ {
+ static void preprocess(string dir, string filein, string fileout, string symbol, string classin, string classout)
+ {
+ fileout = Path.Combine(dir, fileout);
+ string[] contents = File.ReadAllLines(Path.Combine(dir, filein));
+ string symboldef = "#define " + symbol + "not";
+ bool equal = File.Exists(fileout);
+ TextReader oldversion = equal ? new StreamReader(fileout) : null;
+ for (int lineno = 0; lineno < contents.Length; lineno++)
+ {
+ if (contents[lineno].StartsWith(symboldef))
+ contents[lineno] = "#define " + symbol;
+ else
+ contents[lineno] = contents[lineno].Replace(classin, classout);
+ if (equal)
+ equal = contents[lineno] == oldversion.ReadLine();
+ }
+ if (equal && oldversion.ReadLine() == null)
+ {
+ Console.Error.WriteLine("File {0} is up-to-date", fileout);
+ return;
+ }
+ File.WriteAllLines(fileout + "-new", contents);
+ if (oldversion != null)
+ {
+ oldversion.Close();
+ File.Replace(fileout + "-new", fileout, fileout + ".bak");
+ Console.Error.WriteLine("Updated {0}", fileout);
+ }
+ else
+ {
+ File.Move(fileout + "-new", fileout);
+ Console.Error.WriteLine("Created {0}", fileout);
+ }
+ }
+ static void Main(string[] args)
+ {
+ System.Environment.CurrentDirectory = @"..\..\..\C5";
+ preprocess("trees", "RedBlackTreeSet.cs", "RedBlackTreeBag.cs", "BAG", "TreeSet", "TreeBag");
+ preprocess("arrays", "ArrayList.cs", "HashedArrayList.cs", "HASHINDEX", "ArrayList", "HashedArrayList");
+ preprocess("linkedlists", "LinkedList.cs", "HashedLinkedList.cs", "HASHINDEX", "LinkedList", "HashedLinkedList");
+ }
+ }
+}
diff --git a/mcs/class/Mono.C5/1.0/Test/AssemblyInfo.cs b/mcs/class/Mono.C5/1.0/Test/AssemblyInfo.cs
new file mode 100644
index 00000000000..5a12cf79079
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/Test/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("")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("")]
+[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.*")]
+
+//
+// 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("")]
+[assembly: AssemblyKeyName("")]
diff --git a/mcs/class/Mono.C5/1.0/Test/BasesTest.cs b/mcs/class/Mono.C5/1.0/Test/BasesTest.cs
new file mode 100644
index 00000000000..60cfe17b29a
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/Test/BasesTest.cs
@@ -0,0 +1,419 @@
+/*
+ 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 C5;
+using NUnit.Framework;
+using SCG = System.Collections.Generic;
+
+
+namespace C5UnitTests.support
+{
+ namespace bases
+ {
+ [TestFixture]
+ public class ArrayBaseTest
+ {
+ class ABT : ArrayBase<string>
+ {
+ public ABT() : base(8,NaturalEqualityComparer<string>.Default) { }
+
+ public override string Choose() { if (size > 0) return array[0]; throw new NoSuchItemException(); }
+
+ public string this[int i] { get { return array[i]; } set { array[i] = value; } }
+
+
+ public int thesize { get { return size; } set { size = value; } }
+ }
+
+
+ [Test]
+ public void Check()
+ {
+ ABT abt = new ABT();
+
+ abt.thesize = 3;
+ abt[2] = "aaa";
+ // Assert.IsFalse(abt.Check());
+ abt[0] = "##";
+ abt[1] = "##";
+ Assert.IsTrue(abt.Check());
+ }
+ }
+ }
+
+ namespace itemops
+ {
+ [TestFixture]
+ public class Comparers
+ {
+ class dbl : IComparable<dbl>
+ {
+ double d;
+
+ public dbl(double din) { d = din; }
+
+ public int CompareTo(dbl that)
+ {
+ return d < that.d ? -1 : d == that.d ? 0 : 1;
+ }
+ public bool Equals(dbl that) { return d == that.d; }
+ }
+
+ [Test]
+ [ExpectedException(typeof(NotComparableException))]
+ public void NotComparable()
+ {
+ SCG.IComparer<object> foo = Comparer<object>.Default;
+ }
+
+ [Test]
+ public void GenericC()
+ {
+ SCG.IComparer<dbl> h = new NaturalComparer<dbl>();
+ dbl s = new dbl(3.4);
+ dbl t = new dbl(3.4);
+ dbl u = new dbl(7.4);
+
+ Assert.AreEqual(0, h.Compare(s, t));
+ Assert.IsTrue(h.Compare(s, u) < 0);
+ }
+
+
+ [Test]
+ public void OrdinaryC()
+ {
+ SCG.IComparer<string> h = new NaturalComparerO<string>();
+ string s = "bamse";
+ string t = "bamse";
+ string u = "bimse";
+
+ Assert.AreEqual(0, h.Compare(s, t));
+ Assert.IsTrue(h.Compare(s, u) < 0);
+ }
+
+
+ [Test]
+ public void GenericCViaBuilder()
+ {
+ SCG.IComparer<dbl> h = Comparer<dbl>.Default;
+ dbl s = new dbl(3.4);
+ dbl t = new dbl(3.4);
+ dbl u = new dbl(7.4);
+
+ Assert.AreEqual(0, h.Compare(s, t));
+ Assert.IsTrue(h.Compare(s, u) < 0);
+ Assert.AreSame(h, Comparer<dbl>.Default);
+ }
+
+
+ [Test]
+ public void OrdinaryCViaBuilder()
+ {
+ SCG.IComparer<string> h = Comparer<string>.Default;
+ string s = "bamse";
+ string t = "bamse";
+ string u = "bimse";
+
+ Assert.AreEqual(0, h.Compare(s, t));
+ Assert.IsTrue(h.Compare(s, u) < 0);
+ Assert.AreSame(h, Comparer<string>.Default);
+
+ }
+
+
+ [Test]
+ public void ICViaBuilder()
+ {
+ SCG.IComparer<int> h = Comparer<int>.Default;
+ int s = 4;
+ int t = 4;
+ int u = 5;
+
+ Assert.AreEqual(0, h.Compare(s, t));
+ Assert.IsTrue(h.Compare(s, u) < 0);
+ Assert.AreSame(h, Comparer<int>.Default);
+
+ }
+
+ [Test]
+ public void Nulls()
+ {
+ Assert.IsTrue(Comparer<string>.Default.Compare(null, "abe") < 0);
+ Assert.IsTrue(Comparer<string>.Default.Compare(null, null) == 0);
+ Assert.IsTrue(Comparer<string>.Default.Compare("abe", null) > 0);
+ }
+ }
+
+ [TestFixture]
+ public class EqualityComparers
+ {
+ [Test]
+ public void ReftypeequalityComparer()
+ {
+ SCG.IEqualityComparer<string> h = NaturalEqualityComparer<string>.Default;
+ string s = "bamse";
+ string t = "bamse";
+ string u = "bimse";
+
+ Assert.AreEqual(s.GetHashCode(), h.GetHashCode(s));
+ Assert.IsTrue(h.Equals(s, t));
+ Assert.IsFalse(h.Equals(s, u));
+ }
+
+
+ [Test]
+ public void ValuetypeequalityComparer()
+ {
+ SCG.IEqualityComparer<double> h = NaturalEqualityComparer<double>.Default;
+ double s = 3.4;
+ double t = 3.4;
+ double u = 5.7;
+
+ Assert.AreEqual(s.GetHashCode(), h.GetHashCode(s));
+ Assert.IsTrue(h.Equals(s, t));
+ Assert.IsFalse(h.Equals(s, u));
+ }
+
+ internal class REHTest { public override int GetHashCode() { return 37; } }
+
+ [Test]
+ public void ReferenceEqualityEqualityComparerTest()
+ {
+ REHTest rehtest = new REHTest();
+ SCG.IEqualityComparer<REHTest> equalityComparer = ReferenceEqualityComparer<REHTest>.Default;
+ Assert.AreEqual(37, rehtest.GetHashCode());
+ Assert.IsFalse(equalityComparer.GetHashCode(rehtest) == 37);
+ }
+
+ [Test]
+ public void ReftypeequalityComparerViaBuilder()
+ {
+ SCG.IEqualityComparer<string> h = EqualityComparer<string>.Default;
+ string s = "bamse";
+ string t = "bamse";
+ string u = "bimse";
+
+ Assert.AreEqual(s.GetHashCode(), h.GetHashCode(s));
+ Assert.IsTrue(h.Equals(s, t));
+ Assert.IsFalse(h.Equals(s, u));
+ Assert.AreSame(h, EqualityComparer<string>.Default);
+ }
+
+
+ [Test]
+ public void ValuetypeequalityComparerViaBuilder()
+ {
+ SCG.IEqualityComparer<double> h = EqualityComparer<double>.Default;
+ double s = 3.4;
+ double t = 3.4;
+ double u = 5.7;
+
+ Assert.AreEqual(s.GetHashCode(), h.GetHashCode(s));
+ Assert.IsTrue(h.Equals(s, t));
+ Assert.IsFalse(h.Equals(s, u));
+ Assert.AreSame(h, EqualityComparer<double>.Default);
+ }
+
+
+ [Test]
+ public void IntequalityComparerViaBuilder()
+ {
+ SCG.IEqualityComparer<int> h = EqualityComparer<int>.Default;
+ int s = 3;
+ int t = 3;
+ int u = 5;
+
+ Assert.AreEqual(s.GetHashCode(), h.GetHashCode(s));
+ Assert.IsTrue(h.Equals(s, t));
+ Assert.IsFalse(h.Equals(s, u));
+ Assert.AreSame(h, EqualityComparer<int>.Default);
+ }
+
+ [Test]
+ public void DoubleequalityComparerViaBuilder()
+ {
+ SCG.IEqualityComparer<double> h = EqualityComparer<double>.Default;
+ double s = 3.1;
+ double t = 3.1;
+ double u = 5.2;
+
+ Assert.AreEqual(s.GetHashCode(), h.GetHashCode(s));
+ Assert.IsTrue(h.Equals(s, t));
+ Assert.IsFalse(h.Equals(s, u));
+ Assert.AreSame(h, EqualityComparer<double>.Default);
+ }
+
+ [Test]
+ public void CharequalityComparerViaBuilder()
+ {
+ SCG.IEqualityComparer<char> h = EqualityComparer<char>.Default;
+ char s = 'å';
+ char t = 'å';
+ char u = 'r';
+
+ Assert.AreEqual(s.GetHashCode(), h.GetHashCode(s));
+ Assert.IsTrue(h.Equals(s, t));
+ Assert.IsFalse(h.Equals(s, u));
+ Assert.AreSame(h, EqualityComparer<char>.Default);
+ }
+
+ [Test]
+ public void ByteequalityComparerViaBuilder()
+ {
+ SCG.IEqualityComparer<byte> h = EqualityComparer<byte>.Default;
+ byte s = 3;
+ byte t = 3;
+ byte u = 5;
+
+ Assert.AreEqual(s.GetHashCode(), h.GetHashCode(s));
+ Assert.IsTrue(h.Equals(s, t));
+ Assert.IsFalse(h.Equals(s, u));
+ Assert.AreSame(h, EqualityComparer<byte>.Default);
+ }
+
+ [Test]
+ public void UnseqequalityComparerViaBuilder()
+ {
+ SCG.IEqualityComparer<ICollection<int>> h = EqualityComparer<ICollection<int>>.Default;
+ ICollection<int> s = new LinkedList<int>();
+ ICollection<int> t = new LinkedList<int>();
+ ICollection<int> u = new LinkedList<int>();
+ s.Add(1); s.Add(2); s.Add(3);
+ t.Add(3); t.Add(2); t.Add(1);
+ u.Add(3); u.Add(2); u.Add(4);
+ Assert.AreEqual(s.GetUnsequencedHashCode(), h.GetHashCode(s));
+ Assert.IsTrue(h.Equals(s, t));
+ Assert.IsFalse(h.Equals(s, u));
+ Assert.AreSame(h, EqualityComparer<ICollection<int>>.Default);
+ }
+
+ [Test]
+ public void SeqequalityComparerViaBuilder2()
+ {
+ SCG.IEqualityComparer<LinkedList<int>> h = EqualityComparer<LinkedList<int>>.Default;
+ LinkedList<int> s = new LinkedList<int>();
+ s.Add(1); s.Add(2); s.Add(3);
+ Assert.AreEqual(CHC.sequencedhashcode(1, 2, 3), h.GetHashCode(s));
+ }
+
+ [Test]
+ public void UnseqequalityComparerViaBuilder2()
+ {
+ SCG.IEqualityComparer<HashSet<int>> h = EqualityComparer<HashSet<int>>.Default;
+ HashSet<int> s = new HashSet<int>();
+ s.Add(1); s.Add(2); s.Add(3);
+ Assert.AreEqual(CHC.unsequencedhashcode(1, 2, 3), h.GetHashCode(s));
+ }
+
+ //generic types implementing collection interfaces
+ [Test]
+ public void SeqequalityComparerViaBuilder3()
+ {
+ SCG.IEqualityComparer<IList<int>> h = EqualityComparer<IList<int>>.Default;
+ IList<int> s = new LinkedList<int>();
+ s.Add(1); s.Add(2); s.Add(3);
+ Assert.AreEqual(CHC.sequencedhashcode(1, 2, 3), h.GetHashCode(s));
+ }
+
+ interface IFoo<T> : ICollection<T> { void Bamse(); }
+
+ class Foo<T> : HashSet<T>, IFoo<T>
+ {
+ internal Foo() : base() { }
+ public void Bamse() { }
+ }
+
+ [Test]
+ public void UnseqequalityComparerViaBuilder3()
+ {
+ SCG.IEqualityComparer<IFoo<int>> h = EqualityComparer<IFoo<int>>.Default;
+ IFoo<int> s = new Foo<int>();
+ s.Add(1); s.Add(2); s.Add(3);
+ Assert.AreEqual(CHC.unsequencedhashcode(1, 2, 3), h.GetHashCode(s));
+ }
+
+ //Nongeneric types implementing collection types:
+ interface IBaz : ISequenced<int> { void Bamse(); }
+
+ class Baz : LinkedList<int>, IBaz
+ {
+ internal Baz() : base() { }
+ public void Bamse() { }
+ //int ISequenced<int>.GetHashCode() { return sequencedhashcode(); }
+ //bool ISequenced<int>.Equals(ISequenced<int> that) { return sequencedequals(that); }
+ }
+
+#warning This test fails because of an error in .Net 2.0
+ //[Test]
+ public void SeqequalityComparerViaBuilder4()
+ {
+ SCG.IEqualityComparer<IBaz> h = EqualityComparer<IBaz>.Default;
+ IBaz s = new Baz();
+ s.Add(1); s.Add(2); s.Add(3);
+ Assert.AreEqual(CHC.sequencedhashcode(1, 2, 3), h.GetHashCode(s));
+ }
+
+ interface IBar : ICollection<int>
+ {
+ void Bamse();
+ }
+
+ class Bar : HashSet<int>, IBar
+ {
+ internal Bar() : base() { }
+ public void Bamse() { }
+
+ //TODO: remove all this workaround stuff:
+
+ bool ICollection<int>.ContainsAll<U>(System.Collections.Generic.IEnumerable<U> items)
+ {
+ throw new NotImplementedException();
+ }
+
+ void ICollection<int>.RemoveAll<U>(System.Collections.Generic.IEnumerable<U> items)
+ {
+ throw new NotImplementedException();
+ }
+
+ void ICollection<int>.RetainAll<U>(System.Collections.Generic.IEnumerable<U> items)
+ {
+ throw new NotImplementedException();
+ }
+
+ void IExtensible<int>.AddAll<U>(System.Collections.Generic.IEnumerable<U> items)
+ {
+ throw new NotImplementedException();
+ }
+
+ }
+
+ [Test]
+ public void UnseqequalityComparerViaBuilder4()
+ {
+ SCG.IEqualityComparer<IBar> h = EqualityComparer<IBar>.Default;
+ IBar s = new Bar();
+ s.Add(1); s.Add(2); s.Add(3);
+ Assert.AreEqual(CHC.unsequencedhashcode(1, 2, 3), h.GetHashCode(s));
+ }
+ }
+ }
+}
diff --git a/mcs/class/Mono.C5/1.0/Test/Records.cs b/mcs/class/Mono.C5/1.0/Test/Records.cs
new file mode 100644
index 00000000000..cb237824b77
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/Test/Records.cs
@@ -0,0 +1,119 @@
+/*
+ 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 C5;
+using NUnit.Framework;
+using SCG = System.Collections.Generic;
+
+namespace C5UnitTests.RecordsTests
+{
+ [TestFixture]
+ public class Basic
+ {
+ [SetUp]
+ public void Init()
+ {
+ }
+ [Test]
+ public void FourElement()
+ {
+ Rec<string, string, int, int> rec1, rec2, rec3;
+ rec1 = new Rec<string, string, int, int>("abe", null, 0, 1);
+ rec2 = new Rec<string, string, int, int>("abe", null, 0, 1);
+ rec3 = new Rec<string, string, int, int>("abe", "kat", 0, 1);
+ Assert.IsTrue(rec1 == rec2);
+ Assert.IsFalse(rec1 != rec2);
+ Assert.IsFalse(rec1 == rec3);
+ Assert.IsTrue(rec1 != rec3);
+ Assert.IsTrue(rec1.Equals(rec2));
+ Assert.IsFalse(rec1.Equals(rec3));
+ //
+ Assert.IsFalse(rec1.Equals(null));
+ Assert.IsFalse(rec1.Equals("bamse"));
+ //
+ Assert.IsTrue(rec1.GetHashCode() == rec2.GetHashCode());
+ Assert.IsFalse(rec1.GetHashCode() == rec3.GetHashCode());
+ //
+ Assert.AreEqual("abe", rec1.X1);
+ Assert.IsNull(rec1.X2);
+ Assert.AreEqual(0, rec1.X3);
+ Assert.AreEqual(1, rec1.X4);
+ }
+
+
+ [Test]
+ public void ThreeElement()
+ {
+ Rec<string, string, int> rec1, rec2, rec3;
+ rec1 = new Rec<string, string, int>("abe", null, 0);
+ rec2 = new Rec<string, string, int>("abe", null, 0);
+ rec3 = new Rec<string, string, int>("abe", "kat", 0);
+ Assert.IsTrue(rec1 == rec2);
+ Assert.IsFalse(rec1 != rec2);
+ Assert.IsFalse(rec1 == rec3);
+ Assert.IsTrue(rec1 != rec3);
+ Assert.IsTrue(rec1.Equals(rec2));
+ Assert.IsFalse(rec1.Equals(rec3));
+ //
+ Assert.IsFalse(rec1.Equals(null));
+ Assert.IsFalse(rec1.Equals("bamse"));
+ //
+ Assert.IsTrue(rec1.GetHashCode() == rec2.GetHashCode());
+ Assert.IsFalse(rec1.GetHashCode() == rec3.GetHashCode());
+ //
+ Assert.AreEqual("abe", rec1.X1);
+ Assert.IsNull(rec1.X2);
+ Assert.AreEqual(0, rec1.X3);
+
+ }
+
+ [Test]
+ public void TwoElement()
+ {
+ Rec<string, string> rec1, rec2, rec3;
+ rec1 = new Rec<string, string>("abe", null);
+ rec2 = new Rec<string, string>("abe", null);
+ rec3 = new Rec<string, string>("abe", "kat");
+ Assert.IsTrue(rec1 == rec2);
+ Assert.IsFalse(rec1 != rec2);
+ Assert.IsFalse(rec1 == rec3);
+ Assert.IsTrue(rec1 != rec3);
+ Assert.IsTrue(rec1.Equals(rec2));
+ Assert.IsFalse(rec1.Equals(rec3));
+ //
+ Assert.IsFalse(rec1.Equals(null));
+ Assert.IsFalse(rec1.Equals("bamse"));
+ //
+ Assert.IsTrue(rec1.GetHashCode() == rec2.GetHashCode());
+ Assert.IsFalse(rec1.GetHashCode() == rec3.GetHashCode());
+ //
+ Assert.AreEqual("abe", rec1.X1);
+ Assert.IsNull(rec1.X2);
+ }
+
+ [TearDown]
+ public void Dispose()
+ {
+ }
+ }
+
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/1.0/Test/Sorting.cs b/mcs/class/Mono.C5/1.0/Test/Sorting.cs
new file mode 100644
index 00000000000..38deb379c3c
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/Test/Sorting.cs
@@ -0,0 +1,268 @@
+/*
+ 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 C5;
+using NUnit.Framework;
+using SCG = System.Collections.Generic;
+
+namespace C5UnitTests.SortingTests
+{
+ [TestFixture]
+ public class SortRandom
+ {
+ IC ic;
+
+ Random ran;
+
+ int[] a;
+
+ int length;
+
+
+ [SetUp]
+ public void Init()
+ {
+ ic = new IC();
+ ran = new Random(3456);
+ length = 100000;
+ a = new int[length];
+ for (int i = 0; i < length; i++)
+ a[i] = ran.Next();
+ }
+
+
+ [Test]
+ public void HeapSort()
+ {
+ Sorting.HeapSort<int>(a, 0, length, ic);
+ for (int i = 1; i < length; i++)
+ Assert.IsTrue(a[i - 1] <= a[i], "Inversion at " + i);
+ }
+
+
+ [Test]
+ public void IntroSort()
+ {
+ Sorting.IntroSort<int>(a, 0, length, ic);
+ for (int i = 1; i < length; i++)
+ Assert.IsTrue(a[i - 1] <= a[i], "Inversion at " + i);
+ }
+
+
+ [Test]
+ public void InsertionSort()
+ {
+ length = 1000;
+ Sorting.InsertionSort<int>(a, 0, length, ic);
+ for (int i = 1; i < length; i++)
+ Assert.IsTrue(a[i - 1] <= a[i], "Inversion at " + i);
+
+ Sorting.InsertionSort<int>(a, length, 2 * length, ic);
+ for (int i = length + 1; i < 2 * length; i++)
+ Assert.IsTrue(a[i - 1] <= a[i], "Inversion at " + i);
+ }
+
+
+ [TearDown]
+ public void Dispose() { ic = null; }
+ }
+
+
+
+ [TestFixture]
+ public class SortRandomDuplicates
+ {
+ IC ic;
+
+ Random ran;
+
+ int[] a;
+
+ int length;
+
+
+ [SetUp]
+ public void Init()
+ {
+ ic = new IC();
+ ran = new Random(3456);
+ length = 100000;
+ a = new int[length];
+ for (int i = 0; i < length; i++)
+ a[i] = ran.Next(3, 23);
+ }
+
+
+ [Test]
+ public void HeapSort()
+ {
+ Sorting.HeapSort<int>(a, 0, length, ic);
+ for (int i = 1; i < length; i++)
+ Assert.IsTrue(a[i - 1] <= a[i], "Inversion at " + i);
+ }
+
+
+ [Test]
+ public void IntroSort()
+ {
+ Sorting.IntroSort<int>(a, 0, length, ic);
+ for (int i = 1; i < length; i++)
+ Assert.IsTrue(a[i - 1] <= a[i], "Inversion at " + i);
+ }
+
+
+ [Test]
+ public void InsertionSort()
+ {
+ length = 1000;
+ Sorting.InsertionSort<int>(a, 0, length, ic);
+ for (int i = 1; i < length; i++)
+ Assert.IsTrue(a[i - 1] <= a[i], "Inversion at " + i);
+
+ Sorting.InsertionSort<int>(a, length, 2 * length, ic);
+ for (int i = length + 1; i < 2 * length; i++)
+ Assert.IsTrue(a[i - 1] <= a[i], "Inversion at " + i);
+ }
+
+
+ [TearDown]
+ public void Dispose() { ic = null; a = null; ran = null; }
+ }
+
+
+
+ [TestFixture]
+ public class SortIncreasing
+ {
+ IC ic;
+
+ int[] a;
+
+ int length;
+
+
+ [SetUp]
+ public void Init()
+ {
+ ic = new IC();
+ length = 100000;
+ a = new int[length];
+ for (int i = 0; i < length; i++)
+ a[i] = i;
+ }
+
+
+ [Test]
+ public void HeapSort()
+ {
+ Sorting.HeapSort<int>(a, 0, length, ic);
+ for (int i = 1; i < length; i++)
+ Assert.IsTrue(a[i - 1] <= a[i], "Inversion at " + i);
+ }
+
+
+ [Test]
+ public void IntroSort()
+ {
+ Sorting.IntroSort<int>(a, 0, length, ic);
+ for (int i = 1; i < length; i++)
+ Assert.IsTrue(a[i - 1] <= a[i], "Inversion at " + i);
+ }
+
+
+ [Test]
+ public void InsertionSort()
+ {
+ length = 1000;
+ Sorting.InsertionSort<int>(a, 0, length, ic);
+ for (int i = 1; i < length; i++)
+ Assert.IsTrue(a[i - 1] <= a[i], "Inversion at " + i);
+
+ Sorting.InsertionSort<int>(a, length, 2 * length, ic);
+ for (int i = length + 1; i < 2 * length; i++)
+ Assert.IsTrue(a[i - 1] <= a[i], "Inversion at " + i);
+ }
+
+
+ [TearDown]
+ public void Dispose() { ic = null; a = null; }
+ }
+
+
+
+ [TestFixture]
+ public class SortDecreasing
+ {
+ IC ic;
+
+ int[] a;
+
+ int length;
+
+
+ [SetUp]
+ public void Init()
+ {
+ ic = new IC();
+ length = 100000;
+ a = new int[length];
+ for (int i = 0; i < length; i++)
+ a[i] = -i;
+ }
+
+
+ [Test]
+ public void HeapSort()
+ {
+ Sorting.HeapSort<int>(a, 0, length, ic);
+ for (int i = 1; i < length; i++)
+ Assert.IsTrue(a[i - 1] <= a[i], "Inversion at " + i);
+ }
+
+
+ [Test]
+ public void IntroSort()
+ {
+ Sorting.IntroSort<int>(a, 0, length, ic);
+ for (int i = 1; i < length; i++)
+ Assert.IsTrue(a[i - 1] <= a[i], "Inversion at " + i);
+ }
+
+
+ [Test]
+ public void InsertionSort()
+ {
+ length = 1000;
+ Sorting.InsertionSort<int>(a, 0, length, ic);
+ for (int i = 1; i < length; i++)
+ Assert.IsTrue(a[i - 1] <= a[i], "Inversion at " + i);
+
+ Sorting.InsertionSort<int>(a, length, 2 * length, ic);
+ for (int i = length + 1; i < 2 * length; i++)
+ Assert.IsTrue(a[i - 1] <= a[i], "Inversion at " + i);
+ }
+
+
+ [TearDown]
+ public void Dispose() { ic = null; a = null; }
+ }
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/1.0/Test/SupportClasses.cs b/mcs/class/Mono.C5/1.0/Test/SupportClasses.cs
new file mode 100644
index 00000000000..e48ba49dab8
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/Test/SupportClasses.cs
@@ -0,0 +1,493 @@
+/*
+ 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 C5;
+using NUnit.Framework;
+using SCG = System.Collections.Generic;
+
+
+namespace C5UnitTests
+{
+ class SC : SCG.IComparer<string>
+ {
+ public int Compare(string a, string b)
+ {
+ return a.CompareTo(b);
+ }
+
+
+ public void appl(String s)
+ {
+ System.Console.WriteLine("--{0}", s);
+ }
+ }
+
+ class TenEqualityComparer : SCG.IEqualityComparer<int>, SCG.IComparer<int>
+ {
+ TenEqualityComparer() { }
+ public static TenEqualityComparer Default { get { return new TenEqualityComparer(); } }
+ public int GetHashCode(int item) { return (item / 10).GetHashCode(); }
+ public bool Equals(int item1, int item2) { return item1 / 10 == item2 / 10; }
+ public int Compare(int a, int b) { return (a / 10).CompareTo(b / 10); }
+ }
+
+ class IC : SCG.IComparer<int>, IComparable<int>, SCG.IComparer<IC>, IComparable<IC>
+ {
+ public int Compare(int a, int b)
+ {
+ return a > b ? 1 : a < b ? -1 : 0;
+ }
+
+
+ public int Compare(IC a, IC b)
+ {
+ return a._i > b._i ? 1 : a._i < b._i ? -1 : 0;
+ }
+
+
+ private int _i;
+
+
+ public int i
+ {
+ get { return _i; }
+ set { _i = value; }
+ }
+
+
+ public IC() { }
+
+
+ public IC(int i) { _i = i; }
+
+
+ public int CompareTo(int that) { return _i > that ? 1 : _i < that ? -1 : 0; }
+
+ public bool Equals(int that) { return _i == that; }
+
+
+ public int CompareTo(IC that) { return _i > that._i ? 1 : _i < that._i ? -1 : 0; }
+ public bool Equals(IC that) { return _i == that._i; }
+
+
+ public static bool eq(SCG.IEnumerable<int> me, params int[] that)
+ {
+ int i = 0, maxind = that.Length - 1;
+
+ foreach (int item in me)
+ if (i > maxind || item != that[i++])
+ return false;
+
+ return i == maxind + 1;
+ }
+ public static bool seteq(ICollectionValue<int> me, params int[] that)
+ {
+ int[] me2 = me.ToArray();
+
+ Array.Sort(me2);
+
+ int i = 0, maxind = that.Length - 1;
+
+ foreach (int item in me2)
+ if (i > maxind || item != that[i++])
+ return false;
+
+ return i == maxind + 1;
+ }
+ public static bool seteq(ICollectionValue<KeyValuePair<int, int>> me, params int[] that)
+ {
+ ArrayList<KeyValuePair<int, int>> first = new ArrayList<KeyValuePair<int, int>>();
+ first.AddAll(me);
+ ArrayList<KeyValuePair<int, int>> other = new ArrayList<KeyValuePair<int, int>>();
+ for (int i = 0; i < that.Length; i += 2)
+ {
+ other.Add(new KeyValuePair<int, int>(that[i], that[i + 1]));
+ }
+ return other.UnsequencedEquals(first);
+ }
+ }
+
+ class RevIC : SCG.IComparer<int>
+ {
+ public int Compare(int a, int b)
+ {
+ return a > b ? -1 : a < b ? 1 : 0;
+ }
+ }
+
+ public class FunEnumerable : SCG.IEnumerable<int>
+ {
+ int size;
+ Fun<int, int> f;
+
+ public FunEnumerable(int size, Fun<int, int> f)
+ {
+ this.size = size; this.f = f;
+ }
+
+ public SCG.IEnumerator<int> GetEnumerator()
+ {
+ for (int i = 0; i < size; i++)
+ yield return f(i);
+ }
+
+
+ #region IEnumerable Members
+
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+ {
+ throw new Exception("The method or operation is not implemented.");
+ }
+
+ #endregion
+ }
+
+ public class BadEnumerableException : Exception { }
+
+ public class BadEnumerable<T> : CollectionValueBase<T>, ICollectionValue<T>
+ {
+ T[] contents;
+ Exception exception;
+
+ public BadEnumerable(Exception exception, params T[] contents)
+ {
+ this.contents = (T[])contents.Clone();
+ this.exception = exception;
+ }
+
+ public override SCG.IEnumerator<T> GetEnumerator()
+ {
+ for (int i = 0; i < contents.Length; i++)
+ yield return contents[i];
+ throw exception;
+ }
+
+ public override bool IsEmpty { get { return false; } }
+
+ public override int Count { get { return contents.Length + 1; } }
+
+ public override Speed CountSpeed { get { return Speed.Constant; } }
+
+ public override T Choose() { throw exception; }
+ }
+
+ public class CollectionEventList<T>
+ {
+ ArrayList<CollectionEvent<T>> happened;
+ EventTypeEnum listenTo;
+ SCG.IEqualityComparer<T> itemequalityComparer;
+ public CollectionEventList(SCG.IEqualityComparer<T> itemequalityComparer)
+ {
+ happened = new ArrayList<CollectionEvent<T>>();
+ this.itemequalityComparer = itemequalityComparer;
+ }
+ public void Listen(ICollectionValue<T> list, EventTypeEnum listenTo)
+ {
+ this.listenTo = listenTo;
+ if ((listenTo & EventTypeEnum.Changed) != 0)
+ list.CollectionChanged += new CollectionChangedHandler<T>(changed);
+ if ((listenTo & EventTypeEnum.Cleared) != 0)
+ list.CollectionCleared += new CollectionClearedHandler<T>(cleared);
+ if ((listenTo & EventTypeEnum.Removed) != 0)
+ list.ItemsRemoved += new ItemsRemovedHandler<T>(removed);
+ if ((listenTo & EventTypeEnum.Added) != 0)
+ list.ItemsAdded += new ItemsAddedHandler<T>(added);
+ if ((listenTo & EventTypeEnum.Inserted) != 0)
+ list.ItemInserted += new ItemInsertedHandler<T>(inserted);
+ if ((listenTo & EventTypeEnum.RemovedAt) != 0)
+ list.ItemRemovedAt += new ItemRemovedAtHandler<T>(removedAt);
+ }
+ public void Add(CollectionEvent<T> e) { happened.Add(e); }
+ /// <summary>
+ /// Check that we have seen exactly the events in expected that match listenTo.
+ /// </summary>
+ /// <param name="expected"></param>
+ public void Check(SCG.IEnumerable<CollectionEvent<T>> expected)
+ {
+ int i = 0;
+ foreach (CollectionEvent<T> expectedEvent in expected)
+ {
+ if ((expectedEvent.Act & listenTo) == 0)
+ continue;
+ if (i >= happened.Count)
+ Assert.Fail(string.Format("Event number {0} did not happen:\n expected {1}", i, expectedEvent));
+ if (!expectedEvent.Equals(happened[i], itemequalityComparer))
+ Assert.Fail(string.Format("Event number {0}:\n expected {1}\n but saw {2}", i, expectedEvent, happened[i]));
+ i++;
+ }
+ if (i < happened.Count)
+ Assert.Fail(string.Format("Event number {0} seen but no event expected:\n {1}", i, happened[i]));
+ happened.Clear();
+ }
+ public void Clear() { happened.Clear(); }
+ public void Print(System.IO.TextWriter writer)
+ {
+ happened.Apply(delegate(CollectionEvent<T> e) { writer.WriteLine(e); });
+ }
+ void changed(object sender)
+ {
+ happened.Add(new CollectionEvent<T>(EventTypeEnum.Changed, new EventArgs(), sender));
+ }
+ void cleared(object sender, ClearedEventArgs eventArgs)
+ {
+ happened.Add(new CollectionEvent<T>(EventTypeEnum.Cleared, eventArgs, sender));
+ }
+ void added(object sender, ItemCountEventArgs<T> eventArgs)
+ {
+ happened.Add(new CollectionEvent<T>(EventTypeEnum.Added, eventArgs, sender));
+ }
+ void removed(object sender, ItemCountEventArgs<T> eventArgs)
+ {
+ happened.Add(new CollectionEvent<T>(EventTypeEnum.Removed, eventArgs, sender));
+ }
+ void inserted(object sender, ItemAtEventArgs<T> eventArgs)
+ {
+ happened.Add(new CollectionEvent<T>(EventTypeEnum.Inserted, eventArgs, sender));
+ }
+ void removedAt(object sender, ItemAtEventArgs<T> eventArgs)
+ {
+ happened.Add(new CollectionEvent<T>(EventTypeEnum.RemovedAt, eventArgs, sender));
+ }
+ }
+
+ public sealed class CollectionEvent<T>
+ {
+ public readonly EventTypeEnum Act;
+ public readonly EventArgs Args;
+ public readonly object Sender;
+
+ public CollectionEvent(EventTypeEnum act, EventArgs args, object sender)
+ {
+ this.Act = act;
+ this.Args = args;
+ this.Sender = sender;
+ }
+
+ public bool Equals(CollectionEvent<T> otherEvent, SCG.IEqualityComparer<T> itemequalityComparer)
+ {
+ if (otherEvent == null || Act != otherEvent.Act || !object.ReferenceEquals(Sender, otherEvent.Sender))
+ return false;
+ switch (Act)
+ {
+ case EventTypeEnum.None:
+ break;
+ case EventTypeEnum.Changed:
+ return true;
+ case EventTypeEnum.Cleared:
+ if (Args is ClearedRangeEventArgs)
+ {
+ ClearedRangeEventArgs a = Args as ClearedRangeEventArgs, o = otherEvent.Args as ClearedRangeEventArgs;
+ if (o == null)
+ return false;
+ return a.Full == o.Full && a.Start == o.Start && a.Count == o.Count;
+ }
+ else
+ {
+ if (otherEvent.Args is ClearedRangeEventArgs)
+ return false;
+ ClearedEventArgs a = Args as ClearedEventArgs, o = otherEvent.Args as ClearedEventArgs;
+ return a.Full == o.Full && a.Count == o.Count;
+ }
+ case EventTypeEnum.Added:
+ {
+ ItemCountEventArgs<T> a = Args as ItemCountEventArgs<T>, o = otherEvent.Args as ItemCountEventArgs<T>;
+ return itemequalityComparer.Equals(a.Item, o.Item) && a.Count == o.Count;
+ }
+ case EventTypeEnum.Removed:
+ {
+ ItemCountEventArgs<T> a = Args as ItemCountEventArgs<T>, o = otherEvent.Args as ItemCountEventArgs<T>;
+ return itemequalityComparer.Equals(a.Item, o.Item) && a.Count == o.Count;
+ }
+ case EventTypeEnum.Inserted:
+ {
+ ItemAtEventArgs<T> a = Args as ItemAtEventArgs<T>, o = otherEvent.Args as ItemAtEventArgs<T>;
+ return a.Index == o.Index && itemequalityComparer.Equals(a.Item, o.Item);
+ }
+ case EventTypeEnum.RemovedAt:
+ {
+ ItemAtEventArgs<T> a = Args as ItemAtEventArgs<T>, o = otherEvent.Args as ItemAtEventArgs<T>;
+ return a.Index == o.Index && itemequalityComparer.Equals(a.Item, o.Item);
+ }
+ }
+ throw new ApplicationException("Illegat Act: " + Act);
+ }
+
+ public override string ToString()
+ {
+ return string.Format("Act: {0}, Args : {1}, Source : {2}", Act, Args, Sender);
+ }
+
+ }
+
+ public class CHC
+ {
+ static public int unsequencedhashcode(params int[] a)
+ {
+ int h = 0;
+ foreach (int i in a)
+ {
+ h += (int)(((uint)i * 1529784657 + 1) ^ ((uint)i * 2912831877) ^ ((uint)i * 1118771817 + 2));
+ }
+ return h;
+ }
+ static public int sequencedhashcode(params int[] a)
+ {
+ int h = 0;
+ foreach (int i in a) { h = h * 31 + i; }
+ return h;
+ }
+ }
+
+ //This class is a modified sample from VS2005 beta1 documentation
+ public class RadixFormatProvider : IFormatProvider
+ {
+ RadixFormatter _radixformatter;
+ public RadixFormatProvider(int radix)
+ {
+ if (radix < 2 || radix > 36)
+ throw new ArgumentException(String.Format(
+ "The radix \"{0}\" is not in the range 2..36.",
+ radix));
+ _radixformatter = new RadixFormatter(radix);
+ }
+ public object GetFormat(Type argType)
+ {
+ if (argType == typeof(ICustomFormatter))
+ return _radixformatter;
+ else
+ return null;
+ }
+ }
+
+ //This class is a modified sample from VS2005 beta1 documentation
+ public class RadixFormatter : ICustomFormatter
+ {
+ int radix;
+ public RadixFormatter(int radix)
+ {
+ if (radix < 2 || radix > 36)
+ throw new ArgumentException(String.Format(
+ "The radix \"{0}\" is not in the range 2..36.",
+ radix));
+ this.radix = radix;
+ }
+
+ // The value to be formatted is returned as a signed string
+ // of digits from the rDigits array.
+ private static char[] rDigits = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
+ 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+ 'U', 'V', 'W', 'X', 'Y', 'Z' };
+
+ public string Format(string formatString,
+ object argToBeFormatted, IFormatProvider provider)
+ {
+ /*switch (Type.GetTypeCode(argToBeFormatted.GetType()))
+ {
+ case TypeCode.Boolean:
+ break;
+ case TypeCode.Byte:
+ break;
+ case TypeCode.Char:
+ break;
+ case TypeCode.DBNull:
+ break;
+ case TypeCode.DateTime:
+ break;
+ case TypeCode.Decimal:
+ break;
+ case TypeCode.Double:
+ break;
+ case TypeCode.Empty:
+ break;
+ case TypeCode.Int16:
+ break;
+ case TypeCode.Int32:
+ break;
+ case TypeCode.Int64:
+ break;
+ case TypeCode.Object:
+ break;
+ case TypeCode.SByte:
+ break;
+ case TypeCode.Single:
+ break;
+ case TypeCode.String:
+ break;
+ case TypeCode.UInt16:
+ break;
+ case TypeCode.UInt32:
+ break;
+ case TypeCode.UInt64:
+ break;
+ }*/
+ int intToBeFormatted;
+ try
+ {
+ intToBeFormatted = (int)argToBeFormatted;
+ }
+ catch (Exception)
+ {
+ if (argToBeFormatted is IFormattable)
+ return ((IFormattable)argToBeFormatted).
+ ToString(formatString, provider);
+ else
+ return argToBeFormatted.ToString();
+ }
+ return formatInt(intToBeFormatted);
+ }
+
+ private string formatInt(int intToBeFormatted)
+ {
+ // The formatting is handled here.
+ if (intToBeFormatted == 0)
+ return "0";
+ int digitIndex = 0;
+ int intPositive;
+ char[] outDigits = new char[31];
+
+ // Verify that the argument can be converted to a int integer.
+ // Extract the magnitude for conversion.
+ intPositive = Math.Abs(intToBeFormatted);
+
+ // Convert the magnitude to a digit string.
+ for (digitIndex = 0; digitIndex <= 32; digitIndex++)
+ {
+ if (intPositive == 0) break;
+
+ outDigits[outDigits.Length - digitIndex - 1] =
+ rDigits[intPositive % radix];
+ intPositive /= radix;
+ }
+
+ // Add a minus sign if the argument is negative.
+ if (intToBeFormatted < 0)
+ outDigits[outDigits.Length - digitIndex++ - 1] =
+ '-';
+
+ return new string(outDigits,
+ outDigits.Length - digitIndex, digitIndex);
+ }
+ }
+
+}
diff --git a/mcs/class/Mono.C5/1.0/Test/WrappersTest.cs b/mcs/class/Mono.C5/1.0/Test/WrappersTest.cs
new file mode 100644
index 00000000000..15a13f3dbfc
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/Test/WrappersTest.cs
@@ -0,0 +1,857 @@
+/*
+ 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 C5;
+using NUnit.Framework;
+using SCG = System.Collections.Generic;
+
+
+namespace C5UnitTests.wrappers
+{
+ namespace Events
+ {
+ [TestFixture]
+ public class IList_
+ {
+ private ArrayList<int> list;
+ ICollectionValue<int> guarded;
+ CollectionEventList<int> seen;
+
+ [SetUp]
+ public void Init()
+ {
+ list = new ArrayList<int>(TenEqualityComparer.Default);
+ guarded = new GuardedList<int>(list);
+ seen = new CollectionEventList<int>(IntEqualityComparer.Default);
+ }
+
+ private void listen() { seen.Listen(guarded, EventTypeEnum.All); }
+
+ [Test]
+ public void Listenable()
+ {
+ Assert.AreEqual(EventTypeEnum.All, guarded.ListenableEvents);
+ Assert.AreEqual(EventTypeEnum.None, guarded.ActiveEvents);
+ listen();
+ Assert.AreEqual(EventTypeEnum.All, guarded.ActiveEvents);
+ }
+
+ [Test]
+ public void SetThis()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list[1] = 45;
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(56, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(56,1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(45, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(45,1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)
+ });
+ }
+
+ [Test]
+ public void Insert()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.Insert(1, 45);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(45,1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(45, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)
+ });
+ }
+
+ [Test]
+ public void InsertAll()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.InsertAll<int>(1, new int[] { 666, 777, 888 });
+ //seen.Print(Console.Error);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(666,1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(666, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(777,2), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(777, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(888,3), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(888, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)
+ });
+ list.InsertAll<int>(1, new int[] {});
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+ [Test]
+ public void InsertFirstLast()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.InsertFirst(45);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(45,0), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(45, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)
+ });
+ list.InsertLast(88);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(88,4), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(88, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)
+ });
+ }
+
+ [Test]
+ public void Remove()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.Remove();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(8, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)});
+ }
+
+ [Test]
+ public void RemoveFirst()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.RemoveFirst();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(4,0), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(4, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)});
+ }
+
+ [Test]
+ public void RemoveLast()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.RemoveLast();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(8,2), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(8, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)});
+ }
+
+ [Test]
+ public void Reverse()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.Reverse();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)
+ });
+ list.View(1, 0).Reverse();
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+
+ [Test]
+ public void Sort()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.Sort();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)
+ });
+ list.View(1, 0).Sort();
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+ [Test]
+ public void Shuffle()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.Shuffle();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)
+ });
+ list.View(1, 0).Shuffle();
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+ [Test]
+ public void RemoveAt()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.RemoveAt(1);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(56,1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(56, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)});
+ }
+
+ [Test]
+ public void RemoveInterval()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.RemoveInterval(1, 2);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Cleared, new ClearedRangeEventArgs(false,2,1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)
+ });
+ list.RemoveInterval(1, 0);
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+ [Test]
+ public void Update()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.Update(53);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(56, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(53, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)
+ });
+ list.Update(67);
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+ [Test]
+ public void FindOrAdd()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ int val = 53;
+ list.FindOrAdd(ref val);
+ seen.Check(new CollectionEvent<int>[] {});
+ val = 67;
+ list.FindOrAdd(ref val);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(67, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)
+ });
+ }
+
+ [Test]
+ public void UpdateOrAdd()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ int val = 53;
+ list.UpdateOrAdd(val);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(56, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(53, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)
+ });
+ val = 67;
+ list.UpdateOrAdd(val);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(67, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)
+ });
+ list.UpdateOrAdd(51, out val);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(53, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(51, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)
+ });
+ val = 67;
+ list.UpdateOrAdd(81, out val);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(81, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)
+ });
+ }
+
+ [Test]
+ public void RemoveItem()
+ {
+ list.Add(4); list.Add(56); list.Add(18);
+ listen();
+ list.Remove(53);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(56, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)});
+ list.Remove(11);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(18, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)});
+ }
+
+ [Test]
+ public void RemoveAll()
+ {
+ for (int i = 0; i < 10; i++)
+ {
+ list.Add(10 * i + 5);
+ }
+ listen();
+ list.RemoveAll<int>(new int[] { 32, 187, 45 });
+ //TODO: the order depends on internals of the HashSet
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(35, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(45, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)});
+ list.RemoveAll<int>(new int[] { 200, 300 });
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+ [Test]
+ public void Clear()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.View(1, 1).Clear();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Cleared, new ClearedRangeEventArgs(false,1,1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)
+ });
+ list.Clear();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Cleared, new ClearedRangeEventArgs(true,2,0), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)
+ });
+ list.Clear();
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+ [Test]
+ public void ListDispose()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.View(1, 1).Dispose();
+ seen.Check(new CollectionEvent<int>[] {});
+ list.Dispose();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Cleared, new ClearedRangeEventArgs(true,3,0), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)
+ });
+ list.Dispose();
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+
+ [Test]
+ public void RetainAll()
+ {
+ for (int i = 0; i < 10; i++)
+ {
+ list.Add(10 * i + 5);
+ }
+ listen();
+ list.RetainAll<int>(new int[] { 32, 187, 45, 62, 82, 95, 2 });
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(15, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(25, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(55, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(75, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)});
+ list.RetainAll<int>(new int[] { 32, 187, 45, 62, 82, 95, 2 });
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+ [Test]
+ public void RemoveAllCopies()
+ {
+ for (int i = 0; i < 10; i++)
+ {
+ list.Add(3 * i + 5);
+ }
+ listen();
+ list.RemoveAllCopies(14);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(11, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(14, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(17, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)});
+ list.RemoveAllCopies(14);
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+ [Test]
+ public void Add()
+ {
+ listen();
+ seen.Check(new CollectionEvent<int>[0]);
+ list.Add(23);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(23, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)});
+ }
+
+ [Test]
+ public void AddAll()
+ {
+ for (int i = 0; i < 10; i++)
+ {
+ list.Add(10 * i + 5);
+ }
+ listen();
+ list.AddAll<int>(new int[] { 45, 56, 67 });
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(45, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(56, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(67, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)});
+ list.AddAll<int>(new int[] { });
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+ [TearDown]
+ public void Dispose() { list = null; seen = null; }
+
+ [Test]
+ [ExpectedException(typeof(UnlistenableEventException))]
+ public void ViewChanged()
+ {
+ IList<int> w = list.View(0, 0);
+ w.CollectionChanged += new CollectionChangedHandler<int>(w_CollectionChanged);
+ }
+
+ [Test]
+ [ExpectedException(typeof(UnlistenableEventException))]
+ public void ViewCleared()
+ {
+ IList<int> w = list.View(0, 0);
+ w.CollectionCleared += new CollectionClearedHandler<int>(w_CollectionCleared);
+ }
+
+ [Test]
+ [ExpectedException(typeof(UnlistenableEventException))]
+ public void ViewAdded()
+ {
+ IList<int> w = list.View(0, 0);
+ w.ItemsAdded += new ItemsAddedHandler<int>(w_ItemAdded);
+ }
+
+ [Test]
+ [ExpectedException(typeof(UnlistenableEventException))]
+ public void ViewInserted()
+ {
+ IList<int> w = list.View(0, 0);
+ w.ItemInserted += new ItemInsertedHandler<int>(w_ItemInserted);
+ }
+
+ [Test]
+ [ExpectedException(typeof(UnlistenableEventException))]
+ public void ViewRemoved()
+ {
+ IList<int> w = list.View(0, 0);
+ w.ItemsRemoved += new ItemsRemovedHandler<int>(w_ItemRemoved);
+ }
+
+ [Test]
+ [ExpectedException(typeof(UnlistenableEventException))]
+ public void ViewRemovedAt()
+ {
+ IList<int> w = list.View(0, 0);
+ w.ItemRemovedAt += new ItemRemovedAtHandler<int>(w_ItemRemovedAt);
+ }
+
+ void w_CollectionChanged(object sender)
+ {
+ throw new NotImplementedException();
+ }
+
+ void w_CollectionCleared(object sender, ClearedEventArgs eventArgs)
+ {
+ throw new NotImplementedException();
+ }
+
+ void w_ItemAdded(object sender, ItemCountEventArgs<int> eventArgs)
+ {
+ throw new NotImplementedException();
+ }
+
+ void w_ItemInserted(object sender, ItemAtEventArgs<int> eventArgs)
+ {
+ throw new NotImplementedException();
+ }
+
+ void w_ItemRemoved(object sender, ItemCountEventArgs<int> eventArgs)
+ {
+ throw new NotImplementedException();
+ }
+
+ void w_ItemRemovedAt(object sender, ItemAtEventArgs<int> eventArgs)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ [TestFixture]
+ public class StackQueue
+ {
+ private ArrayList<int> list;
+ ICollectionValue<int> guarded;
+ CollectionEventList<int> seen;
+
+ [SetUp]
+ public void Init()
+ {
+ list = new ArrayList<int>(TenEqualityComparer.Default);
+ guarded = new GuardedList<int>(list);
+ seen = new CollectionEventList<int>(IntEqualityComparer.Default);
+ }
+
+ private void listen() { seen.Listen(guarded, EventTypeEnum.All); }
+
+
+ [Test]
+ public void EnqueueDequeue()
+ {
+ listen();
+ list.Enqueue(67);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(67,0), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(67, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)});
+ list.Enqueue(2);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(2,1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(2, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)});
+ list.Dequeue();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(67,0), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(67, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)});
+ list.Dequeue();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(2,0), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(2, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)});
+ }
+
+ [Test]
+ public void PushPop()
+ {
+ listen();
+ seen.Check(new CollectionEvent<int>[0]);
+ list.Push(23);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(23,0), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(23, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)});
+ list.Push(-12);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(-12,1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(-12, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)});
+ list.Pop();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(-12,1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(-12, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)});
+ list.Pop();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(23,0), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(23, 1), guarded),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), guarded)});
+ }
+
+ [TearDown]
+ public void Dispose() { list = null; seen = null; }
+ }
+
+
+ }
+
+ namespace wrappedarray
+ {
+ [TestFixture]
+ public class Basic
+ {
+
+ [SetUp]
+ public void Init()
+ {
+ }
+
+ [TearDown]
+ public void Dispose()
+ {
+ }
+
+ [Test]
+ public void NoExc()
+ {
+ WrappedArray<int> wrapped = new WrappedArray<int>(new int[] { 4, 6, 5 });
+ Assert.AreEqual(6, wrapped[1]);
+ Assert.IsTrue(IC.eq(wrapped[1, 2], 6, 5));
+ //
+ Fun<int, bool> is4 = delegate(int i) { return i == 4; };
+ Assert.AreEqual(EventTypeEnum.None, wrapped.ActiveEvents);
+ Assert.AreEqual(false, wrapped.All(is4));
+ Assert.AreEqual(true, wrapped.AllowsDuplicates);
+ wrapped.Apply(delegate(int i) { });
+ Assert.AreEqual("{ 5, 6, 4 }", wrapped.Backwards().ToString());
+ Assert.AreEqual(true, wrapped.Check());
+ wrapped.Choose();
+ Assert.AreEqual(true, wrapped.Contains(4));
+ Assert.AreEqual(true, wrapped.ContainsAll(new ArrayList<int>()));
+ Assert.AreEqual(1, wrapped.ContainsCount(4));
+ Assert.AreEqual(Speed.Linear, wrapped.ContainsSpeed);
+ int[] extarray = new int[5];
+ wrapped.CopyTo(extarray, 1);
+ Assert.IsTrue(IC.eq(extarray, 0, 4, 6, 5, 0));
+ Assert.AreEqual(3, wrapped.Count);
+ Assert.AreEqual(Speed.Constant, wrapped.CountSpeed);
+ Assert.AreEqual(EnumerationDirection.Forwards, wrapped.Direction);
+ Assert.AreEqual(false, wrapped.DuplicatesByCounting);
+ Assert.AreEqual(IntEqualityComparer.Default, wrapped.EqualityComparer);
+ Assert.AreEqual(true, wrapped.Exists(is4));
+ Assert.IsTrue(IC.eq(wrapped.Filter(is4), 4));
+ int j = 5;
+ Assert.AreEqual(true, wrapped.Find(ref j));
+ Assert.AreEqual(true, wrapped.Find(is4, out j));
+ Assert.AreEqual("[ 0:4 ]", wrapped.FindAll(is4).ToString());
+ Assert.AreEqual(0, wrapped.FindIndex(is4));
+ Assert.AreEqual(true, wrapped.FindLast(is4, out j));
+ Assert.AreEqual(0, wrapped.FindLastIndex(is4));
+ Assert.AreEqual(4, wrapped.First);
+ wrapped.GetEnumerator();
+ Assert.AreEqual(CHC.sequencedhashcode(4, 6, 5), wrapped.GetSequencedHashCode());
+ Assert.AreEqual(CHC.unsequencedhashcode(4, 6, 5), wrapped.GetUnsequencedHashCode());
+ Assert.AreEqual(Speed.Constant, wrapped.IndexingSpeed);
+ Assert.AreEqual(2, wrapped.IndexOf(5));
+ Assert.AreEqual(false, wrapped.IsEmpty);
+ Assert.AreEqual(true, wrapped.IsReadOnly);
+ Assert.AreEqual(false, wrapped.IsSorted());
+ Assert.AreEqual(true, wrapped.IsValid);
+ Assert.AreEqual(5, wrapped.Last);
+ Assert.AreEqual(2, wrapped.LastIndexOf(5));
+ Assert.AreEqual(EventTypeEnum.None, wrapped.ListenableEvents);
+ Fun<int, string> i2s = delegate(int i) { return string.Format("T{0}", i); };
+ Assert.AreEqual("[ 0:T4, 1:T6, 2:T5 ]", wrapped.Map<string>(i2s).ToString());
+ Assert.AreEqual(0, wrapped.Offset);
+ wrapped.Reverse();
+ Assert.AreEqual("[ 0:5, 1:6, 2:4 ]", wrapped.ToString());
+ IList<int> other = new ArrayList<int>(); other.AddAll<int>(new int[] { 4, 5, 6 });
+ Assert.IsFalse(wrapped.SequencedEquals(other));
+ j = 30;
+ Assert.AreEqual(true, wrapped.Show(new System.Text.StringBuilder(), ref j, null));
+ wrapped.Sort();
+ Assert.AreEqual("[ 0:4, 1:5, 2:6 ]", wrapped.ToString());
+ Assert.IsNotNull(wrapped.SyncRoot);
+ Assert.IsTrue(IC.eq(wrapped.ToArray(), 4, 5, 6));
+ Assert.AreEqual("[ ... ]", wrapped.ToString("L4", null));
+ Assert.AreEqual(null, wrapped.Underlying);
+ Assert.IsTrue(IC.seteq(wrapped.UniqueItems(), 4, 5, 6));
+ Assert.IsTrue(wrapped.UnsequencedEquals(other));
+ wrapped.Shuffle();
+ Assert.IsTrue(IC.seteq(wrapped.UniqueItems(), 4, 5, 6));
+ }
+
+ [Test]
+ public void WithExc()
+ {
+ WrappedArray<int> wrapped = new WrappedArray<int>(new int[] { 3, 4, 6, 5, 7 });
+ //
+ try { wrapped.Add(1); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.AddAll<int>(null); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.Clear(); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.Dispose(); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ int j = 1;
+ try { wrapped.FindOrAdd(ref j); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.Insert(1, 1); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.Insert(wrapped.View(0, 0), 1); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.InsertAll<int>(1, null); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.InsertFirst(1); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.InsertLast(1); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.Remove(); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.Remove(1); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.RemoveAll<int>(null); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.RemoveAllCopies(1); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.RemoveAt(1); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.RemoveFirst(); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.RemoveInterval(0, 0); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.RemoveLast(); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.RetainAll<int>(null); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.Update(1, out j); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.UpdateOrAdd(1); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ }
+
+ [Test]
+ public void View()
+ {
+ WrappedArray<int> outerwrapped = new WrappedArray<int>(new int[] { 3, 4, 6, 5, 7 });
+ WrappedArray<int> wrapped = (WrappedArray<int>)outerwrapped.View(1, 3);
+ //
+ Assert.AreEqual(6, wrapped[1]);
+ Assert.IsTrue(IC.eq(wrapped[1, 2], 6, 5));
+ //
+ Fun<int, bool> is4 = delegate(int i) { return i == 4; };
+ Assert.AreEqual(EventTypeEnum.None, wrapped.ActiveEvents);
+ Assert.AreEqual(false, wrapped.All(is4));
+ Assert.AreEqual(true, wrapped.AllowsDuplicates);
+ wrapped.Apply(delegate(int i) { });
+ Assert.AreEqual("{ 5, 6, 4 }", wrapped.Backwards().ToString());
+ Assert.AreEqual(true, wrapped.Check());
+ wrapped.Choose();
+ Assert.AreEqual(true, wrapped.Contains(4));
+ Assert.AreEqual(true, wrapped.ContainsAll(new ArrayList<int>()));
+ Assert.AreEqual(1, wrapped.ContainsCount(4));
+ Assert.AreEqual(Speed.Linear, wrapped.ContainsSpeed);
+ int[] extarray = new int[5];
+ wrapped.CopyTo(extarray, 1);
+ Assert.IsTrue(IC.eq(extarray, 0, 4, 6, 5, 0));
+ Assert.AreEqual(3, wrapped.Count);
+ Assert.AreEqual(Speed.Constant, wrapped.CountSpeed);
+ Assert.AreEqual(EnumerationDirection.Forwards, wrapped.Direction);
+ Assert.AreEqual(false, wrapped.DuplicatesByCounting);
+ Assert.AreEqual(IntEqualityComparer.Default, wrapped.EqualityComparer);
+ Assert.AreEqual(true, wrapped.Exists(is4));
+ Assert.IsTrue(IC.eq(wrapped.Filter(is4), 4));
+ int j = 5;
+ Assert.AreEqual(true, wrapped.Find(ref j));
+ Assert.AreEqual(true, wrapped.Find(is4, out j));
+ Assert.AreEqual("[ 0:4 ]", wrapped.FindAll(is4).ToString());
+ Assert.AreEqual(0, wrapped.FindIndex(is4));
+ Assert.AreEqual(true, wrapped.FindLast(is4, out j));
+ Assert.AreEqual(0, wrapped.FindLastIndex(is4));
+ Assert.AreEqual(4, wrapped.First);
+ wrapped.GetEnumerator();
+ Assert.AreEqual(CHC.sequencedhashcode(4, 6, 5), wrapped.GetSequencedHashCode());
+ Assert.AreEqual(CHC.unsequencedhashcode(4, 6, 5), wrapped.GetUnsequencedHashCode());
+ Assert.AreEqual(Speed.Constant, wrapped.IndexingSpeed);
+ Assert.AreEqual(2, wrapped.IndexOf(5));
+ Assert.AreEqual(false, wrapped.IsEmpty);
+ Assert.AreEqual(true, wrapped.IsReadOnly);
+ Assert.AreEqual(false, wrapped.IsSorted());
+ Assert.AreEqual(true, wrapped.IsValid);
+ Assert.AreEqual(5, wrapped.Last);
+ Assert.AreEqual(2, wrapped.LastIndexOf(5));
+ Assert.AreEqual(EventTypeEnum.None, wrapped.ListenableEvents);
+ Fun<int, string> i2s = delegate(int i) { return string.Format("T{0}", i); };
+ Assert.AreEqual("[ 0:T4, 1:T6, 2:T5 ]", wrapped.Map<string>(i2s).ToString());
+ Assert.AreEqual(1, wrapped.Offset);
+ wrapped.Reverse();
+ Assert.AreEqual("[ 0:5, 1:6, 2:4 ]", wrapped.ToString());
+ IList<int> other = new ArrayList<int>(); other.AddAll<int>(new int[] { 4, 5, 6 });
+ Assert.IsFalse(wrapped.SequencedEquals(other));
+ j = 30;
+ Assert.AreEqual(true, wrapped.Show(new System.Text.StringBuilder(), ref j, null));
+ wrapped.Sort();
+ Assert.AreEqual("[ 0:4, 1:5, 2:6 ]", wrapped.ToString());
+ Assert.IsNotNull(wrapped.SyncRoot);
+ Assert.IsTrue(IC.eq(wrapped.ToArray(), 4, 5, 6));
+ Assert.AreEqual("[ ... ]", wrapped.ToString("L4", null));
+ Assert.AreEqual(outerwrapped, wrapped.Underlying);
+ Assert.IsTrue(IC.seteq(wrapped.UniqueItems(), 4, 5, 6));
+ Assert.IsTrue(wrapped.UnsequencedEquals(other));
+ //
+ Assert.IsTrue(wrapped.TrySlide(1));
+ Assert.IsTrue(IC.eq(wrapped, 5, 6, 7));
+ Assert.IsTrue(wrapped.TrySlide(-1, 2));
+ Assert.IsTrue(IC.eq(wrapped, 4, 5));
+ Assert.IsFalse(wrapped.TrySlide(-2));
+ Assert.IsTrue(IC.eq(wrapped.Span(outerwrapped.ViewOf(7)), 4, 5, 6, 7));
+ //
+ wrapped.Shuffle();
+ Assert.IsTrue(IC.seteq(wrapped.UniqueItems(), 4, 5));
+ Assert.IsTrue(wrapped.IsValid);
+ wrapped.Dispose();
+ Assert.IsFalse(wrapped.IsValid);
+ }
+
+ [Test]
+ public void ViewWithExc()
+ {
+ WrappedArray<int> outerwrapped = new WrappedArray<int>(new int[] { 3, 4, 6, 5, 7 });
+ WrappedArray<int> wrapped = (WrappedArray<int>)outerwrapped.View(1, 3);
+ //
+ try { wrapped.Add(1); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.AddAll<int>(null); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.Clear(); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ //Should not throw
+ //try { wrapped.Dispose(); Assert.Fail("No throw"); }
+ //catch (FixedSizeCollectionException) { }
+ int j = 1;
+ try { wrapped.FindOrAdd(ref j); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.Insert(1, 1); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.Insert(wrapped.View(0, 0), 1); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.InsertAll<int>(1, null); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.InsertFirst(1); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.InsertLast(1); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.Remove(); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.Remove(1); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.RemoveAll<int>(null); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.RemoveAllCopies(1); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.RemoveAt(1); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.RemoveFirst(); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.RemoveInterval(0, 0); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.RemoveLast(); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.RetainAll<int>(null); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.Update(1, out j); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ try { wrapped.UpdateOrAdd(1); Assert.Fail("No throw"); }
+ catch (FixedSizeCollectionException) { }
+ }
+ }
+ }
+}
+
diff --git a/mcs/class/Mono.C5/1.0/Test/arrays/ArrayListTest.cs b/mcs/class/Mono.C5/1.0/Test/arrays/ArrayListTest.cs
new file mode 100644
index 00000000000..af492d1c56d
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/Test/arrays/ArrayListTest.cs
@@ -0,0 +1,3821 @@
+/*
+ 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 C5;
+using NUnit.Framework;
+using SCG = System.Collections.Generic;
+
+namespace C5UnitTests.arrays.list
+{
+ using CollectionOfInt = ArrayList<int>;
+
+ [TestFixture]
+ public class GenericTesters
+ {
+ [Test]
+ public void TestEvents()
+ {
+ Fun<CollectionOfInt> factory = delegate() { return new CollectionOfInt(TenEqualityComparer.Default); };
+ new C5UnitTests.Templates.Events.ListTester<CollectionOfInt>().Test(factory);
+ new C5UnitTests.Templates.Events.QueueTester<CollectionOfInt>().Test(factory);
+ new C5UnitTests.Templates.Events.StackTester<CollectionOfInt>().Test(factory);
+ }
+
+ [Test]
+ public void Extensible()
+ {
+ C5UnitTests.Templates.Extensible.Clone.Tester<CollectionOfInt>();
+ C5UnitTests.Templates.Extensible.Clone.ViewTester<CollectionOfInt>();
+ C5UnitTests.Templates.Extensible.Serialization.Tester<CollectionOfInt>();
+ C5UnitTests.Templates.Extensible.Serialization.ViewTester<CollectionOfInt>();
+ }
+ }
+
+ static class Factory
+ {
+ public static ICollection<T> New<T>() { return new ArrayList<T>(); }
+ }
+
+ namespace Events
+ {
+ [TestFixture]
+ public class IList_
+ {
+ private ArrayList<int> list;
+ CollectionEventList<int> seen;
+
+ [SetUp]
+ public void Init()
+ {
+ list = new ArrayList<int>(TenEqualityComparer.Default);
+ seen = new CollectionEventList<int>(IntEqualityComparer.Default);
+ }
+
+ private void listen() { seen.Listen(list, EventTypeEnum.Added); }
+
+ [Test]
+ public void Listenable()
+ {
+ Assert.AreEqual(EventTypeEnum.All, list.ListenableEvents);
+ Assert.AreEqual(EventTypeEnum.None, list.ActiveEvents);
+ listen();
+ Assert.AreEqual(EventTypeEnum.Added, list.ActiveEvents);
+ }
+
+ [Test]
+ public void SetThis()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list[1] = 45;
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(56, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(56,1), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(45, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(45,1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ }
+
+ [Test]
+ public void Insert()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.Insert(1, 45);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(45,1), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(45, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ }
+
+ [Test]
+ public void InsertAll()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.InsertAll<int>(1, new int[] { 666, 777, 888 });
+ //seen.Print(Console.Error);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(666,1), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(666, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(777,2), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(777, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(888,3), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(888, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ list.InsertAll<int>(1, new int[] {});
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+ [Test]
+ public void InsertFirstLast()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.InsertFirst(45);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(45,0), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(45, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ list.InsertLast(88);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(88,4), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(88, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ }
+
+ [Test]
+ public void Remove()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.Remove();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(8, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ }
+
+ [Test]
+ public void RemoveFirst()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.RemoveFirst();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(4,0), list),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(4, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ }
+
+ [Test]
+ public void RemoveLast()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.RemoveLast();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(8,2), list),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(8, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ }
+
+ [Test]
+ public void Reverse()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.Reverse();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ list.View(1, 0).Reverse();
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+
+ [Test]
+ public void Sort()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.Sort();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ list.View(1, 0).Sort();
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+ [Test]
+ public void Shuffle()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.Shuffle();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ list.View(1, 0).Shuffle();
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+ [Test]
+ public void RemoveAt()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.RemoveAt(1);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(56,1), list),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(56, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ }
+
+ [Test]
+ public void RemoveInterval()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.RemoveInterval(1, 2);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Cleared, new ClearedRangeEventArgs(false,2,1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ list.RemoveInterval(1, 0);
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+ [Test]
+ public void Update()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.Update(53);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(56, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(53, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ list.Update(67);
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+ [Test]
+ public void FindOrAdd()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ int val = 53;
+ list.FindOrAdd(ref val);
+ seen.Check(new CollectionEvent<int>[] {});
+ val = 67;
+ list.FindOrAdd(ref val);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(67, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ }
+
+ [Test]
+ public void UpdateOrAdd()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ int val = 53;
+ list.UpdateOrAdd(val);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(56, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(53, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ val = 67;
+ list.UpdateOrAdd(val);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(67, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ list.UpdateOrAdd(51, out val);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(53, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(51, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ val = 67;
+ list.UpdateOrAdd(81, out val);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(81, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ }
+
+ [Test]
+ public void RemoveItem()
+ {
+ list.Add(4); list.Add(56); list.Add(18);
+ listen();
+ list.Remove(53);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(56, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ list.Remove(11);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(18, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ }
+
+ [Test]
+ public void RemoveAll()
+ {
+ for (int i = 0; i < 10; i++)
+ {
+ list.Add(10 * i + 5);
+ }
+ listen();
+ list.RemoveAll<int>(new int[] { 32, 187, 45 });
+ //TODO: the order depends on internals of the HashSet
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(35, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(45, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ list.RemoveAll<int>(new int[] { 200, 300 });
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+ [Test]
+ public void Clear()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.View(1, 1).Clear();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Cleared, new ClearedRangeEventArgs(false,1,1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ list.Clear();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Cleared, new ClearedRangeEventArgs(true,2,0), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ list.Clear();
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+ [Test]
+ public void ListDispose()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.View(1, 1).Dispose();
+ seen.Check(new CollectionEvent<int>[] {});
+ list.Dispose();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Cleared, new ClearedRangeEventArgs(true,3,0), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ list.Dispose();
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+
+ [Test]
+ public void RetainAll()
+ {
+ for (int i = 0; i < 10; i++)
+ {
+ list.Add(10 * i + 5);
+ }
+ listen();
+ list.RetainAll<int>(new int[] { 32, 187, 45, 62, 82, 95, 2 });
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(15, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(25, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(55, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(75, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ list.RetainAll<int>(new int[] { 32, 187, 45, 62, 82, 95, 2 });
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+ [Test]
+ public void RemoveAllCopies()
+ {
+ for (int i = 0; i < 10; i++)
+ {
+ list.Add(3 * i + 5);
+ }
+ listen();
+ list.RemoveAllCopies(14);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(11, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(14, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(17, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ list.RemoveAllCopies(14);
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+ [Test]
+ public void Add()
+ {
+ listen();
+ seen.Check(new CollectionEvent<int>[0]);
+ list.Add(23);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(23, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ }
+
+ [Test]
+ public void AddAll()
+ {
+ for (int i = 0; i < 10; i++)
+ {
+ list.Add(10 * i + 5);
+ }
+ listen();
+ list.AddAll<int>(new int[] { 45, 56, 67 });
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(45, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(56, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(67, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ list.AddAll<int>(new int[] { });
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+ [TearDown]
+ public void Dispose() { list = null; seen = null; }
+
+ [Test]
+ [ExpectedException(typeof(UnlistenableEventException))]
+ public void ViewChanged()
+ {
+ IList<int> w = list.View(0, 0);
+ w.CollectionChanged += new CollectionChangedHandler<int>(w_CollectionChanged);
+ }
+
+ [Test]
+ [ExpectedException(typeof(UnlistenableEventException))]
+ public void ViewCleared()
+ {
+ IList<int> w = list.View(0, 0);
+ w.CollectionCleared += new CollectionClearedHandler<int>(w_CollectionCleared);
+ }
+
+ [Test]
+ [ExpectedException(typeof(UnlistenableEventException))]
+ public void ViewAdded()
+ {
+ IList<int> w = list.View(0, 0);
+ w.ItemsAdded += new ItemsAddedHandler<int>(w_ItemAdded);
+ }
+
+ [Test]
+ [ExpectedException(typeof(UnlistenableEventException))]
+ public void ViewInserted()
+ {
+ IList<int> w = list.View(0, 0);
+ w.ItemInserted += new ItemInsertedHandler<int>(w_ItemInserted);
+ }
+
+ [Test]
+ [ExpectedException(typeof(UnlistenableEventException))]
+ public void ViewRemoved()
+ {
+ IList<int> w = list.View(0, 0);
+ w.ItemsRemoved += new ItemsRemovedHandler<int>(w_ItemRemoved);
+ }
+
+ [Test]
+ [ExpectedException(typeof(UnlistenableEventException))]
+ public void ViewRemovedAt()
+ {
+ IList<int> w = list.View(0, 0);
+ w.ItemRemovedAt += new ItemRemovedAtHandler<int>(w_ItemRemovedAt);
+ }
+
+ void w_CollectionChanged(object sender)
+ {
+ throw new NotImplementedException();
+ }
+
+ void w_CollectionCleared(object sender, ClearedEventArgs eventArgs)
+ {
+ throw new NotImplementedException();
+ }
+
+ void w_ItemAdded(object sender, ItemCountEventArgs<int> eventArgs)
+ {
+ throw new NotImplementedException();
+ }
+
+ void w_ItemInserted(object sender, ItemAtEventArgs<int> eventArgs)
+ {
+ throw new NotImplementedException();
+ }
+
+ void w_ItemRemoved(object sender, ItemCountEventArgs<int> eventArgs)
+ {
+ throw new NotImplementedException();
+ }
+
+ void w_ItemRemovedAt(object sender, ItemAtEventArgs<int> eventArgs)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ [TestFixture]
+ public class StackQueue
+ {
+
+ private ArrayList<int> list;
+ CollectionEventList<int> seen;
+
+ [SetUp]
+ public void Init()
+ {
+ list = new ArrayList<int>(TenEqualityComparer.Default);
+ seen = new CollectionEventList<int>(IntEqualityComparer.Default);
+ }
+
+ private void listen() { seen.Listen(list, EventTypeEnum.All); }
+
+ [Test]
+ public void EnqueueDequeue()
+ {
+ listen();
+ list.Enqueue(67);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(67,0), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(67, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ list.Enqueue(2);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(2,1), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(2, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ list.Dequeue();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(67,0), list),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(67, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ list.Dequeue();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(2,0), list),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(2, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ }
+
+ [Test]
+ public void PushPop()
+ {
+ listen();
+ seen.Check(new CollectionEvent<int>[0]);
+ list.Push(23);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(23,0), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(23, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ list.Push(-12);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(-12,1), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(-12, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ list.Pop();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(-12,1), list),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(-12, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ list.Pop();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(23,0), list),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(23, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ }
+
+ [TearDown]
+ public void Dispose() { list = null; seen = null; }
+ }
+ }
+
+ namespace Safety
+ {
+ /// <summary>
+ /// Tests to see if the collection classes are robust for enumerable arguments that throw exceptions.
+ /// </summary>
+ [TestFixture]
+ public class BadEnumerable
+ {
+ private ArrayList<int> list;
+
+ [SetUp]
+ public void Init()
+ {
+ list = new ArrayList<int>();
+ }
+
+ [Test]
+ public void InsertAll()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ try
+ {
+ list.InsertAll<int>(1, new BadEnumerable<int>(new BadEnumerableException(), 9, 8, 7));
+ Assert.Fail("Should not get here");
+ }
+ catch (BadEnumerableException) { }
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4, 9, 8, 7, 56, 8));
+
+ }
+
+ [Test]
+ public void AddAll()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ try
+ {
+ list.View(0, 1).AddAll<int>(new BadEnumerable<int>(new BadEnumerableException(), 9, 8, 7));
+ Assert.Fail("Should not get here");
+ }
+ catch (BadEnumerableException) { }
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4, 9, 8, 7, 56, 8));
+ }
+
+ [Test]
+ public void RemoveAll()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ try
+ {
+ list.RemoveAll(new BadEnumerable<int>(new BadEnumerableException(), 9, 8, 7));
+ Assert.Fail("Should not get here");
+ }
+ catch (BadEnumerableException) { }
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4, 56, 8));
+ }
+
+ [Test]
+ public void RetainAll()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ try
+ {
+ list.RetainAll(new BadEnumerable<int>(new BadEnumerableException(), 9, 8, 7));
+ Assert.Fail("Should not get here");
+ }
+ catch (BadEnumerableException) { }
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4, 56, 8));
+ }
+
+
+ [Test]
+ public void ContainsAll()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ try
+ {
+ list.ContainsAll(new BadEnumerable<int>(new BadEnumerableException(), 4, 18));
+ Assert.Fail("Should not get here");
+ }
+ catch (BadEnumerableException) { }
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4, 56, 8));
+ }
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+ }
+
+ /// <summary>
+ /// Tests to see if the collection classes are robust for delegate arguments that throw exceptions.
+ /// </summary>
+ [TestFixture]
+ public class BadFun
+ {
+ private ArrayList<int> list;
+
+ [SetUp]
+ public void Init()
+ {
+ list = new ArrayList<int>();
+ }
+
+ [Test]
+ public void NoTests() { }
+
+ [TearDown]
+ public void Dispose() { list = null; }
+ }
+ }
+
+ namespace Enumerable
+ {
+ [TestFixture]
+ public class Multiops
+ {
+ private ArrayList<int> list;
+
+ private Fun<int, bool> always, never, even;
+
+
+ [SetUp]
+ public void Init()
+ {
+ list = new ArrayList<int>();
+ always = delegate { return true; };
+ never = delegate { return false; };
+ even = delegate(int i) { return i % 2 == 0; };
+ }
+
+
+ [Test]
+ public void All()
+ {
+ Assert.IsTrue(list.All(always));
+ Assert.IsTrue(list.All(never));
+ Assert.IsTrue(list.All(even));
+ list.Add(8);
+ Assert.IsTrue(list.All(always));
+ Assert.IsFalse(list.All(never));
+ Assert.IsTrue(list.All(even));
+ list.Add(5);
+ Assert.IsTrue(list.All(always));
+ Assert.IsFalse(list.All(never));
+ Assert.IsFalse(list.All(even));
+ }
+
+
+ [Test]
+ public void Exists()
+ {
+ Assert.IsFalse(list.Exists(always));
+ Assert.IsFalse(list.Exists(never));
+ Assert.IsFalse(list.Exists(even));
+ list.Add(5);
+ Assert.IsTrue(list.Exists(always));
+ Assert.IsFalse(list.Exists(never));
+ Assert.IsFalse(list.Exists(even));
+ list.Add(8);
+ Assert.IsTrue(list.Exists(always));
+ Assert.IsFalse(list.Exists(never));
+ Assert.IsTrue(list.Exists(even));
+ }
+
+
+ [Test]
+ public void Apply()
+ {
+ int sum = 0;
+ Act<int> a = delegate(int i) { sum = i + 10 * sum; };
+
+ list.Apply(a);
+ Assert.AreEqual(0, sum);
+ sum = 0;
+ list.Add(5); list.Add(8); list.Add(7); list.Add(5);
+ list.Apply(a);
+ Assert.AreEqual(5875, sum);
+ }
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+ }
+
+
+
+ [TestFixture]
+ public class GetEnumerator
+ {
+ private ArrayList<int> list;
+
+
+ [SetUp]
+ public void Init() { list = new ArrayList<int>(); }
+
+
+ [Test]
+ public void Empty()
+ {
+ SCG.IEnumerator<int> e = list.GetEnumerator();
+
+ Assert.IsFalse(e.MoveNext());
+ }
+
+
+ [Test]
+ public void Normal()
+ {
+ list.Add(5);
+ list.Add(8);
+ list.Add(5);
+ list.Add(5);
+ list.Add(10);
+ list.Add(1);
+
+ SCG.IEnumerator<int> e = list.GetEnumerator();
+
+ Assert.IsTrue(e.MoveNext());
+ Assert.AreEqual(5, e.Current);
+ Assert.IsTrue(e.MoveNext());
+ Assert.AreEqual(8, e.Current);
+ Assert.IsTrue(e.MoveNext());
+ Assert.AreEqual(5, e.Current);
+ Assert.IsTrue(e.MoveNext());
+ Assert.AreEqual(5, e.Current);
+ Assert.IsTrue(e.MoveNext());
+ Assert.AreEqual(10, e.Current);
+ Assert.IsTrue(e.MoveNext());
+ Assert.AreEqual(1, e.Current);
+ Assert.IsFalse(e.MoveNext());
+ }
+
+
+ [Test]
+ public void DoDispose()
+ {
+ list.Add(5);
+ list.Add(8);
+ list.Add(5);
+
+ SCG.IEnumerator<int> e = list.GetEnumerator();
+
+ e.MoveNext();
+ e.MoveNext();
+ e.Dispose();
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void MoveNextAfterUpdate()
+ {
+ list.Add(5);
+ list.Add(8);
+ list.Add(5);
+
+ SCG.IEnumerator<int> e = list.GetEnumerator();
+
+ e.MoveNext();
+ list.Add(99);
+ e.MoveNext();
+ }
+
+ [TearDown]
+ public void Dispose() { list = null; }
+ }
+ }
+
+ namespace CollectionOrSink
+ {
+ [TestFixture]
+ public class Formatting
+ {
+ ICollection<int> coll;
+ IFormatProvider rad16;
+ [SetUp]
+ public void Init() { coll = Factory.New<int>(); rad16 = new RadixFormatProvider(16); }
+ [TearDown]
+ public void Dispose() { coll = null; rad16 = null; }
+ [Test]
+ public void Format()
+ {
+ Assert.AreEqual("[ ]", coll.ToString());
+ coll.AddAll<int>(new int[] { -4, 28, 129, 65530 });
+ Assert.AreEqual("[ 0:-4, 1:28, 2:129, 3:65530 ]", coll.ToString());
+ Assert.AreEqual("[ 0:-4, 1:1C, 2:81, 3:FFFA ]", coll.ToString(null, rad16));
+ Assert.AreEqual("[ 0:-4, 1:28... ]", coll.ToString("L14", null));
+ Assert.AreEqual("[ 0:-4, 1:1C... ]", coll.ToString("L14", rad16));
+ }
+ }
+
+ [TestFixture]
+ public class CollectionOrSink
+ {
+ private ArrayList<int> list;
+
+
+ [SetUp]
+ public void Init() { list = new ArrayList<int>(); }
+
+ [Test]
+ public void Choose()
+ {
+ list.Add(7);
+ Assert.AreEqual(7, list.Choose());
+ }
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void BadChoose()
+ {
+ list.Choose();
+ }
+
+ [Test]
+ public void CountEtAl()
+ {
+ Assert.AreEqual(0, list.Count);
+ Assert.IsTrue(list.IsEmpty);
+ Assert.IsTrue(list.AllowsDuplicates);
+ list.Add(5);
+ Assert.AreEqual(1, list.Count);
+ Assert.IsFalse(list.IsEmpty);
+ list.Add(5);
+ Assert.AreEqual(2, list.Count);
+ Assert.IsFalse(list.IsEmpty);
+ list.Add(8);
+ Assert.AreEqual(3, list.Count);
+ }
+
+
+ [Test]
+ public void AddAll()
+ {
+ list.Add(3); list.Add(4); list.Add(5);
+
+ ArrayList<int> list2 = new ArrayList<int>();
+
+ list2.AddAll(list);
+ Assert.IsTrue(IC.eq(list2, 3, 4, 5));
+ list.AddAll(list2);
+ Assert.IsTrue(IC.eq(list2, 3, 4, 5));
+ Assert.IsTrue(IC.eq(list, 3, 4, 5, 3, 4, 5));
+ }
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+ }
+
+ [TestFixture]
+ public class FindPredicate
+ {
+ private ArrayList<int> list;
+ Fun<int, bool> pred;
+
+ [SetUp]
+ public void Init()
+ {
+ list = new ArrayList<int>(TenEqualityComparer.Default);
+ pred = delegate(int i) { return i % 5 == 0; };
+ }
+
+ [TearDown]
+ public void Dispose() { list = null; }
+
+ [Test]
+ public void Find()
+ {
+ int i;
+ Assert.IsFalse(list.Find(pred, out i));
+ list.AddAll<int>(new int[] { 4, 22, 67, 37 });
+ Assert.IsFalse(list.Find(pred, out i));
+ list.AddAll<int>(new int[] { 45, 122, 675, 137 });
+ Assert.IsTrue(list.Find(pred, out i));
+ Assert.AreEqual(45, i);
+ }
+
+ [Test]
+ public void FindLast()
+ {
+ int i;
+ Assert.IsFalse(list.FindLast(pred, out i));
+ list.AddAll<int>(new int[] { 4, 22, 67, 37 });
+ Assert.IsFalse(list.FindLast(pred, out i));
+ list.AddAll<int>(new int[] { 45, 122, 675, 137 });
+ Assert.IsTrue(list.FindLast(pred, out i));
+ Assert.AreEqual(675, i);
+ }
+
+ [Test]
+ public void FindIndex()
+ {
+ Assert.IsFalse(0 <= list.FindIndex(pred));
+ list.AddAll<int>(new int[] { 4, 22, 67, 37 });
+ Assert.IsFalse(0 <= list.FindIndex(pred));
+ list.AddAll<int>(new int[] { 45, 122, 675, 137 });
+ Assert.AreEqual(4, list.FindIndex(pred));
+ }
+
+ [Test]
+ public void FindLastIndex()
+ {
+ Assert.IsFalse(0 <= list.FindLastIndex(pred));
+ list.AddAll<int>(new int[] { 4, 22, 67, 37 });
+ Assert.IsFalse(0 <= list.FindLastIndex(pred));
+ list.AddAll<int>(new int[] { 45, 122, 675, 137 });
+ Assert.AreEqual(6, list.FindLastIndex(pred));
+ }
+ }
+
+ [TestFixture]
+ public class UniqueItems
+ {
+ private ArrayList<int> list;
+
+ [SetUp]
+ public void Init() { list = new ArrayList<int>(); }
+
+ [TearDown]
+ public void Dispose() { list = null; }
+
+ [Test]
+ public void Test()
+ {
+ Assert.IsTrue(IC.seteq(list.UniqueItems()));
+ Assert.IsTrue(IC.seteq(list.ItemMultiplicities()));
+ list.AddAll<int>(new int[] { 7, 9, 7 });
+ Assert.IsTrue(IC.seteq(list.UniqueItems(), 7, 9));
+ Assert.IsTrue(IC.seteq(list.ItemMultiplicities(), 7, 2, 9, 1));
+ }
+ }
+
+ [TestFixture]
+ public class ArrayTest
+ {
+ private ArrayList<int> list;
+
+ int[] a;
+
+
+ [SetUp]
+ public void Init()
+ {
+ list = new ArrayList<int>();
+ a = new int[10];
+ for (int i = 0; i < 10; i++)
+ a[i] = 1000 + i;
+ }
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+
+
+ private string aeq(int[] a, params int[] b)
+ {
+ if (a.Length != b.Length)
+ return "Lengths differ: " + a.Length + " != " + b.Length;
+
+ for (int i = 0; i < a.Length; i++)
+ if (a[i] != b[i])
+ return String.Format("{0}'th elements differ: {1} != {2}", i, a[i], b[i]);
+
+ return "Alles klar";
+ }
+
+
+ [Test]
+ public void ToArray()
+ {
+ Assert.AreEqual("Alles klar", aeq(list.ToArray()));
+ list.Add(7);
+ list.Add(7);
+ Assert.AreEqual("Alles klar", aeq(list.ToArray(), 7, 7));
+ }
+
+
+ [Test]
+ public void CopyTo()
+ {
+ list.CopyTo(a, 1);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009));
+ list.Add(6);
+ list.CopyTo(a, 2);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 6, 1003, 1004, 1005, 1006, 1007, 1008, 1009));
+ list.Add(4);
+ list.Add(4);
+ list.Add(9);
+ list.CopyTo(a, 4);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 6, 1003, 6, 4, 4, 9, 1008, 1009));
+ list.Clear();
+ list.Add(7);
+ list.CopyTo(a, 9);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 6, 1003, 6, 4, 4, 9, 1008, 7));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void CopyToBad()
+ {
+ list.CopyTo(a, 11);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void CopyToBad2()
+ {
+ list.CopyTo(a, -1);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void CopyToTooFar()
+ {
+ list.Add(3);
+ list.Add(3);
+ list.CopyTo(a, 9);
+ }
+ }
+
+ [TestFixture]
+ public class Sync
+ {
+ private ArrayList<int> list;
+
+
+ [SetUp]
+ public void Init()
+ {
+ list = new ArrayList<int>();
+ }
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+
+
+ [Test]
+ public void Get()
+ {
+ Assert.IsNotNull(list.SyncRoot);
+ }
+ }
+ }
+
+
+
+
+ namespace EditableCollection
+ {
+ [TestFixture]
+ public class Searching
+ {
+ private ArrayList<int> list;
+
+
+ [SetUp]
+ public void Init() { list = new ArrayList<int>(); }
+
+ [Test]
+ [ExpectedException(typeof(NullReferenceException))]
+ public void NullEqualityComparerinConstructor1()
+ {
+ new ArrayList<int>(null);
+ }
+
+ [Test]
+ [ExpectedException(typeof(NullReferenceException))]
+ public void NullEqualityComparerinConstructor2()
+ {
+ new ArrayList<int>(5, null);
+ }
+
+ [Test]
+ public void Contains()
+ {
+ Assert.IsFalse(list.Contains(5));
+ list.Add(5);
+ Assert.IsTrue(list.Contains(5));
+ Assert.IsFalse(list.Contains(7));
+ list.Add(8);
+ list.Add(10);
+ Assert.IsTrue(list.Contains(5));
+ Assert.IsFalse(list.Contains(7));
+ Assert.IsTrue(list.Contains(8));
+ Assert.IsTrue(list.Contains(10));
+ list.Remove(8);
+ Assert.IsTrue(list.Contains(5));
+ Assert.IsFalse(list.Contains(7));
+ Assert.IsFalse(list.Contains(8));
+ Assert.IsTrue(list.Contains(10));
+ }
+
+
+ [Test]
+ public void ContainsCount()
+ {
+ Assert.AreEqual(0, list.ContainsCount(5));
+ list.Add(5);
+ Assert.AreEqual(1, list.ContainsCount(5));
+ Assert.AreEqual(0, list.ContainsCount(7));
+ list.Add(8);
+ Assert.AreEqual(1, list.ContainsCount(5));
+ Assert.AreEqual(0, list.ContainsCount(7));
+ Assert.AreEqual(1, list.ContainsCount(8));
+ list.Add(5);
+ Assert.AreEqual(2, list.ContainsCount(5));
+ Assert.AreEqual(0, list.ContainsCount(7));
+ Assert.AreEqual(1, list.ContainsCount(8));
+ }
+
+
+ [Test]
+ public void RemoveAllCopies()
+ {
+ list.Add(5); list.Add(7); list.Add(5);
+ Assert.AreEqual(2, list.ContainsCount(5));
+ Assert.AreEqual(1, list.ContainsCount(7));
+ list.RemoveAllCopies(5);
+ Assert.AreEqual(0, list.ContainsCount(5));
+ Assert.AreEqual(1, list.ContainsCount(7));
+ list.Add(5); list.Add(8); list.Add(5);
+ list.RemoveAllCopies(8);
+ Assert.IsTrue(IC.eq(list, 7, 5, 5));
+ }
+
+
+ [Test]
+ public void FindAll()
+ {
+ Fun<int, bool> f = delegate(int i) { return i % 2 == 0; };
+
+ Assert.IsTrue(list.FindAll(f).IsEmpty);
+ list.Add(5); list.Add(8); list.Add(5); list.Add(10); list.Add(8);
+ Assert.IsTrue(((ArrayList<int>)list.FindAll(f)).Check());
+ Assert.IsTrue(IC.eq(list.FindAll(f), 8, 10, 8));
+ }
+
+
+ [Test]
+ public void ContainsAll()
+ {
+ ArrayList<int> list2 = new ArrayList<int>();
+
+ Assert.IsTrue(list.ContainsAll(list2));
+ list2.Add(4);
+ Assert.IsFalse(list.ContainsAll(list2));
+ list.Add(4);
+ Assert.IsTrue(list.ContainsAll(list2));
+ list.Add(5);
+ Assert.IsTrue(list.ContainsAll(list2));
+ list2.Add(4);
+ Assert.IsFalse(list.ContainsAll(list2));
+ list.Add(4);
+ Assert.IsTrue(list.ContainsAll(list2));
+ }
+
+
+ [Test]
+ public void RetainAll()
+ {
+ ArrayList<int> list2 = new ArrayList<int>();
+
+ list.Add(4); list.Add(4); list.Add(5); list.Add(4); list.Add(6);
+ list2.Add(5); list2.Add(4); list2.Add(7); list2.Add(7); list2.Add(4);
+ list.RetainAll(list2);
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4, 4, 5));
+ list.Add(5); list.Add(4); list.Add(6);
+ list2.Clear();
+ list2.Add(5); list2.Add(5); list2.Add(6);
+ list.RetainAll(list2);
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 5, 5, 6));
+ list2.Clear();
+ list2.Add(7); list2.Add(8); list2.Add(9);
+ list.RetainAll(list2);
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list));
+ }
+
+
+ [Test]
+ public void RemoveAll()
+ {
+ ArrayList<int> list2 = new ArrayList<int>();
+
+ list.Add(4); list.Add(4); list.Add(5); list.Add(4); list.Add(6);
+ list2.Add(5); list2.Add(4); list2.Add(7); list2.Add(7); list2.Add(4);
+ list.RemoveAll(list2);
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4, 6));
+ list.Add(5); list.Add(4); list.Add(6);
+ list2.Clear();
+ list2.Add(6); list2.Add(5); list2.Add(5); list2.Add(6);
+ list.RemoveAll(list2);
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4, 4));
+ list2.Clear();
+ list2.Add(7); list2.Add(8); list2.Add(9);
+ list.RemoveAll(list2);
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4, 4));
+ }
+
+
+ [Test]
+ public void Remove()
+ {
+ Assert.IsFalse(list.FIFO);
+ list.Add(4); list.Add(4); list.Add(5); list.Add(4); list.Add(6);
+ Assert.IsFalse(list.Remove(2));
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(list.Remove(4));
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4, 4, 5, 6));
+ Assert.AreEqual(6, list.RemoveLast());
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4, 4, 5));
+ list.Add(7);
+ Assert.AreEqual(4, list.RemoveFirst());
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4, 5, 7));
+
+ list.FIFO = true;
+ list.Clear();
+ list.Add(4); list.Add(4); list.Add(5); list.Add(4); list.Add(6);
+ Assert.IsFalse(list.Remove(2));
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(list.Remove(4));
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4, 5, 4, 6));
+ Assert.AreEqual(6, list.RemoveLast());
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4, 5, 4));
+ list.Add(7);
+ Assert.AreEqual(4, list.RemoveFirst());
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 5, 4, 7));
+ }
+
+
+ [Test]
+ public void Clear()
+ {
+ list.Add(7); list.Add(7);
+ list.Clear();
+ Assert.IsTrue(list.IsEmpty);
+ }
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+ }
+ }
+
+
+
+
+ namespace Indexed
+ {
+ [TestFixture]
+ public class Searching
+ {
+ private IIndexed<int> dit;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new ArrayList<int>();
+ }
+
+
+ [Test]
+ public void IndexOf()
+ {
+ Assert.AreEqual(~0, dit.IndexOf(6));
+ dit.Add(7);
+ Assert.AreEqual(~1, dit.IndexOf(6));
+ Assert.AreEqual(~1, dit.LastIndexOf(6));
+ Assert.AreEqual(0, dit.IndexOf(7));
+ dit.Add(5); dit.Add(7); dit.Add(8); dit.Add(7);
+ Assert.AreEqual(~5, dit.IndexOf(6));
+ Assert.AreEqual(0, dit.IndexOf(7));
+ Assert.AreEqual(4, dit.LastIndexOf(7));
+ Assert.AreEqual(3, dit.IndexOf(8));
+ Assert.AreEqual(1, dit.LastIndexOf(5));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class Removing
+ {
+ private IIndexed<int> dit;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new ArrayList<int>();
+ }
+
+
+ [Test]
+ public void RemoveAt()
+ {
+ dit.Add(5); dit.Add(7); dit.Add(9); dit.Add(1); dit.Add(2);
+ Assert.AreEqual(7, dit.RemoveAt(1));
+ Assert.IsTrue(((ArrayList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 5, 9, 1, 2));
+ Assert.AreEqual(5, dit.RemoveAt(0));
+ Assert.IsTrue(((ArrayList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 9, 1, 2));
+ Assert.AreEqual(2, dit.RemoveAt(2));
+ Assert.IsTrue(((ArrayList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 9, 1));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void RemoveAtBad0()
+ {
+ dit.RemoveAt(0);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void RemoveAtBadM1()
+ {
+ dit.RemoveAt(-1);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void RemoveAtBad1()
+ {
+ dit.Add(8);
+ dit.RemoveAt(1);
+ }
+
+
+ [Test]
+ public void RemoveInterval()
+ {
+ dit.RemoveInterval(0, 0);
+ dit.Add(10); dit.Add(20); dit.Add(30); dit.Add(40); dit.Add(50); dit.Add(60);
+ dit.RemoveInterval(3, 0);
+ Assert.IsTrue(((ArrayList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 10, 20, 30, 40, 50, 60));
+ dit.RemoveInterval(3, 1);
+ Assert.IsTrue(((ArrayList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 10, 20, 30, 50, 60));
+ dit.RemoveInterval(1, 3);
+ Assert.IsTrue(((ArrayList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 10, 60));
+ dit.RemoveInterval(0, 2);
+ Assert.IsTrue(((ArrayList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit));
+ dit.Add(10); dit.Add(20); dit.Add(30); dit.Add(40); dit.Add(50); dit.Add(60);
+ dit.RemoveInterval(0, 2);
+ Assert.IsTrue(((ArrayList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 30, 40, 50, 60));
+ dit.RemoveInterval(2, 2);
+ Assert.IsTrue(((ArrayList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 30, 40));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = null;
+ }
+ }
+ }
+
+
+
+
+ namespace List
+ {
+ [TestFixture]
+ public class Searching
+ {
+ private IList<int> lst;
+
+
+ [SetUp]
+ public void Init() { lst = new ArrayList<int>(); }
+
+
+ [TearDown]
+ public void Dispose() { lst = null; }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void FirstBad()
+ {
+ int f = lst.First;
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void LastBad()
+ {
+ int f = lst.Last;
+ }
+
+
+ [Test]
+ public void FirstLast()
+ {
+ lst.Add(19);
+ Assert.AreEqual(19, lst.First);
+ Assert.AreEqual(19, lst.Last);
+ lst.Add(34); lst.InsertFirst(12);
+ Assert.AreEqual(12, lst.First);
+ Assert.AreEqual(34, lst.Last);
+ }
+
+
+ [Test]
+ public void This()
+ {
+ lst.Add(34);
+ Assert.AreEqual(34, lst[0]);
+ lst[0] = 56;
+ Assert.AreEqual(56, lst.First);
+ lst.Add(7); lst.Add(7); lst.Add(7); lst.Add(7);
+ lst[0] = 45; lst[2] = 78; lst[4] = 101;
+ Assert.IsTrue(IC.eq(lst, 45, 7, 78, 7, 101));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void ThisBadEmptyGet()
+ {
+ int f = lst[0];
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void ThisBadLowGet()
+ {
+ lst.Add(7);
+
+ int f = lst[-1];
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void ThisBadHiGet()
+ {
+ lst.Add(6);
+
+ int f = lst[1];
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void ThisBadEmptySet()
+ {
+ lst[0] = 4;
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void ThisBadLowSet()
+ {
+ lst.Add(7);
+ lst[-1] = 9;
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void ThisBadHiSet()
+ {
+ lst.Add(6);
+ lst[1] = 11;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class Inserting
+ {
+ private IList<int> lst;
+
+
+ [SetUp]
+ public void Init() { lst = new ArrayList<int>(); }
+
+
+ [TearDown]
+ public void Dispose() { lst = null; }
+
+
+ [Test]
+ public void Insert()
+ {
+ lst.Insert(0, 5);
+ Assert.IsTrue(IC.eq(lst, 5));
+ lst.Insert(0, 7);
+ Assert.IsTrue(IC.eq(lst, 7, 5));
+ lst.Insert(1, 4);
+ Assert.IsTrue(IC.eq(lst, 7, 4, 5));
+ lst.Insert(3, 2);
+ Assert.IsTrue(IC.eq(lst, 7, 4, 5, 2));
+ }
+
+ [Test]
+ public void InsertDuplicate()
+ {
+ lst.Insert(0, 5);
+ Assert.IsTrue(IC.eq(lst, 5));
+ lst.Insert(0, 7);
+ Assert.IsTrue(IC.eq(lst, 7, 5));
+ lst.Insert(1, 5);
+ Assert.IsTrue(IC.eq(lst, 7, 5, 5));
+ }
+
+
+ [Test]
+ public void InsertAllDuplicate1()
+ {
+ lst.Insert(0, 3);
+ Assert.IsTrue(IC.eq(lst, 3));
+ lst.Insert(0, 7);
+ Assert.IsTrue(IC.eq(lst, 7, 3));
+ lst.InsertAll<int>(1, new int[] { 1, 2, 3, 4 });
+ Assert.IsTrue(IC.eq(lst, 7, 1, 2, 3, 4, 3));
+ Assert.IsTrue(lst.Check());
+ }
+ [Test]
+ public void InsertAllDuplicate2()
+ {
+ lst.Insert(0, 3);
+ Assert.IsTrue(IC.eq(lst, 3));
+ lst.Insert(0, 7);
+ Assert.IsTrue(IC.eq(lst, 7, 3));
+ lst.InsertAll<int>(1, new int[] { 5, 6, 5, 8 });
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 5, 6, 5, 8, 3));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void BadInsertLow()
+ {
+ lst.Add(7);
+ lst.Insert(-1, 9);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void BadInsertHi()
+ {
+ lst.Add(6);
+ lst.Insert(2, 11);
+ }
+
+
+ [Test]
+ public void FIFO()
+ {
+ for (int i = 0; i < 7; i++)
+ lst.Add(2 * i);
+
+ Assert.IsFalse(lst.FIFO);
+ Assert.AreEqual(12, lst.Remove());
+ Assert.AreEqual(10, lst.Remove());
+ lst.FIFO = true;
+ Assert.AreEqual(0, lst.Remove());
+ Assert.AreEqual(2, lst.Remove());
+ lst.FIFO = false;
+ Assert.AreEqual(8, lst.Remove());
+ Assert.AreEqual(6, lst.Remove());
+ }
+
+
+ [Test]
+ public void InsertFirstLast()
+ {
+ lst.InsertFirst(4);
+ lst.InsertLast(5);
+ lst.InsertFirst(14);
+ lst.InsertLast(15);
+ lst.InsertFirst(24);
+ lst.InsertLast(25);
+ lst.InsertFirst(34);
+ lst.InsertLast(55);
+ Assert.IsTrue(IC.eq(lst, 34, 24, 14, 4, 5, 15, 25, 55));
+ }
+
+
+ [Test]
+ public void InsertFirst()
+ {
+ lst.Add(2);
+ lst.Add(3);
+ lst.Add(2);
+ lst.Add(5);
+ lst.ViewOf(2).InsertFirst(7);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 2, 3, 2, 5));
+ lst.ViewOf(3).InsertFirst(8);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 2, 8, 3, 2, 5));
+ lst.ViewOf(5).InsertFirst(9);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 2, 8, 3, 2, 9, 5));
+ }
+
+ [Test]
+ public void InsertAfter()
+ {
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ lst.Add(2);
+ lst.Add(5);
+ lst.LastViewOf(2).InsertLast(7);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 1, 2, 3, 2, 7, 5));
+ lst.LastViewOf(1).InsertLast(8);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 1, 8, 2, 3, 2, 7, 5));
+ lst.LastViewOf(5).InsertLast(9);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 1, 8, 2, 3, 2, 7, 5, 9));
+ }
+
+ [Test]
+ public void InsertAll()
+ {
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ lst.Add(4);
+
+ IList<int> lst2 = new ArrayList<int>();
+
+ lst2.Add(7); lst2.Add(8); lst2.Add(9);
+ lst.InsertAll(0, lst2);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 8, 9, 1, 2, 3, 4));
+ lst.InsertAll(7, lst2);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 8, 9, 1, 2, 3, 4, 7, 8, 9));
+ lst.InsertAll(5, lst2);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 8, 9, 1, 2, 7, 8, 9, 3, 4, 7, 8, 9));
+ }
+
+
+ [Test]
+ public void Map()
+ {
+ Fun<int, string> m = delegate(int i) { return "<<" + i + ">>"; };
+ IList<string> r = lst.Map(m);
+
+ Assert.IsTrue(r.Check());
+ Assert.IsTrue(r.IsEmpty);
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ lst.Add(4);
+ r = lst.Map(m);
+ Assert.IsTrue(r.Check());
+ Assert.AreEqual(4, r.Count);
+ for (int i = 0; i < 4; i++)
+ Assert.AreEqual("<<" + (i + 1) + ">>", r[i]);
+ }
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void BadMapper()
+ {
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ Fun<int, bool> m = delegate(int i) { if (i == 2) lst.Add(7); return true; };
+ lst.Map(m);
+ }
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void ModifyingFindAll()
+ {
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ Fun<int, bool> m = delegate(int i) { if (i == 2) lst.Add(7); return true; };
+ lst.FindAll(m);
+ }
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void BadMapperView()
+ {
+ lst = lst.View(0, 0);
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ Fun<int, bool> m = delegate(int i) { if (i == 2) lst.Add(7); return true; };
+ lst.Map(m);
+ }
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void ModifyingFindAllView()
+ {
+ lst = lst.View(0, 0);
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ Fun<int, bool> m = delegate(int i) { if (i == 2) lst.Add(7); return true; };
+ lst.FindAll(m);
+ }
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void BadRemove() { lst.Remove(); }
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void BadRemoveFirst() { lst.RemoveFirst(); }
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void BadRemoveLast() { lst.RemoveLast(); }
+
+
+ [Test]
+ public void RemoveFirstLast()
+ {
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ lst.Add(4);
+ Assert.AreEqual(1, lst.RemoveFirst());
+ Assert.AreEqual(4, lst.RemoveLast());
+ Assert.AreEqual(2, lst.RemoveFirst());
+ Assert.AreEqual(3, lst.RemoveLast());
+ Assert.IsTrue(lst.IsEmpty);
+ }
+
+
+ [Test]
+ public void Reverse()
+ {
+ for (int i = 0; i < 10; i++)
+ lst.Add(i);
+
+ lst.Reverse();
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0));
+ lst.View(0, 3).Reverse();
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 8, 9, 6, 5, 4, 3, 2, 1, 0));
+ lst.View(7, 0).Reverse();
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 8, 9, 6, 5, 4, 3, 2, 1, 0));
+ lst.View(7, 3).Reverse();
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 8, 9, 6, 5, 4, 3, 0, 1, 2));
+ lst.View(5, 1).Reverse();
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 8, 9, 6, 5, 4, 3, 0, 1, 2));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void BadReverse()
+ {
+ for (int i = 0; i < 10; i++)
+ lst.Add(i);
+
+ lst.View(8, 3).Reverse();
+ }
+ }
+
+ [TestFixture]
+ public class Combined
+ {
+ private IList<KeyValuePair<int, int>> lst;
+
+
+ [SetUp]
+ public void Init()
+ {
+ lst = new ArrayList<KeyValuePair<int, int>>(new KeyValuePairEqualityComparer<int, int>());
+ for (int i = 0; i < 10; i++)
+ lst.Add(new KeyValuePair<int, int>(i, i + 30));
+ }
+
+
+ [TearDown]
+ public void Dispose() { lst = null; }
+
+
+ [Test]
+ public void Find()
+ {
+ KeyValuePair<int, int> p = new KeyValuePair<int, int>(3, 78);
+ Assert.IsTrue(lst.Find(ref p));
+ Assert.AreEqual(3, p.Key);
+ Assert.AreEqual(33, p.Value);
+ p = new KeyValuePair<int, int>(13, 78);
+ Assert.IsFalse(lst.Find(ref p));
+ }
+
+
+ [Test]
+ public void FindOrAdd()
+ {
+ KeyValuePair<int, int> p = new KeyValuePair<int, int>(3, 78);
+
+ Assert.IsTrue(lst.FindOrAdd(ref p));
+ Assert.AreEqual(3, p.Key);
+ Assert.AreEqual(33, p.Value);
+ p = new KeyValuePair<int, int>(13, 79);
+ Assert.IsFalse(lst.FindOrAdd(ref p));
+ Assert.AreEqual(13, lst[10].Key);
+ Assert.AreEqual(79, lst[10].Value);
+ }
+
+
+ [Test]
+ public void Update()
+ {
+ KeyValuePair<int, int> p = new KeyValuePair<int, int>(3, 78);
+
+ Assert.IsTrue(lst.Update(p));
+ Assert.AreEqual(3, lst[3].Key);
+ Assert.AreEqual(78, lst[3].Value);
+ p = new KeyValuePair<int, int>(13, 78);
+ Assert.IsFalse(lst.Update(p));
+ }
+
+
+ [Test]
+ public void UpdateOrAdd()
+ {
+ KeyValuePair<int, int> p = new KeyValuePair<int, int>(3, 78);
+
+ Assert.IsTrue(lst.UpdateOrAdd(p));
+ Assert.AreEqual(3, lst[3].Key);
+ Assert.AreEqual(78, lst[3].Value);
+ p = new KeyValuePair<int, int>(13, 79);
+ Assert.IsFalse(lst.UpdateOrAdd(p));
+ Assert.AreEqual(13, lst[10].Key);
+ Assert.AreEqual(79, lst[10].Value);
+ }
+
+
+ [Test]
+ public void RemoveWithReturn()
+ {
+ KeyValuePair<int, int> p = new KeyValuePair<int, int>(3, 78);
+
+ Assert.IsTrue(lst.Remove(p, out p));
+ Assert.AreEqual(3, p.Key);
+ Assert.AreEqual(33, p.Value);
+ Assert.AreEqual(4, lst[3].Key);
+ Assert.AreEqual(34, lst[3].Value);
+ p = new KeyValuePair<int, int>(13, 78);
+ Assert.IsFalse(lst.Remove(p, out p));
+ }
+ }
+
+
+ [TestFixture]
+ public class SortingTests
+ {
+ private IList<int> lst;
+
+
+ [SetUp]
+ public void Init() { lst = new ArrayList<int>(); }
+
+
+ [TearDown]
+ public void Dispose() { lst = null; }
+
+
+ [Test]
+ public void Sort()
+ {
+ lst.Add(5); lst.Add(6); lst.Add(5); lst.Add(7); lst.Add(3);
+ Assert.IsFalse(lst.IsSorted(new IC()));
+ lst.Sort(new IC());
+ Assert.IsTrue(lst.IsSorted());
+ Assert.IsTrue(lst.IsSorted(new IC()));
+ Assert.IsTrue(IC.eq(lst, 3, 5, 5, 6, 7));
+ }
+
+
+ [Test]
+ public void Stability()
+ {
+ IList<KeyValuePair<int, string>> lst2 = new ArrayList<KeyValuePair<int, string>>();
+ SCG.IComparer<KeyValuePair<int, string>> c = new KeyValuePairComparer<int, string>(new IC());
+
+ lst2.Add(new KeyValuePair<int, string>(5, "a"));
+ lst2.Add(new KeyValuePair<int, string>(5, "b"));
+ lst2.Add(new KeyValuePair<int, string>(6, "c"));
+ lst2.Add(new KeyValuePair<int, string>(4, "d"));
+ lst2.Add(new KeyValuePair<int, string>(3, "e"));
+ lst2.Add(new KeyValuePair<int, string>(4, "f"));
+ lst2.Add(new KeyValuePair<int, string>(5, "handle"));
+ Assert.IsFalse(lst2.IsSorted(c));
+ lst2.Sort(c);
+ Assert.IsTrue(lst2.IsSorted(c));
+
+ KeyValuePair<int, string> p = lst2.RemoveFirst();
+
+ Assert.AreEqual(3, p.Key);
+ Assert.AreEqual("e", p.Value);
+ p = lst2.RemoveFirst();
+ Assert.AreEqual(4, p.Key);
+ Assert.AreEqual("d", p.Value);
+ p = lst2.RemoveFirst();
+ Assert.AreEqual(4, p.Key);
+ Assert.AreEqual("f", p.Value);
+ p = lst2.RemoveFirst();
+ Assert.AreEqual(5, p.Key);
+ Assert.AreEqual("a", p.Value);
+ p = lst2.RemoveFirst();
+ Assert.AreEqual(5, p.Key);
+ Assert.AreEqual("b", p.Value);
+ p = lst2.RemoveFirst();
+ Assert.AreEqual(5, p.Key);
+ Assert.AreEqual("handle", p.Value);
+ p = lst2.RemoveFirst();
+ Assert.AreEqual(6, p.Key);
+ Assert.AreEqual("c", p.Value);
+ Assert.IsTrue(lst2.IsEmpty);
+ }
+ }
+
+ [TestFixture]
+ public class ShuffleTests
+ {
+ private IList<int> lst;
+
+
+ [SetUp]
+ public void Init() { lst = new ArrayList<int>(); }
+
+
+ [TearDown]
+ public void Dispose() { lst = null; }
+
+
+ [Test]
+ public void Shuffle()
+ {
+ lst.Add(5); lst.Add(6); lst.Add(5); lst.Add(7); lst.Add(3);
+ for (int i = 0; i < 100; i++)
+ {
+ lst.Shuffle(new C5Random(i + 1));
+ Assert.IsTrue(lst.Check(), "Check " + i);
+ int[] lst2 = lst.ToArray();
+ Sorting.IntroSort<int>(lst2);
+ Assert.IsTrue(IC.eq(lst2, 3, 5, 5, 6, 7), "Contents " + i);
+ }
+ }
+ }
+
+ }
+
+
+ namespace IStackQueue
+ {
+ [TestFixture]
+ public class Stack
+ {
+ private IStack<int> list;
+
+
+ [SetUp]
+ public void Init() { list = new ArrayList<int>(); }
+
+
+ [Test]
+ public void Normal()
+ {
+ list.Push(7);
+ list.Push(5);
+ list.Push(7);
+ list.Push(8);
+ list.Push(9);
+ Assert.AreEqual(9, list.Pop());
+ Assert.AreEqual(8, list.Pop());
+ Assert.AreEqual(7, list.Pop());
+ Assert.AreEqual(5, list.Pop());
+ Assert.AreEqual(7, list.Pop());
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void PopEmpty()
+ {
+ list.Push(5);
+ Assert.AreEqual(5, list.Pop());
+ list.Pop();
+ }
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+ }
+ [TestFixture]
+ public class Queue
+ {
+ private IQueue<int> list;
+
+
+ [SetUp]
+ public void Init() { list = new ArrayList<int>(); }
+
+
+ [Test]
+ public void Normal()
+ {
+ list.Enqueue(7);
+ list.Enqueue(5);
+ list.Enqueue(7);
+ list.Enqueue(8);
+ list.Enqueue(9);
+ Assert.AreEqual(7, list.Dequeue());
+ Assert.AreEqual(5, list.Dequeue());
+ Assert.AreEqual(7, list.Dequeue());
+ Assert.AreEqual(8, list.Dequeue());
+ Assert.AreEqual(9, list.Dequeue());
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void DeQueueEmpty()
+ {
+ list.Enqueue(5);
+ Assert.AreEqual(5, list.Dequeue());
+ list.Dequeue();
+ }
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+ }
+ }
+
+
+ namespace Range
+ {
+ [TestFixture]
+ public class Range
+ {
+ private IList<int> lst;
+
+
+ [SetUp]
+ public void Init() { lst = new ArrayList<int>(); }
+
+
+ [TearDown]
+ public void Dispose() { lst = null; }
+
+
+ [Test]
+ public void GetRange()
+ {
+ //Assert.IsTrue(IC.eq(lst[0, 0)));
+ for (int i = 0; i < 10; i++) lst.Add(i);
+
+ Assert.IsTrue(IC.eq(lst[0, 3], 0, 1, 2));
+ Assert.IsTrue(IC.eq(lst[3, 4], 3, 4, 5, 6));
+ Assert.IsTrue(IC.eq(lst[6, 4], 6, 7, 8, 9));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void BadGetRange()
+ {
+ object foo = lst[0, 11];
+ }
+
+
+ [Test]
+ public void Backwards()
+ {
+ for (int i = 0; i < 10; i++) lst.Add(i);
+
+ Assert.IsTrue(IC.eq(lst.Backwards(), 9, 8, 7, 6, 5, 4, 3, 2, 1, 0));
+ Assert.IsTrue(IC.eq(lst[0, 4].Backwards(), 3, 2, 1, 0));
+ Assert.IsTrue(IC.eq(lst[3, 4].Backwards(), 6, 5, 4, 3));
+ Assert.IsTrue(IC.eq(lst[6, 4].Backwards(), 9, 8, 7, 6));
+ }
+
+
+ [Test]
+ public void DirectionAndCount()
+ {
+ for (int i = 0; i < 10; i++) lst.Add(i);
+
+ Assert.AreEqual(EnumerationDirection.Forwards, lst.Direction);
+ Assert.AreEqual(EnumerationDirection.Forwards, lst[3, 4].Direction);
+ Assert.AreEqual(EnumerationDirection.Backwards, lst[3, 4].Backwards().Direction);
+ Assert.AreEqual(EnumerationDirection.Backwards, lst.Backwards().Direction);
+ Assert.AreEqual(4, lst[3, 4].Count);
+ Assert.AreEqual(4, lst[3, 4].Backwards().Count);
+ Assert.AreEqual(10, lst.Backwards().Count);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void MoveNextAfterUpdate()
+ {
+ for (int i = 0; i < 10; i++) lst.Add(i);
+
+ foreach (int i in lst)
+ {
+ lst.Add(45 + i);
+ }
+ }
+ }
+ }
+
+
+
+
+ namespace View
+ {
+ [TestFixture]
+ public class Simple
+ {
+ ArrayList<int> list, view;
+
+
+ [SetUp]
+ public void Init()
+ {
+ list = new ArrayList<int>();
+ list.Add(0); list.Add(1); list.Add(2); list.Add(3);
+ view = (ArrayList<int>)list.View(1, 2);
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ list = view = null;
+ }
+
+
+ void check()
+ {
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(view.Check());
+ }
+
+
+ //static void pint(IEnumerable<int> l) { foreach (int cell in l) Console.WriteLine(cell); }
+
+ [Test]
+ public void InsertPointer()
+ {
+ IList<int> view2 = list.View(2, 0);
+ list.Insert(view2, 7);
+ check();
+ list.Insert(list, 8);
+ check();
+ view.Insert(view2, 9);
+ check();
+ view.Insert(list.View(3, 2), 10);
+ check();
+ view.Insert(list.ViewOf(0), 11);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 11, 1, 9, 7, 2, 10, 3, 8));
+ Assert.IsTrue(IC.eq(view, 11, 1, 9, 7, 2, 10));
+ }
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void InsertPointerBad1()
+ {
+ view.Insert(list.View(0, 0), 7);
+ }
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void InsertPointerBad2()
+ {
+ view.Insert(list, 7);
+ }
+
+ [Test]
+ [ExpectedException(typeof(IncompatibleViewException))]
+ public void InsertPointerBad3()
+ {
+ list.Insert(new ArrayList<int>(), 7);
+ }
+
+ [Test]
+ [ExpectedException(typeof(IncompatibleViewException))]
+ public void InsertPointerBad4()
+ {
+ list.Insert(new ArrayList<int>().View(0, 0), 7);
+ }
+
+
+ [Test]
+ public void Span()
+ {
+ IList<int> span = list.View(1, 0).Span(list.View(2, 0));
+ Assert.IsTrue(span.Check());
+ Assert.AreEqual(1, span.Offset);
+ Assert.AreEqual(1, span.Count);
+ span = list.View(0, 2).Span(list.View(2, 2));
+ Assert.IsTrue(span.Check());
+ Assert.AreEqual(0, span.Offset);
+ Assert.AreEqual(4, span.Count);
+ span = list.View(3, 1).Span(list.View(1, 1));
+ Assert.IsNull(span);
+ }
+
+ [Test]
+ public void ViewOf()
+ {
+ for (int i = 0; i < 4; i++)
+ list.Add(i);
+ IList<int> v = view.ViewOf(2);
+ Assert.IsTrue(v.Check());
+ Assert.IsTrue(IC.eq(v, 2));
+ Assert.AreEqual(2, v.Offset);
+ v = list.ViewOf(2);
+ Assert.IsTrue(v.Check());
+ Assert.IsTrue(IC.eq(v, 2));
+ Assert.AreEqual(2, v.Offset);
+ v = list.LastViewOf(2);
+ Assert.IsTrue(v.Check());
+ Assert.IsTrue(IC.eq(v, 2));
+ Assert.AreEqual(6, v.Offset);
+ }
+
+ [Test]
+ public void ArrayStuff()
+ {
+ Assert.IsTrue(IC.eq(view.ToArray(), 1, 2));
+ int[] extarray = new int[5];
+ view.CopyTo(extarray, 2);
+ Assert.IsTrue(IC.eq(extarray, 0, 0, 1, 2, 0));
+ }
+
+ [Test]
+ public void BadViewOf()
+ {
+ Assert.IsNull(view.ViewOf(5));
+ Assert.IsNull(view.LastViewOf(5));
+ Assert.IsNull(view.ViewOf(3));
+ Assert.IsNull(view.LastViewOf(3));
+ Assert.IsNull(view.ViewOf(0));
+ Assert.IsNull(view.LastViewOf(0));
+ }
+
+ [Test]
+ public void Add()
+ {
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 1, 2, 3));
+ Assert.IsTrue(IC.eq(view, 1, 2));
+ view.InsertFirst(10);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 10, 1, 2, 3));
+ Assert.IsTrue(IC.eq(view, 10, 1, 2));
+ view.Clear();
+ Assert.IsFalse(view.IsReadOnly);
+ Assert.IsTrue(view.AllowsDuplicates);
+ Assert.IsTrue(view.IsEmpty);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 3));
+ Assert.IsTrue(IC.eq(view));
+ view.Add(8);
+ Assert.IsFalse(view.IsEmpty);
+ Assert.IsTrue(view.AllowsDuplicates);
+ Assert.IsFalse(view.IsReadOnly);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 8, 3));
+ Assert.IsTrue(IC.eq(view, 8));
+ view.Add(12);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 8, 12, 3));
+ Assert.IsTrue(IC.eq(view, 8, 12));
+ view./*ViewOf(12)*/InsertLast(15);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 8, 12, 15, 3));
+ Assert.IsTrue(IC.eq(view, 8, 12, 15));
+ view.ViewOf(12).InsertFirst(18);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 8, 18, 12, 15, 3));
+ Assert.IsTrue(IC.eq(view, 8, 18, 12, 15));
+
+ ArrayList<int> lst2 = new ArrayList<int>();
+
+ lst2.Add(90); lst2.Add(92);
+ view.AddAll(lst2);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 8, 18, 12, 15, 90, 92, 3));
+ Assert.IsTrue(IC.eq(view, 8, 18, 12, 15, 90, 92));
+ view.InsertLast(66);
+ check();
+
+ Assert.IsTrue(IC.eq(list, 0, 8, 18, 12, 15, 90, 92, 66, 3));
+ Assert.IsTrue(IC.eq(view, 8, 18, 12, 15, 90, 92, 66));
+ }
+
+
+ [Test]
+ public void Bxxx()
+ {
+ Assert.IsTrue(IC.eq(view.Backwards(), 2, 1));
+ Assert.AreSame(list, view.Underlying);
+ Assert.IsNull(list.Underlying);
+ Assert.AreEqual(EnumerationDirection.Forwards, view.Direction);
+ Assert.AreEqual(EnumerationDirection.Backwards, view.Backwards().Direction);
+ Assert.AreEqual(0, list.Offset);
+ Assert.AreEqual(1, view.Offset);
+ }
+
+
+ [Test]
+ public void Contains()
+ {
+ Assert.IsTrue(view.Contains(1));
+ Assert.IsFalse(view.Contains(0));
+
+ ArrayList<int> lst2 = new ArrayList<int>();
+
+ lst2.Add(2);
+ Assert.IsTrue(view.ContainsAll(lst2));
+ lst2.Add(3);
+ Assert.IsFalse(view.ContainsAll(lst2));
+ Assert.AreEqual(Speed.Linear, view.ContainsSpeed);
+ Assert.AreEqual(2, view.Count);
+ view.Add(1);
+ Assert.AreEqual(1, view.ContainsCount(2));
+ Assert.AreEqual(2, view.ContainsCount(1));
+ Assert.AreEqual(3, view.Count);
+ }
+
+
+ [Test]
+ public void CreateView()
+ {
+ ArrayList<int> view2 = (ArrayList<int>)view.View(1, 0);
+
+ Assert.AreSame(list, view2.Underlying);
+ }
+
+
+ [Test]
+ public void FIFO()
+ {
+ Assert.IsFalse(view.FIFO);
+ view.FIFO = true;
+ view.Add(23); view.Add(24); view.Add(25);
+ check();
+ Assert.IsTrue(IC.eq(view, 1, 2, 23, 24, 25));
+ Assert.AreEqual(1, view.Remove());
+ check();
+ Assert.IsTrue(IC.eq(view, 2, 23, 24, 25));
+ view.FIFO = false;
+ Assert.IsFalse(view.FIFO);
+ Assert.AreEqual(25, view.Remove());
+ check();
+ Assert.IsTrue(IC.eq(view, 2, 23, 24));
+ }
+
+
+ [Test]
+ public void MapEtc()
+ {
+ ArrayList<double> dbl = (ArrayList<double>)view.Map(new Fun<int, double>(delegate(int i) { return i / 10.0; }));
+
+ Assert.IsTrue(dbl.Check());
+ Assert.AreEqual(0.1, dbl[0]);
+ Assert.AreEqual(0.2, dbl[1]);
+ for (int i = 0; i < 10; i++) view.Add(i);
+
+ list = (ArrayList<int>)view.FindAll(new Fun<int, bool>(delegate(int i) { return i % 4 == 1; }));
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 1, 1, 5, 9));
+ }
+
+
+ [Test]
+ public void FL()
+ {
+ Assert.AreEqual(1, view.First);
+ Assert.AreEqual(2, view.Last);
+ }
+
+
+ [Test]
+ public void Indexing()
+ {
+ list.Clear();
+ for (int i = 0; i < 20; i++) list.Add(i);
+
+ view = (ArrayList<int>)list.View(5, 7);
+ for (int i = 0; i < 7; i++) Assert.AreEqual(i + 5, view[i]);
+
+ for (int i = 0; i < 7; i++) Assert.AreEqual(i, view.IndexOf(i + 5));
+
+ for (int i = 0; i < 7; i++) Assert.AreEqual(i, view.LastIndexOf(i + 5));
+ }
+
+
+ [Test]
+ public void Insert()
+ {
+ view.Insert(0, 34);
+ view.Insert(1, 35);
+ view.Insert(4, 36);
+ Assert.IsTrue(view.Check());
+ Assert.IsTrue(IC.eq(view, 34, 35, 1, 2, 36));
+
+ IList<int> list2 = new ArrayList<int>();
+
+ list2.AddAll(view);
+ view.InsertAll(3, list2);
+ Assert.IsTrue(view.Check());
+ Assert.IsTrue(IC.eq(view, 34, 35, 1, 34, 35, 1, 2, 36, 2, 36));
+ }
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void RangeCheck1()
+ {
+ IList<int> lst = new ArrayList<int>();
+ lst.Add(2);
+ lst = lst.View(1, 1);
+ }
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void RangeCheck2()
+ {
+ IList<int> lst = new ArrayList<int>();
+ lst.Add(2);
+ lst = lst.View(1, -1);
+ }
+
+
+ [Test]
+ public void Sort()
+ {
+ view.Add(45); view.Add(47); view.Add(46); view.Add(48);
+ Assert.IsFalse(view.IsSorted(new IC()));
+ view.Sort(new IC());
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 1, 2, 45, 46, 47, 48, 3));
+ Assert.IsTrue(IC.eq(view, 1, 2, 45, 46, 47, 48));
+ }
+
+
+ [Test]
+ public void Remove()
+ {
+ view.Add(1); view.Add(5); view.Add(3); view.Add(1); view.Add(3); view.Add(0);
+ Assert.IsTrue(IC.eq(view, 1, 2, 1, 5, 3, 1, 3, 0));
+ Assert.IsTrue(view.Remove(1));
+ check();
+ Assert.IsTrue(IC.eq(view, 1, 2, 1, 5, 3, 3, 0));
+ Assert.IsTrue(view.Remove(1));
+ check();
+ Assert.IsTrue(IC.eq(view, 1, 2, 5, 3, 3, 0));
+ Assert.IsTrue(view.Remove(0));
+ check();
+ Assert.IsTrue(IC.eq(view, 1, 2, 5, 3, 3));
+ view.RemoveAllCopies(3);
+ check();
+ Assert.IsTrue(IC.eq(view, 1, 2, 5));
+ Assert.IsTrue(IC.eq(list, 0, 1, 2, 5, 3));
+ view.Add(1); view.Add(5); view.Add(3); view.Add(1); view.Add(3); view.Add(0);
+ Assert.IsTrue(IC.eq(view, 1, 2, 5, 1, 5, 3, 1, 3, 0));
+
+ view.FIFO = true;
+ view.Clear(); view.Add(1); view.Add(2);
+
+ view.Add(1); view.Add(5); view.Add(3); view.Add(1); view.Add(3); view.Add(0);
+ Assert.IsTrue(IC.eq(view, 1, 2, 1, 5, 3, 1, 3, 0));
+ Assert.IsTrue(view.Remove(1));
+ check();
+ Assert.IsTrue(IC.eq(view, 2, 1, 5, 3, 1, 3, 0));
+ Assert.IsTrue(view.Remove(1));
+ check();
+ Assert.IsTrue(IC.eq(view, 2, 5, 3, 1, 3, 0));
+ Assert.IsTrue(view.Remove(0));
+ check();
+ Assert.IsTrue(IC.eq(view, 2, 5, 3, 1, 3));
+ view.RemoveAllCopies(3);
+ check();
+ Assert.IsTrue(IC.eq(view, 2, 5, 1));
+ Assert.IsTrue(IC.eq(list, 0, 2, 5, 1, 3));
+ view.Add(1); view.Add(5); view.Add(3); view.Add(1); view.Add(3); view.Add(0);
+ Assert.IsTrue(IC.eq(view, 2, 5, 1, 1, 5, 3, 1, 3, 0));
+
+ view.FIFO = false;
+
+ ArrayList<int> l2 = new ArrayList<int>();
+
+ l2.Add(1); l2.Add(2); l2.Add(2); l2.Add(3); l2.Add(1);
+ view.RemoveAll(l2);
+ check();
+ Assert.IsTrue(IC.eq(view, 5, 5, 1, 3, 0));
+ view.RetainAll(l2);
+ check();
+ Assert.IsTrue(IC.eq(view, 1, 3));
+ view.Add(2); view.Add(4); view.Add(5);
+ Assert.AreEqual(1, view.RemoveAt(0));
+ Assert.AreEqual(5, view.RemoveAt(3));
+ Assert.AreEqual(2, view.RemoveAt(1));
+ check();
+ Assert.IsTrue(IC.eq(view, 3, 4));
+ view.Add(8);
+ Assert.AreEqual(3, view.RemoveFirst());
+ Assert.AreEqual(8, view.RemoveLast());
+ view.Add(2); view.Add(5); view.Add(3); view.Add(1);
+ view.RemoveInterval(1, 2);
+ check();
+ Assert.IsTrue(IC.eq(view, 4, 3, 1));
+ }
+
+
+ [Test]
+ public void Reverse()
+ {
+ view.Clear();
+ for (int i = 0; i < 10; i++) view.Add(10 + i);
+
+ view.View(3, 4).Reverse();
+ check();
+ Assert.IsTrue(IC.eq(view, 10, 11, 12, 16, 15, 14, 13, 17, 18, 19));
+ view.Reverse();
+ Assert.IsTrue(IC.eq(view, 19, 18, 17, 13, 14, 15, 16, 12, 11, 10));
+ Assert.IsTrue(IC.eq(list, 0, 19, 18, 17, 13, 14, 15, 16, 12, 11, 10, 3));
+ }
+
+
+ [Test]
+ public void Slide()
+ {
+ view.Slide(1);
+ check();
+ Assert.IsTrue(IC.eq(view, 2, 3));
+ view.Slide(-2);
+ check();
+ Assert.IsTrue(IC.eq(view, 0, 1));
+ view.Slide(0, 3);
+ check();
+ Assert.IsTrue(IC.eq(view, 0, 1, 2));
+ view.Slide(2, 1);
+ check();
+ Assert.IsTrue(IC.eq(view, 2));
+ Assert.AreEqual(view, view.Slide(-1, 0));
+ check();
+ Assert.IsTrue(IC.eq(view));
+ view.Add(28);
+ Assert.IsTrue(IC.eq(list, 0, 28, 1, 2, 3));
+ }
+ [Test]
+ public void Iterate()
+ {
+ list.Clear();
+ view = null;
+ foreach (int i in new int[] { 2, 4, 8, 13, 6, 1, 2, 7 }) list.Add(i);
+
+ view = (ArrayList<int>)list.View(list.Count - 2, 2);
+ while (true)
+ {
+ if ((view.Last - view.First) % 2 == 1)
+ view.Insert(1, 666);
+ check();
+ if (view.Offset == 0)
+ break;
+ else
+ view.Slide(-1, 2);
+ }
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 2, 4, 8, 666, 13, 6, 1, 666, 2, 666, 7));
+ }
+
+
+ [Test]
+ public void SyncRoot()
+ {
+ Assert.AreSame(view.SyncRoot, list.SyncRoot);
+ }
+ }
+ [TestFixture]
+ public class MulipleViews
+ {
+ IList<int> list;
+ IList<int>[][] views;
+ [SetUp]
+ public void Init()
+ {
+ list = new ArrayList<int>();
+ for (int i = 0; i < 6; i++)
+ list.Add(i);
+ views = new IList<int>[7][];
+ for (int i = 0; i < 7; i++)
+ {
+ views[i] = new IList<int>[7 - i];
+ for (int j = 0; j < 7 - i; j++)
+ views[i][j] = list.View(i, j);
+ }
+ }
+ [TearDown]
+ public void Dispose()
+ {
+ list = null;
+ views = null;
+ }
+ [Test]
+ public void Insert()
+ {
+ Assert.IsTrue(list.Check(), "list check before insert");
+ list.Insert(3, 777);
+ Assert.IsTrue(list.Check(), "list check after insert");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i < 3 || (i == 3 && j == 0) ? i : i + 1, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(i < 3 && i + j > 3 ? j + 1 : j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+ [Test]
+ public void RemoveAt()
+ {
+ Assert.IsTrue(list.Check(), "list check before remove");
+ list.RemoveAt(3);
+ Assert.IsTrue(list.Check(), "list check after remove");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i <= 3 ? i : i - 1, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(i <= 3 && i + j > 3 ? j - 1 : j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+
+ [Test]
+ public void RemoveInterval()
+ {
+ Assert.IsTrue(list.Check(), "list check before remove");
+ list.RemoveInterval(3, 2);
+ Assert.IsTrue(list.Check(), "list check after remove");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i <= 3 ? i : i <= 5 ? 3 : i - 2, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(j == 0 ? 0 : i <= 3 && i + j > 4 ? j - 2 : i > 4 || i + j <= 3 ? j : j - 1, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+
+
+ [Test]
+ public void InsertAtEnd()
+ {
+ Assert.IsTrue(list.Check(), "list check before insert");
+ list.InsertLast(777);
+ Assert.IsTrue(list.Check(), "list check after insert");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+ [Test]
+ public void RemoveAtEnd()
+ {
+ Assert.IsTrue(list.Check(), "list check before remove");
+ list.RemoveAt(5);
+ Assert.IsTrue(list.Check(), "list check after remove");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i <= 5 ? i : i - 1, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(i <= 5 && i + j > 5 ? j - 1 : j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+ [Test]
+ public void InsertAtStart()
+ {
+ Assert.IsTrue(list.Check(), "list check before insert");
+ list.Insert(0, 777);
+ Assert.IsTrue(list.Check(), "list check after insert");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i == 0 && j == 0 ? 0 : i + 1, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+ [Test]
+ public void RemoveAtStart()
+ {
+ Assert.IsTrue(list.Check(), "list check before remove");
+ list.RemoveAt(0);
+ Assert.IsTrue(list.Check(), "list check after remove");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i == 0 ? i : i - 1, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(i == 0 && j > 0 ? j - 1 : j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+ [Test]
+ public void Clear()
+ {
+ Assert.IsTrue(list.Check(), "list check before clear");
+ views[2][3].Clear();
+ Assert.IsTrue(list.Check(), "list check after clear");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i < 2 ? i : i < 6 ? 2 : i - 3, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(s(i, j), views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+
+ private int s(int i, int j)
+ {
+ if (j == 0) return 0;
+ int k = i + j - 1; //end
+ if (i > 4 || k <= 1) return j;
+ if (i >= 2) return k > 4 ? k - 4 : 0;
+ if (i <= 2) return k >= 4 ? j - 3 : 2 - i;
+ return -1;
+ }
+ [Test]
+ public void InsertAll()
+ {
+ ArrayList<int> list2 = new ArrayList<int>();
+ for (int i = 0; i < 5; i++) { list2.Add(100 + i); }
+ Assert.IsTrue(list.Check(), "list check before insertAll");
+ list.InsertAll(3, list2);
+ Assert.IsTrue(list.Check(), "list check after insertAll");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i < 3 || (i == 3 && j == 0) ? i : i + 5, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(i < 3 && i + j > 3 ? j + 5 : j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+
+ [Test]
+ public void AddAll()
+ {
+ ArrayList<int> list2 = new ArrayList<int>();
+ for (int i = 0; i < 5; i++) { list2.Add(100 + i); }
+ Assert.IsTrue(list.Check(), "list check before AddAll");
+ list.View(1, 2).AddAll(list2);
+ Assert.IsTrue(list.Check(), "list check after AddAll");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i < 3 || (i == 3 && j == 0) ? i : i + 5, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(i < 3 && i + j > 3 ? j + 5 : j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+
+ [Test]
+ public void RemoveAll1()
+ {
+ ArrayList<int> list2 = new ArrayList<int>();
+ list2.Add(1); list2.Add(3); list2.Add(4);
+
+ for (int i = 0; i < 7; i++)
+ {
+ for (int j = 0; j < 7 - i; j++)
+ {
+ list = new ArrayList<int>();
+ for (int k = 0; k < 6; k++) list.Add(k);
+ ArrayList<int> v = (ArrayList<int>)list.View(i, j);
+ list.RemoveAll(list2);
+ Assert.IsTrue(list.Check(), "list check after RemoveAll, i=" + i + ", j=" + j);
+ }
+ }
+ }
+ [Test]
+ public void RemoveAll2()
+ {
+ ArrayList<int> list2 = new ArrayList<int>();
+ list2.Add(1); list2.Add(3); list2.Add(4);
+ Assert.IsTrue(list.Check(), "list check before RemoveAll");
+ list.RemoveAll(list2);
+
+ Assert.AreEqual(0, views[0][0].Offset, "view [0][0] offset");
+ Assert.AreEqual(0, views[0][1].Offset, "view [0][1] offset");
+ Assert.AreEqual(0, views[0][2].Offset, "view [0][2] offset");
+ Assert.AreEqual(0, views[0][3].Offset, "view [0][3] offset");
+ Assert.AreEqual(0, views[0][4].Offset, "view [0][4] offset");
+ Assert.AreEqual(0, views[0][5].Offset, "view [0][5] offset");
+ Assert.AreEqual(0, views[0][6].Offset, "view [0][6] offset");
+ Assert.AreEqual(1, views[1][0].Offset, "view [1][0] offset");
+ Assert.AreEqual(1, views[1][1].Offset, "view [1][1] offset");
+ Assert.AreEqual(1, views[1][2].Offset, "view [1][2] offset");
+ Assert.AreEqual(1, views[1][3].Offset, "view [1][3] offset");
+ Assert.AreEqual(1, views[1][4].Offset, "view [1][4] offset");
+ Assert.AreEqual(1, views[1][5].Offset, "view [1][5] offset");
+ Assert.AreEqual(1, views[2][0].Offset, "view [2][0] offset");
+ Assert.AreEqual(1, views[2][1].Offset, "view [2][1] offset");
+ Assert.AreEqual(1, views[2][2].Offset, "view [2][2] offset");
+ Assert.AreEqual(1, views[2][3].Offset, "view [2][3] offset");
+ Assert.AreEqual(1, views[2][4].Offset, "view [2][4] offset");
+ Assert.AreEqual(2, views[3][0].Offset, "view [3][0] offset");
+ Assert.AreEqual(2, views[3][1].Offset, "view [3][1] offset");
+ Assert.AreEqual(2, views[3][2].Offset, "view [3][2] offset");
+ Assert.AreEqual(2, views[3][3].Offset, "view [3][3] offset");
+ Assert.AreEqual(2, views[4][0].Offset, "view [4][0] offset");
+ Assert.AreEqual(2, views[4][1].Offset, "view [4][1] offset");
+ Assert.AreEqual(2, views[4][2].Offset, "view [4][2] offset");
+ Assert.AreEqual(2, views[5][0].Offset, "view [5][0] offset");
+ Assert.AreEqual(2, views[5][1].Offset, "view [5][1] offset");
+ Assert.AreEqual(3, views[6][0].Offset, "view [6][0] offset");
+
+ Assert.AreEqual(0, views[0][0].Count, "view [0][0] count");
+ Assert.AreEqual(1, views[0][1].Count, "view [0][1] count");
+ Assert.AreEqual(1, views[0][2].Count, "view [0][2] count");
+ Assert.AreEqual(2, views[0][3].Count, "view [0][3] count");
+ Assert.AreEqual(2, views[0][4].Count, "view [0][4] count");
+ Assert.AreEqual(2, views[0][5].Count, "view [0][5] count");
+ Assert.AreEqual(3, views[0][6].Count, "view [0][6] count");
+ Assert.AreEqual(0, views[1][0].Count, "view [1][0] count");
+ Assert.AreEqual(0, views[1][1].Count, "view [1][1] count");
+ Assert.AreEqual(1, views[1][2].Count, "view [1][2] count");
+ Assert.AreEqual(1, views[1][3].Count, "view [1][3] count");
+ Assert.AreEqual(1, views[1][4].Count, "view [1][4] count");
+ Assert.AreEqual(2, views[1][5].Count, "view [1][5] count");
+ Assert.AreEqual(0, views[2][0].Count, "view [2][0] count");
+ Assert.AreEqual(1, views[2][1].Count, "view [2][1] count");
+ Assert.AreEqual(1, views[2][2].Count, "view [2][2] count");
+ Assert.AreEqual(1, views[2][3].Count, "view [2][3] count");
+ Assert.AreEqual(2, views[2][4].Count, "view [2][4] count");
+ Assert.AreEqual(0, views[3][0].Count, "view [3][0] count");
+ Assert.AreEqual(0, views[3][1].Count, "view [3][1] count");
+ Assert.AreEqual(0, views[3][2].Count, "view [3][2] count");
+ Assert.AreEqual(1, views[3][3].Count, "view [3][3] count");
+ Assert.AreEqual(0, views[4][0].Count, "view [4][0] count");
+ Assert.AreEqual(0, views[4][1].Count, "view [4][1] count");
+ Assert.AreEqual(1, views[4][2].Count, "view [4][2] count");
+ Assert.AreEqual(0, views[5][0].Count, "view [5][0] count");
+ Assert.AreEqual(1, views[5][1].Count, "view [5][1] count");
+ Assert.AreEqual(0, views[6][0].Count, "view [6][0] count");
+
+ Assert.IsTrue(list.Check(), "list check after RemoveAll");
+ }
+
+ [Test]
+ public void RetainAll()
+ {
+ ArrayList<int> list2 = new ArrayList<int>();
+ list2.Add(2); list2.Add(4); list2.Add(5);
+ Assert.IsTrue(list.Check(), "list check before RetainAll");
+ list.RetainAll(list2);
+
+ Assert.AreEqual(0, views[0][0].Offset, "view [0][0] offset");
+ Assert.AreEqual(0, views[0][1].Offset, "view [0][1] offset");
+ Assert.AreEqual(0, views[0][2].Offset, "view [0][2] offset");
+ Assert.AreEqual(0, views[0][3].Offset, "view [0][3] offset");
+ Assert.AreEqual(0, views[0][4].Offset, "view [0][4] offset");
+ Assert.AreEqual(0, views[0][5].Offset, "view [0][5] offset");
+ Assert.AreEqual(0, views[0][6].Offset, "view [0][6] offset");
+ Assert.AreEqual(0, views[1][0].Offset, "view [1][0] offset");
+ Assert.AreEqual(0, views[1][1].Offset, "view [1][1] offset");
+ Assert.AreEqual(0, views[1][2].Offset, "view [1][2] offset");
+ Assert.AreEqual(0, views[1][3].Offset, "view [1][3] offset");
+ Assert.AreEqual(0, views[1][4].Offset, "view [1][4] offset");
+ Assert.AreEqual(0, views[1][5].Offset, "view [1][5] offset");
+ Assert.AreEqual(0, views[2][0].Offset, "view [2][0] offset");
+ Assert.AreEqual(0, views[2][1].Offset, "view [2][1] offset");
+ Assert.AreEqual(0, views[2][2].Offset, "view [2][2] offset");
+ Assert.AreEqual(0, views[2][3].Offset, "view [2][3] offset");
+ Assert.AreEqual(0, views[2][4].Offset, "view [2][4] offset");
+ Assert.AreEqual(1, views[3][0].Offset, "view [3][0] offset");
+ Assert.AreEqual(1, views[3][1].Offset, "view [3][1] offset");
+ Assert.AreEqual(1, views[3][2].Offset, "view [3][2] offset");
+ Assert.AreEqual(1, views[3][3].Offset, "view [3][3] offset");
+ Assert.AreEqual(1, views[4][0].Offset, "view [4][0] offset");
+ Assert.AreEqual(1, views[4][1].Offset, "view [4][1] offset");
+ Assert.AreEqual(1, views[4][2].Offset, "view [4][2] offset");
+ Assert.AreEqual(2, views[5][0].Offset, "view [5][0] offset");
+ Assert.AreEqual(2, views[5][1].Offset, "view [5][1] offset");
+ Assert.AreEqual(3, views[6][0].Offset, "view [6][0] offset");
+
+ Assert.AreEqual(0, views[0][0].Count, "view [0][0] count");
+ Assert.AreEqual(0, views[0][1].Count, "view [0][1] count");
+ Assert.AreEqual(0, views[0][2].Count, "view [0][2] count");
+ Assert.AreEqual(1, views[0][3].Count, "view [0][3] count");
+ Assert.AreEqual(1, views[0][4].Count, "view [0][4] count");
+ Assert.AreEqual(2, views[0][5].Count, "view [0][5] count");
+ Assert.AreEqual(3, views[0][6].Count, "view [0][6] count");
+ Assert.AreEqual(0, views[1][0].Count, "view [1][0] count");
+ Assert.AreEqual(0, views[1][1].Count, "view [1][1] count");
+ Assert.AreEqual(1, views[1][2].Count, "view [1][2] count");
+ Assert.AreEqual(1, views[1][3].Count, "view [1][3] count");
+ Assert.AreEqual(2, views[1][4].Count, "view [1][4] count");
+ Assert.AreEqual(3, views[1][5].Count, "view [1][5] count");
+ Assert.AreEqual(0, views[2][0].Count, "view [2][0] count");
+ Assert.AreEqual(1, views[2][1].Count, "view [2][1] count");
+ Assert.AreEqual(1, views[2][2].Count, "view [2][2] count");
+ Assert.AreEqual(2, views[2][3].Count, "view [2][3] count");
+ Assert.AreEqual(3, views[2][4].Count, "view [2][4] count");
+ Assert.AreEqual(0, views[3][0].Count, "view [3][0] count");
+ Assert.AreEqual(0, views[3][1].Count, "view [3][1] count");
+ Assert.AreEqual(1, views[3][2].Count, "view [3][2] count");
+ Assert.AreEqual(2, views[3][3].Count, "view [3][3] count");
+ Assert.AreEqual(0, views[4][0].Count, "view [4][0] count");
+ Assert.AreEqual(1, views[4][1].Count, "view [4][1] count");
+ Assert.AreEqual(2, views[4][2].Count, "view [4][2] count");
+ Assert.AreEqual(0, views[5][0].Count, "view [5][0] count");
+ Assert.AreEqual(1, views[5][1].Count, "view [5][1] count");
+ Assert.AreEqual(0, views[6][0].Count, "view [6][0] count");
+
+ Assert.IsTrue(list.Check(), "list check after RetainAll");
+ }
+
+ [Test]
+ public void RemoveAllCopies()
+ {
+ ArrayList<int> list2 = new ArrayList<int>();
+ list2.Add(0); list2.Add(2); list2.Add(2); list2.Add(2); list2.Add(5); list2.Add(2); list2.Add(1);
+ for (int i = 0; i < 7; i++)
+ {
+ for (int j = 0; j < 7 - i; j++)
+ {
+ list = new ArrayList<int>();
+ list.AddAll(list2);
+ ArrayList<int> v = (ArrayList<int>)list.View(i, j);
+ list.RemoveAllCopies(2);
+ Assert.AreEqual((i == 0 && j > 0 ? 1 : 0) + (i <= 4 && i + j > 4 ? 1 : 0) + (i <= 6 && i + j > 6 ? 1 : 0), v.Count, "v.Count, i=" + i + ", j=" + j);
+ Assert.AreEqual(i == 0 ? 0 : i <= 4 ? 1 : i <= 6 ? 2 : 3, v.Offset, "v.Offset, i=" + i + ", j=" + j);
+ Assert.IsTrue(list.Check(), "list check after RemoveAllCopies, i=" + i + ", j=" + j);
+ }
+ }
+ }
+
+ private void checkDisposed(bool reverse, int start, int count)
+ {
+ int k = 0;
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ if (i + j <= start || i >= start + count || (i <= start && i + j >= start + count) || (reverse && start <= i && start + count >= i + j))
+ {
+ try
+ {
+ k = views[i][j].Count;
+ }
+ catch (ViewDisposedException)
+ {
+ Assert.Fail("view[" + i + "][" + j + "] threw");
+ }
+ Assert.AreEqual(j, views[i][j].Count, "view[" + i + "][" + j + "] size");
+ if (reverse && ((j > 0 && start <= i && start + count >= i + j) || (j == 0 && start < i && start + count > i)))
+ Assert.AreEqual(start + (start + count - i - j), views[i][j].Offset, "view[" + i + "][" + j + "] offset (mirrored)");
+ else
+ Assert.AreEqual(i, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ }
+ else
+ {
+ try
+ {
+ k = views[i][j].Count;
+ Assert.Fail("view[" + i + "][" + j + "] no throw");
+ }
+ catch (ViewDisposedException) { }
+ }
+ }
+ }
+
+ [Test]
+ public void Reverse()
+ {
+ int start = 2, count = 3;
+ IList<int> list2 = list.View(start, count);
+ Assert.IsTrue(list.Check(), "list check before Reverse");
+ list2.Reverse();
+ Assert.IsTrue(list.Check(), "list check after Reverse");
+ checkDisposed(true, start, count);
+ }
+ [Test]
+ public void Sort()
+ {
+ int start = 2, count = 3;
+ IList<int> list2 = list.View(start, count);
+ Assert.IsTrue(list.Check(), "list check before Sort");
+ list2.Sort();
+ Assert.IsTrue(list.Check(), "list check after Sort");
+ checkDisposed(false, start, count);
+ }
+ [Test]
+ public void Shuffle()
+ {
+ int start = 2, count = 3;
+ IList<int> list2 = list.View(start, count);
+ Assert.IsTrue(list.Check(), "list check before Shuffle");
+ list2.Shuffle();
+ Assert.IsTrue(list.Check(), "list check after Shuffle");
+ checkDisposed(false, start, count);
+ }
+
+
+ }
+ }
+
+
+
+
+ namespace ArrayListOfTreesORLists
+ {
+ [TestFixture]
+ public class MultiLevelUnorderedOfUnOrdered
+ {
+ private ICollection<int> dit, dat, dut;
+
+ private ICollection<ICollection<int>> Dit, Dat, Dut;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new ArrayList<int>();
+ dat = new TreeSet<int>(Comparer<int>.Default, EqualityComparer<int>.Default);
+ dut = new ArrayList<int>();
+ dit.Add(2); dit.Add(1);
+ dat.Add(1); dat.Add(2);
+ dut.Add(3);
+ Dit = new ArrayList<ICollection<int>>();
+ Dat = new ArrayList<ICollection<int>>();
+ Dut = new ArrayList<ICollection<int>>();
+ }
+
+
+ [Test]
+ public void Check()
+ {
+ Assert.IsTrue(dit.UnsequencedEquals(dat));
+ Assert.IsFalse(dit.UnsequencedEquals(dut));
+ }
+
+
+ [Test]
+ public void Multi()
+ {
+ Dit.Add(dit); Dit.Add(dut); Dit.Add(dit);
+ Dat.Add(dut); Dat.Add(dit); Dat.Add(dat);
+ Assert.IsTrue(Dit.UnsequencedEquals(Dat));
+ Assert.IsFalse(Dit.UnsequencedEquals(Dut));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = dat = dut = null;
+ Dit = Dat = Dut = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class MultiLevelOrderedOfUnOrdered
+ {
+ private ICollection<int> dit, dat, dut;
+
+ private ISequenced<ICollection<int>> Dit, Dat, Dut;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new ArrayList<int>();
+ dat = new TreeSet<int>(Comparer<int>.Default, EqualityComparer<int>.Default);
+ dut = new ArrayList<int>();
+ dit.Add(2); dit.Add(1);
+ dat.Add(1); dat.Add(2);
+ dut.Add(3);
+ Dit = new ArrayList<ICollection<int>>();
+ Dat = new ArrayList<ICollection<int>>();
+ Dut = new ArrayList<ICollection<int>>();
+ }
+
+
+ [Test]
+ public void Check()
+ {
+ Assert.IsTrue(dit.UnsequencedEquals(dat));
+ Assert.IsFalse(dit.UnsequencedEquals(dut));
+ }
+
+
+ [Test]
+ public void Multi()
+ {
+ Dit.Add(dit); Dit.Add(dut); Dit.Add(dit);
+ Dat.Add(dut); Dat.Add(dit); Dat.Add(dat);
+ Dut.Add(dit); Dut.Add(dut); Dut.Add(dat);
+ Assert.IsFalse(Dit.SequencedEquals(Dat));
+ Assert.IsTrue(Dit.SequencedEquals(Dut));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = dat = dut = null;
+ Dit = Dat = Dut = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class MultiLevelUnOrderedOfOrdered
+ {
+ private ISequenced<int> dit, dat, dut, dot;
+
+ private ICollection<ISequenced<int>> Dit, Dat, Dut, Dot;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new TreeSet<int>(Comparer<int>.Default, EqualityComparer<int>.Default);
+ dat = new ArrayList<int>();
+ dut = new ArrayList<int>();
+ dot = new ArrayList<int>();
+ dit.Add(2); dit.Add(1);
+ dat.Add(2); dat.Add(1);
+ dut.Add(3);
+ dot.Add(1); dot.Add(2);
+ Dit = new ArrayList<ISequenced<int>>();
+ Dat = new ArrayList<ISequenced<int>>();
+ Dut = new ArrayList<ISequenced<int>>();
+ Dot = new ArrayList<ISequenced<int>>();
+ }
+
+
+ [Test]
+ public void Check()
+ {
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ Assert.IsTrue(dit.SequencedEquals(dot));
+ Assert.IsFalse(dit.SequencedEquals(dut));
+ }
+
+
+ [Test]
+ public void Multi()
+ {
+ Dit.Add(dit); Dit.Add(dut); Dit.Add(dit);
+ Dat.Add(dut); Dat.Add(dit); Dat.Add(dat);
+ Dut.Add(dot); Dut.Add(dut); Dut.Add(dit);
+ Dot.Add(dit); Dot.Add(dit); Dot.Add(dut);
+ Assert.IsTrue(Dit.UnsequencedEquals(Dut));
+ Assert.IsFalse(Dit.UnsequencedEquals(Dat));
+ Assert.IsTrue(Dit.UnsequencedEquals(Dot));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = dat = dut = dot = null;
+ Dit = Dat = Dut = Dot = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class MultiLevelOrderedOfOrdered
+ {
+ private ISequenced<int> dit, dat, dut, dot;
+
+ private ISequenced<ISequenced<int>> Dit, Dat, Dut, Dot;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new TreeSet<int>(Comparer<int>.Default, EqualityComparer<int>.Default);
+ dat = new ArrayList<int>();
+ dut = new ArrayList<int>();
+ dot = new ArrayList<int>();
+ dit.Add(2); dit.Add(1);
+ dat.Add(2); dat.Add(1);
+ dut.Add(3);
+ dot.Add(1); dot.Add(2);
+ Dit = new ArrayList<ISequenced<int>>();
+ Dat = new ArrayList<ISequenced<int>>();
+ Dut = new ArrayList<ISequenced<int>>();
+ Dot = new ArrayList<ISequenced<int>>();
+ }
+
+
+ [Test]
+ public void Check()
+ {
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ Assert.IsTrue(dit.SequencedEquals(dot));
+ Assert.IsFalse(dit.SequencedEquals(dut));
+ }
+
+
+ [Test]
+ public void Multi()
+ {
+ Dit.Add(dit); Dit.Add(dut); Dit.Add(dit);
+ Dat.Add(dut); Dat.Add(dit); Dat.Add(dat);
+ Dut.Add(dot); Dut.Add(dut); Dut.Add(dit);
+ Dot.Add(dit); Dot.Add(dit); Dot.Add(dut);
+ Assert.IsTrue(Dit.SequencedEquals(Dut));
+ Assert.IsFalse(Dit.SequencedEquals(Dat));
+ Assert.IsFalse(Dit.SequencedEquals(Dot));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = dat = dut = dot = null;
+ Dit = Dat = Dut = Dot = null;
+ }
+ }
+ }
+
+
+
+
+ namespace HashingAndEquals
+ {
+ [TestFixture]
+ public class ISequenced
+ {
+ private ISequenced<int> dit, dat, dut;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new ArrayList<int>();
+ dat = new ArrayList<int>();
+ dut = new ArrayList<int>();
+ }
+
+
+ [Test]
+ public void EmptyEmpty()
+ {
+ Assert.IsTrue(dit.SequencedEquals(dat));
+ }
+
+
+ [Test]
+ public void EmptyNonEmpty()
+ {
+ dit.Add(3);
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ Assert.IsFalse(dat.SequencedEquals(dit));
+ }
+
+ [Test]
+ public void HashVal()
+ {
+ Assert.AreEqual(CHC.sequencedhashcode(), dit.GetSequencedHashCode());
+ dit.Add(3);
+ Assert.AreEqual(CHC.sequencedhashcode(3), dit.GetSequencedHashCode());
+ dit.Add(7);
+ Assert.AreEqual(CHC.sequencedhashcode(3, 7), dit.GetSequencedHashCode());
+ Assert.AreEqual(CHC.sequencedhashcode(), dut.GetSequencedHashCode());
+ dut.Add(7);
+ Assert.AreEqual(CHC.sequencedhashcode(7), dut.GetSequencedHashCode());
+ dut.Add(3);
+ Assert.AreEqual(CHC.sequencedhashcode(7, 3), dut.GetSequencedHashCode());
+ }
+
+
+ [Test]
+ public void EqualHashButDifferent()
+ {
+ dit.Add(0); dit.Add(31);
+ dat.Add(1); dat.Add(0);
+ Assert.AreEqual(dit.GetSequencedHashCode(), dat.GetSequencedHashCode());
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ }
+
+
+ [Test]
+ public void Normal()
+ {
+ dit.Add(3);
+ dit.Add(7);
+ dat.Add(3);
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ Assert.IsFalse(dat.SequencedEquals(dit));
+ dat.Add(7);
+ Assert.IsTrue(dit.SequencedEquals(dat));
+ Assert.IsTrue(dat.SequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void WrongOrder()
+ {
+ dit.Add(3);
+ dut.Add(3);
+ Assert.IsTrue(dit.SequencedEquals(dut));
+ Assert.IsTrue(dut.SequencedEquals(dit));
+ dit.Add(7);
+ ((ArrayList<int>)dut).InsertFirst(7);
+ Assert.IsFalse(dit.SequencedEquals(dut));
+ Assert.IsFalse(dut.SequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void Reflexive()
+ {
+ Assert.IsTrue(dit.SequencedEquals(dit));
+ dit.Add(3);
+ Assert.IsTrue(dit.SequencedEquals(dit));
+ dit.Add(7);
+ Assert.IsTrue(dit.SequencedEquals(dit));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = null;
+ dat = null;
+ dut = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class IEditableCollection
+ {
+ private ICollection<int> dit, dat, dut;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new ArrayList<int>();
+ dat = new ArrayList<int>();
+ dut = new ArrayList<int>();
+ }
+
+
+ [Test]
+ public void EmptyEmpty()
+ {
+ Assert.IsTrue(dit.UnsequencedEquals(dat));
+ }
+
+
+ [Test]
+ public void EmptyNonEmpty()
+ {
+ dit.Add(3);
+ Assert.IsFalse(dit.UnsequencedEquals(dat));
+ Assert.IsFalse(dat.UnsequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void HashVal()
+ {
+ Assert.AreEqual(CHC.unsequencedhashcode(), dit.GetUnsequencedHashCode());
+ dit.Add(3);
+ Assert.AreEqual(CHC.unsequencedhashcode(3), dit.GetUnsequencedHashCode());
+ dit.Add(7);
+ Assert.AreEqual(CHC.unsequencedhashcode(3, 7), dit.GetUnsequencedHashCode());
+ Assert.AreEqual(CHC.unsequencedhashcode(), dut.GetUnsequencedHashCode());
+ dut.Add(3);
+ Assert.AreEqual(CHC.unsequencedhashcode(3), dut.GetUnsequencedHashCode());
+ dut.Add(7);
+ Assert.AreEqual(CHC.unsequencedhashcode(7, 3), dut.GetUnsequencedHashCode());
+ }
+
+
+ [Test]
+ public void EqualHashButDifferent()
+ {
+ dit.Add(-1657792980); dit.Add(-1570288808);
+ dat.Add(1862883298); dat.Add(-272461342);
+ Assert.AreEqual(dit.GetUnsequencedHashCode(), dat.GetUnsequencedHashCode());
+ Assert.IsFalse(dit.UnsequencedEquals(dat));
+ }
+
+
+ [Test]
+ public void Normal()
+ {
+ dit.Add(3);
+ dit.Add(7);
+ dat.Add(3);
+ Assert.IsFalse(dit.UnsequencedEquals(dat));
+ Assert.IsFalse(dat.UnsequencedEquals(dit));
+ dat.Add(7);
+ Assert.IsTrue(dit.UnsequencedEquals(dat));
+ Assert.IsTrue(dat.UnsequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void WrongOrder()
+ {
+ dit.Add(3);
+ dut.Add(3);
+ Assert.IsTrue(dit.UnsequencedEquals(dut));
+ Assert.IsTrue(dut.UnsequencedEquals(dit));
+ dit.Add(7);
+ dut.Add(7);
+ Assert.IsTrue(dit.UnsequencedEquals(dut));
+ Assert.IsTrue(dut.UnsequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void Reflexive()
+ {
+ Assert.IsTrue(dit.UnsequencedEquals(dit));
+ dit.Add(3);
+ Assert.IsTrue(dit.UnsequencedEquals(dit));
+ dit.Add(7);
+ Assert.IsTrue(dit.UnsequencedEquals(dit));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = null;
+ dat = null;
+ dut = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class MultiLevelUnorderedOfUnOrdered
+ {
+ private ICollection<int> dit, dat, dut;
+
+ private ICollection<ICollection<int>> Dit, Dat, Dut;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new ArrayList<int>();
+ dat = new ArrayList<int>();
+ dut = new ArrayList<int>();
+ dit.Add(2); dit.Add(1);
+ dat.Add(1); dat.Add(2);
+ dut.Add(3);
+ Dit = new ArrayList<ICollection<int>>();
+ Dat = new ArrayList<ICollection<int>>();
+ Dut = new ArrayList<ICollection<int>>();
+ }
+
+
+ [Test]
+ public void Check()
+ {
+ Assert.IsTrue(dit.UnsequencedEquals(dat));
+ Assert.IsFalse(dit.UnsequencedEquals(dut));
+ }
+
+
+ [Test]
+ public void Multi()
+ {
+ Dit.Add(dit); Dit.Add(dut); Dit.Add(dit);
+ Dat.Add(dut); Dat.Add(dit); Dat.Add(dat);
+ Assert.IsTrue(Dit.UnsequencedEquals(Dat));
+ Assert.IsFalse(Dit.UnsequencedEquals(Dut));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = dat = dut = null;
+ Dit = Dat = Dut = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class MultiLevelOrderedOfUnOrdered
+ {
+ private ICollection<int> dit, dat, dut;
+
+ private ISequenced<ICollection<int>> Dit, Dat, Dut;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new ArrayList<int>();
+ dat = new ArrayList<int>();
+ dut = new ArrayList<int>();
+ dit.Add(2); dit.Add(1);
+ dat.Add(1); dat.Add(2);
+ dut.Add(3);
+ Dit = new ArrayList<ICollection<int>>();
+ Dat = new ArrayList<ICollection<int>>();
+ Dut = new ArrayList<ICollection<int>>();
+ }
+
+
+ [Test]
+ public void Check()
+ {
+ Assert.IsTrue(dit.UnsequencedEquals(dat));
+ Assert.IsFalse(dit.UnsequencedEquals(dut));
+ }
+
+
+ [Test]
+ public void Multi()
+ {
+ Dit.Add(dit); Dit.Add(dut); Dit.Add(dit);
+ Dat.Add(dut); Dat.Add(dit); Dat.Add(dat);
+ Dut.Add(dit); Dut.Add(dut); Dut.Add(dat);
+ Assert.IsFalse(Dit.SequencedEquals(Dat));
+ Assert.IsTrue(Dit.SequencedEquals(Dut));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = dat = dut = null;
+ Dit = Dat = Dut = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class MultiLevelUnOrderedOfOrdered
+ {
+ private ISequenced<int> dit, dat, dut, dot;
+
+ private ICollection<ISequenced<int>> Dit, Dat, Dut, Dot;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new ArrayList<int>();
+ dat = new ArrayList<int>();
+ dut = new ArrayList<int>();
+ dot = new ArrayList<int>();
+ dit.Add(2); dit.Add(1);
+ dat.Add(1); dat.Add(2);
+ dut.Add(3);
+ dot.Add(2); dot.Add(1);
+ Dit = new ArrayList<ISequenced<int>>();
+ Dat = new ArrayList<ISequenced<int>>();
+ Dut = new ArrayList<ISequenced<int>>();
+ Dot = new ArrayList<ISequenced<int>>();
+ }
+
+
+ [Test]
+ public void Check()
+ {
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ Assert.IsTrue(dit.SequencedEquals(dot));
+ Assert.IsFalse(dit.SequencedEquals(dut));
+ }
+
+
+ [Test]
+ public void Multi()
+ {
+ Dit.Add(dit); Dit.Add(dut); Dit.Add(dit);
+ Dat.Add(dut); Dat.Add(dit); Dat.Add(dat);
+ Dut.Add(dot); Dut.Add(dut); Dut.Add(dit);
+ Dot.Add(dit); Dot.Add(dit); Dot.Add(dut);
+ Assert.IsTrue(Dit.UnsequencedEquals(Dut));
+ Assert.IsFalse(Dit.UnsequencedEquals(Dat));
+ Assert.IsTrue(Dit.UnsequencedEquals(Dot));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = dat = dut = dot = null;
+ Dit = Dat = Dut = Dot = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class MultiLevelOrderedOfOrdered
+ {
+ private ISequenced<int> dit, dat, dut, dot;
+
+ private ISequenced<ISequenced<int>> Dit, Dat, Dut, Dot;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new ArrayList<int>();
+ dat = new ArrayList<int>();
+ dut = new ArrayList<int>();
+ dot = new ArrayList<int>();
+ dit.Add(2); dit.Add(1);
+ dat.Add(1); dat.Add(2);
+ dut.Add(3);
+ dot.Add(2); dot.Add(1);
+ Dit = new ArrayList<ISequenced<int>>();
+ Dat = new ArrayList<ISequenced<int>>();
+ Dut = new ArrayList<ISequenced<int>>();
+ Dot = new ArrayList<ISequenced<int>>();
+ }
+
+
+ [Test]
+ public void Check()
+ {
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ Assert.IsTrue(dit.SequencedEquals(dot));
+ Assert.IsFalse(dit.SequencedEquals(dut));
+ }
+
+
+ [Test]
+ public void Multi()
+ {
+ Dit.Add(dit); Dit.Add(dut); Dit.Add(dit);
+ Dat.Add(dut); Dat.Add(dit); Dat.Add(dat);
+ Dut.Add(dot); Dut.Add(dut); Dut.Add(dit);
+ Dot.Add(dit); Dot.Add(dit); Dot.Add(dut);
+ Assert.IsTrue(Dit.SequencedEquals(Dut));
+ Assert.IsFalse(Dit.SequencedEquals(Dat));
+ Assert.IsFalse(Dit.SequencedEquals(Dot));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = dat = dut = dot = null;
+ Dit = Dat = Dut = Dot = null;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/1.0/Test/arrays/CircularQueueTest.cs b/mcs/class/Mono.C5/1.0/Test/arrays/CircularQueueTest.cs
new file mode 100644
index 00000000000..f8562221059
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/Test/arrays/CircularQueueTest.cs
@@ -0,0 +1,214 @@
+/*
+ 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 C5;
+using NUnit.Framework;
+using SCG = System.Collections.Generic;
+namespace C5UnitTests.arrays.circularqueue
+{
+ using CollectionOfInt = CircularQueue<int>;
+
+ [TestFixture]
+ public class GenericTesters
+ {
+ [Test]
+ public void TestEvents()
+ {
+ Fun<CollectionOfInt> factory = delegate() { return new CollectionOfInt(); };
+ new C5UnitTests.Templates.Events.QueueTester<CollectionOfInt>().Test(factory);
+ new C5UnitTests.Templates.Events.StackTester<CollectionOfInt>().Test(factory);
+ }
+
+ [Test]
+ public void Extensible()
+ {
+ //TODO: Test Circular Queue for Clone(?) and Serializable
+ //C5UnitTests.Templates.Extensible.Clone.Tester<CollectionOfInt>();
+ //C5UnitTests.Templates.Extensible.Serialization.Tester<CollectionOfInt>();
+ }
+ }
+
+ //[TestFixture]
+ public class Template
+ {
+ private CircularQueue<int> queue;
+
+ [SetUp]
+ public void Init()
+ {
+ queue = new CircularQueue<int>();
+ }
+
+ [Test]
+ public void LeTest()
+ {
+ }
+
+ [TearDown]
+ public void Dispose() { queue = null; }
+
+ }
+
+ [TestFixture]
+ public class Formatting
+ {
+ CircularQueue<int> coll;
+ IFormatProvider rad16;
+ [SetUp]
+ public void Init() { coll = new CircularQueue<int>(); rad16 = new RadixFormatProvider(16); }
+ [TearDown]
+ public void Dispose() { coll = null; rad16 = null; }
+ [Test]
+ public void Format()
+ {
+ Assert.AreEqual("{ }", coll.ToString());
+ foreach (int i in new int[] { -4, 28, 129, 65530 })
+ coll.Enqueue(i);
+ Assert.AreEqual("{ -4, 28, 129, 65530 }", coll.ToString());
+ Assert.AreEqual("{ -4, 1C, 81, FFFA }", coll.ToString(null, rad16));
+ Assert.AreEqual("{ -4, 28, 129... }", coll.ToString("L14", null));
+ Assert.AreEqual("{ -4, 1C, 81... }", coll.ToString("L14", rad16));
+ }
+ }
+
+ [TestFixture]
+ public class CircularQueue
+ {
+ private CircularQueue<int> queue;
+
+ [SetUp]
+ public void Init()
+ {
+ queue = new CircularQueue<int>();
+ }
+
+ void loadup1()
+ {
+ queue.Enqueue(11);
+ queue.Enqueue(12);
+ queue.Enqueue(13);
+ queue.Dequeue();
+ queue.Enqueue(103);
+ queue.Enqueue(14);
+ queue.Enqueue(15);
+ }
+
+ void loadup2()
+ {
+ loadup1();
+ for (int i = 0; i < 4; i++)
+ {
+ queue.Dequeue();
+ queue.Enqueue(1000 + i);
+ }
+ }
+
+ void loadup3()
+ {
+ for (int i = 0; i < 18; i++)
+ {
+ queue.Enqueue(i);
+ Assert.IsTrue(queue.Check());
+ }
+ for (int i = 0; i < 14; i++)
+ {
+ Assert.IsTrue(queue.Check());
+ queue.Dequeue();
+ }
+ }
+
+ [Test]
+ public void Expand()
+ {
+ Assert.IsTrue(queue.Check());
+ loadup3();
+ Assert.IsTrue(IC.eq(queue, 14, 15, 16, 17));
+ }
+
+ [Test]
+ public void Simple()
+ {
+ loadup1();
+ Assert.IsTrue(queue.Check());
+ Assert.AreEqual(5, queue.Count);
+ Assert.IsTrue(IC.eq(queue, 12, 13, 103, 14, 15));
+ Assert.AreEqual(12, queue.Choose());
+ }
+
+ [Test]
+ public void Stack()
+ {
+ queue.Push(1);
+ Assert.IsTrue(queue.Check());
+ queue.Push(2);
+ Assert.IsTrue(queue.Check());
+ queue.Push(3);
+ Assert.IsTrue(queue.Check());
+ Assert.AreEqual(3, queue.Pop());
+ Assert.IsTrue(queue.Check());
+ Assert.AreEqual(2, queue.Pop());
+ Assert.IsTrue(queue.Check());
+ Assert.AreEqual(1, queue.Pop());
+ Assert.IsTrue(queue.Check());
+ }
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void BadChoose()
+ {
+ queue.Choose();
+ }
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void BadDequeue()
+ {
+ queue.Dequeue();
+ }
+
+ [Test]
+ public void Simple2()
+ {
+ loadup2();
+ Assert.IsTrue(queue.Check());
+ Assert.AreEqual(5, queue.Count);
+ Assert.IsTrue(IC.eq(queue, 15, 1000, 1001, 1002, 1003));
+ Assert.AreEqual(15, queue.Choose());
+ }
+
+ [Test]
+ public void Counting()
+ {
+ Assert.IsTrue(queue.IsEmpty);
+ Assert.AreEqual(0, queue.Count);
+ Assert.AreEqual(Speed.Constant, queue.CountSpeed);
+ queue.Enqueue(11);
+ Assert.IsFalse(queue.IsEmpty);
+ queue.Enqueue(12);
+ Assert.AreEqual(2, queue.Count);
+ }
+
+ [TearDown]
+ public void Dispose() { queue = null; }
+
+ }
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/1.0/Test/arrays/HashedArrayListTest.cs b/mcs/class/Mono.C5/1.0/Test/arrays/HashedArrayListTest.cs
new file mode 100644
index 00000000000..aa4e7262802
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/Test/arrays/HashedArrayListTest.cs
@@ -0,0 +1,3405 @@
+/*
+ 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 C5;
+using NUnit.Framework;
+using SCG = System.Collections.Generic;
+
+
+namespace C5UnitTests.arrays.hashed
+{
+ using CollectionOfInt = HashedArrayList<int>;
+
+ [TestFixture]
+ public class GenericTesters
+ {
+ [Test]
+ public void TestEvents()
+ {
+ Fun<CollectionOfInt> factory = delegate() { return new CollectionOfInt(TenEqualityComparer.Default); };
+ new C5UnitTests.Templates.Events.ListTester<CollectionOfInt>().Test(factory);
+ }
+
+ [Test]
+ public void Extensible()
+ {
+ C5UnitTests.Templates.Extensible.Clone.Tester<CollectionOfInt>();
+ C5UnitTests.Templates.Extensible.Clone.ViewTester<CollectionOfInt>();
+ C5UnitTests.Templates.Extensible.Serialization.Tester<CollectionOfInt>();
+ C5UnitTests.Templates.Extensible.Serialization.ViewTester<CollectionOfInt>();
+ }
+ }
+
+ static class Factory
+ {
+ public static ICollection<T> New<T>() { return new HashedArrayList<T>(); }
+ }
+
+ namespace Events
+ {
+ class TenEqualityComparer : SCG.IEqualityComparer<int>
+ {
+ TenEqualityComparer() { }
+ public static TenEqualityComparer Default { get { return new TenEqualityComparer(); } }
+ public int GetHashCode(int item) { return (item / 10).GetHashCode(); }
+ public bool Equals(int item1, int item2) { return item1 / 10 == item2 / 10; }
+ }
+
+ [TestFixture]
+ public class IList_
+ {
+ private HashedArrayList<int> list;
+ CollectionEventList<int> seen;
+
+ [SetUp]
+ public void Init()
+ {
+ list = new HashedArrayList<int>(TenEqualityComparer.Default);
+ seen = new CollectionEventList<int>(IntEqualityComparer.Default);
+ }
+
+ private void listen() { seen.Listen(list, EventTypeEnum.All); }
+
+ [Test]
+ public void SetThis()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list[1] = 45;
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(56, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(56,1), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(45, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(45,1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ }
+
+ [Test]
+ public void Insert()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.Insert(1, 45);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(45,1), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(45, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ }
+
+ [Test]
+ public void InsertAll()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.InsertAll<int>(1, new int[] { 666, 777, 888 });
+ //seen.Print(Console.Error);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(666,1), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(666, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(777,2), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(777, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(888,3), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(888, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ list.InsertAll<int>(1, new int[] {});
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+ [Test]
+ public void InsertFirstLast()
+ {
+ list.Add(4); list.Add(56); list.Add(18);
+ listen();
+ list.InsertFirst(45);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(45,0), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(45, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ list.InsertLast(88);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(88,4), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(88, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ }
+
+ [Test]
+ public void Remove()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.Remove();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(56, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ }
+
+ [Test]
+ public void RemoveFirst()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.RemoveFirst();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(4,0), list),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(4, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ }
+
+ [Test]
+ public void RemoveLast()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.RemoveLast();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(56,1), list),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(56, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ }
+
+ [Test]
+ public void Reverse()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.Reverse();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ list.View(1, 0).Reverse();
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+
+ [Test]
+ public void Sort()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.Sort();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ list.View(1, 0).Sort();
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+ [Test]
+ public void Shuffle()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.Shuffle();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ list.View(1, 0).Shuffle();
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+ [Test]
+ public void RemoveAt()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.RemoveAt(1);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(56,1), list),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(56, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ }
+
+ [Test]
+ public void RemoveInterval()
+ {
+ list.Add(4); list.Add(56); list.Add(18);
+ listen();
+ list.RemoveInterval(1, 2);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Cleared, new ClearedRangeEventArgs(false,2,1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ list.RemoveInterval(1, 0);
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+ [Test]
+ public void Update()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ list.Update(53);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(56, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(53, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ list.Update(67);
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+ [Test]
+ public void FindOrAdd()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ int val = 53;
+ list.FindOrAdd(ref val);
+ seen.Check(new CollectionEvent<int>[] {});
+ val = 67;
+ list.FindOrAdd(ref val);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(67, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ }
+
+ [Test]
+ public void UpdateOrAdd()
+ {
+ list.Add(4); list.Add(56); list.Add(8);
+ listen();
+ int val = 53;
+ list.UpdateOrAdd(val);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(56, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(53, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ val = 67;
+ list.UpdateOrAdd(val);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(67, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ list.UpdateOrAdd(51, out val);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(53, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(51, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ val = 67;
+ list.UpdateOrAdd(81, out val);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(81, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ }
+
+ [Test]
+ public void RemoveItem()
+ {
+ list.Add(4); list.Add(56); list.Add(18);
+ listen();
+ list.Remove(53);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(56, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ list.Remove(11);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(18, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ }
+
+ [Test]
+ public void RemoveAll()
+ {
+ for (int i = 0; i < 10; i++)
+ {
+ list.Add(10 * i + 5);
+ }
+ listen();
+ list.RemoveAll<int>(new int[] { 32, 187, 45 });
+ //TODO: the order depends on internals of the HashSet
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(35, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(45, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ list.RemoveAll<int>(new int[] { 200, 300 });
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+ [Test]
+ public void Clear()
+ {
+ list.Add(4); list.Add(56); list.Add(18);
+ listen();
+ list.View(1, 1).Clear();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Cleared, new ClearedRangeEventArgs(false,1,1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ list.Clear();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Cleared, new ClearedRangeEventArgs(true,2,0), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ list.Clear();
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+ [Test]
+ public void ListDispose()
+ {
+ list.Add(4); list.Add(56); list.Add(18);
+ listen();
+ list.View(1, 1).Dispose();
+ seen.Check(new CollectionEvent<int>[] {});
+ list.Dispose();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Cleared, new ClearedRangeEventArgs(true,3,0), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)
+ });
+ list.Dispose();
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+
+ [Test]
+ public void RetainAll()
+ {
+ for (int i = 0; i < 10; i++)
+ {
+ list.Add(10 * i + 5);
+ }
+ listen();
+ list.RetainAll<int>(new int[] { 32, 187, 45, 62, 82, 95, 2 });
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(15, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(25, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(55, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(75, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ list.RetainAll<int>(new int[] { 32, 187, 45, 62, 82, 95, 2 });
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+ [Test]
+ public void RemoveAllCopies()
+ {
+ for (int i = 0; i < 10; i++)
+ {
+ list.Add(3 * i + 5);
+ }
+ listen();
+ list.RemoveAllCopies(14);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(11, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ list.RemoveAllCopies(14);
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+ [Test]
+ public void Add()
+ {
+ listen();
+ seen.Check(new CollectionEvent<int>[0]);
+ list.Add(23);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(23, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ }
+
+ [Test]
+ public void AddAll()
+ {
+ for (int i = 0; i < 10; i++)
+ {
+ list.Add(10 * i + 5);
+ }
+ listen();
+ list.AddAll<int>(new int[] { 145, 56, 167 });
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(145, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(167, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ list.AddAll<int>(new int[] { });
+ seen.Check(new CollectionEvent<int>[] {});
+ }
+
+ [TearDown]
+ public void Dispose() { list = null; seen = null; }
+ }
+
+ [TestFixture]
+ public class StackQueue
+ {
+
+ private ArrayList<int> list;
+ CollectionEventList<int> seen;
+
+ [SetUp]
+ public void Init()
+ {
+ list = new ArrayList<int>(TenEqualityComparer.Default);
+ seen = new CollectionEventList<int>(IntEqualityComparer.Default);
+ }
+
+ private void listen() { seen.Listen(list, EventTypeEnum.All); }
+
+ [Test]
+ public void EnqueueDequeue()
+ {
+ listen();
+ list.Enqueue(67);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(67,0), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(67, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ list.Enqueue(2);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(2,1), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(2, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ list.Dequeue();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(67,0), list),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(67, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ list.Dequeue();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(2,0), list),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(2, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ }
+
+ [Test]
+ public void PushPop()
+ {
+ listen();
+ seen.Check(new CollectionEvent<int>[0]);
+ list.Push(23);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(23,0), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(23, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ list.Push(-12);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(-12,1), list),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(-12, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ list.Pop();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(-12,1), list),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(-12, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ list.Pop();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(23,0), list),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(23, 1), list),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), list)});
+ }
+
+ [TearDown]
+ public void Dispose() { list = null; seen = null; }
+ }
+
+
+ }
+
+ namespace Safety
+ {
+ /// <summary>
+ /// Tests to see if the collection classes are robust for enumerable arguments that throw exceptions.
+ /// </summary>
+ [TestFixture]
+ public class BadEnumerable
+ {
+ private HashedArrayList<int> list;
+
+ [SetUp]
+ public void Init()
+ {
+ list = new HashedArrayList<int>();
+ }
+
+ [Test]
+ public void InsertAll()
+ {
+ list.Add(4); list.Add(56); list.Add(18);
+ try
+ {
+ list.InsertAll<int>(1, new BadEnumerable<int>(new BadEnumerableException(), 91, 81, 71));
+ Assert.Fail("Should not get here");
+ }
+ catch (BadEnumerableException) { }
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4, 91, 81, 71, 56, 18));
+ }
+
+ [Test]
+ public void AddAll()
+ {
+ list.Add(4); list.Add(56); list.Add(18);
+ try
+ {
+ list.View(0, 1).AddAll<int>(new BadEnumerable<int>(new BadEnumerableException(), 91, 81, 71));
+ Assert.Fail("Should not get here");
+ }
+ catch (BadEnumerableException) { }
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4, 91, 81, 71, 56, 18));
+ }
+
+ [Test]
+ public void RemoveAll()
+ {
+ list.Add(4); list.Add(56); list.Add(18);
+ try
+ {
+ list.RemoveAll(new BadEnumerable<int>(new BadEnumerableException(), 9, 8, 7));
+ Assert.Fail("Should not get here");
+ }
+ catch (BadEnumerableException) { }
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4, 56, 18));
+ }
+
+ [Test]
+ public void RetainAll()
+ {
+ list.Add(4); list.Add(56); list.Add(18);
+ try
+ {
+ list.RetainAll(new BadEnumerable<int>(new BadEnumerableException(), 9, 8, 7));
+ Assert.Fail("Should not get here");
+ }
+ catch (BadEnumerableException) { }
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4, 56, 18));
+ }
+
+
+ [Test]
+ public void ContainsAll()
+ {
+ list.Add(4); list.Add(56); list.Add(18);
+ try
+ {
+ list.ContainsAll(new BadEnumerable<int>(new BadEnumerableException(), 4, 18));
+ Assert.Fail("Should not get here");
+ }
+ catch (BadEnumerableException) { }
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4, 56, 18));
+ }
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+ }
+
+ /// <summary>
+ /// Tests to see if the collection classes are robust for delegate arguments that throw exceptions.
+ /// </summary>
+ [TestFixture]
+ public class BadFun
+ {
+ private HashedArrayList<int> list;
+
+ [SetUp]
+ public void Init()
+ {
+ list = new HashedArrayList<int>();
+ }
+
+ [Test]
+ public void NoTests() { }
+
+ [TearDown]
+ public void Dispose() { list = null; }
+ }
+ }
+
+
+ namespace Enumerable
+ {
+ [TestFixture]
+ public class Multiops
+ {
+ private HashedArrayList<int> list;
+
+ private Fun<int, bool> always, never, even;
+
+
+ [SetUp]
+ public void Init()
+ {
+ list = new HashedArrayList<int>();
+ always = delegate { return true; };
+ never = delegate { return false; };
+ even = delegate(int i) { return i % 2 == 0; };
+ }
+
+
+ [Test]
+ public void All()
+ {
+ Assert.IsTrue(list.All(always));
+ Assert.IsTrue(list.All(never));
+ Assert.IsTrue(list.All(even));
+ list.Add(8);
+ Assert.IsTrue(list.All(always));
+ Assert.IsFalse(list.All(never));
+ Assert.IsTrue(list.All(even));
+ list.Add(5);
+ Assert.IsTrue(list.All(always));
+ Assert.IsFalse(list.All(never));
+ Assert.IsFalse(list.All(even));
+ }
+
+
+ [Test]
+ public void Exists()
+ {
+ Assert.IsFalse(list.Exists(always));
+ Assert.IsFalse(list.Exists(never));
+ Assert.IsFalse(list.Exists(even));
+ list.Add(5);
+ Assert.IsTrue(list.Exists(always));
+ Assert.IsFalse(list.Exists(never));
+ Assert.IsFalse(list.Exists(even));
+ list.Add(8);
+ Assert.IsTrue(list.Exists(always));
+ Assert.IsFalse(list.Exists(never));
+ Assert.IsTrue(list.Exists(even));
+ }
+
+
+ [Test]
+ public void Apply()
+ {
+ int sum = 0;
+ Act<int> a = delegate(int i) { sum = i + 10 * sum; };
+
+ list.Apply(a);
+ Assert.AreEqual(0, sum);
+ sum = 0;
+ list.Add(5); list.Add(8); list.Add(7); list.Add(5);
+ list.Apply(a);
+ Assert.AreEqual(587, sum);
+ }
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+ }
+
+
+
+ [TestFixture]
+ public class GetEnumerator
+ {
+ private HashedArrayList<int> list;
+
+
+ [SetUp]
+ public void Init() { list = new HashedArrayList<int>(); }
+
+
+ [Test]
+ public void Empty()
+ {
+ SCG.IEnumerator<int> e = list.GetEnumerator();
+
+ Assert.IsFalse(e.MoveNext());
+ }
+
+
+ [Test]
+ public void Normal()
+ {
+ list.Add(5);
+ list.Add(8);
+ list.Add(5);
+ list.Add(5);
+ list.Add(10);
+ list.Add(1);
+
+ SCG.IEnumerator<int> e = list.GetEnumerator();
+
+ Assert.IsTrue(e.MoveNext());
+ Assert.AreEqual(5, e.Current);
+ Assert.IsTrue(e.MoveNext());
+ Assert.AreEqual(8, e.Current);
+ Assert.IsTrue(e.MoveNext());
+ Assert.AreEqual(10, e.Current);
+ Assert.IsTrue(e.MoveNext());
+ Assert.AreEqual(1, e.Current);
+ Assert.IsFalse(e.MoveNext());
+ }
+
+
+ [Test]
+ public void DoDispose()
+ {
+ list.Add(5);
+ list.Add(8);
+ list.Add(5);
+
+ SCG.IEnumerator<int> e = list.GetEnumerator();
+
+ e.MoveNext();
+ e.MoveNext();
+ e.Dispose();
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void MoveNextAfterUpdate()
+ {
+ list.Add(5);
+ list.Add(8);
+ list.Add(5);
+
+ SCG.IEnumerator<int> e = list.GetEnumerator();
+
+ e.MoveNext();
+ list.Add(99);
+ e.MoveNext();
+ }
+
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+ }
+ }
+
+ namespace CollectionOrSink
+ {
+ [TestFixture]
+ public class Formatting
+ {
+ ICollection<int> coll;
+ IFormatProvider rad16;
+ [SetUp]
+ public void Init() { coll = Factory.New<int>(); rad16 = new RadixFormatProvider(16); }
+ [TearDown]
+ public void Dispose() { coll = null; rad16 = null; }
+ [Test]
+ public void Format()
+ {
+ Assert.AreEqual("[ ]", coll.ToString());
+ coll.AddAll<int>(new int[] { -4, 28, 129, 65530 });
+ Assert.AreEqual("[ 0:-4, 1:28, 2:129, 3:65530 ]", coll.ToString());
+ Assert.AreEqual("[ 0:-4, 1:1C, 2:81, 3:FFFA ]", coll.ToString(null, rad16));
+ Assert.AreEqual("[ 0:-4, 1:28... ]", coll.ToString("L14", null));
+ Assert.AreEqual("[ 0:-4, 1:1C... ]", coll.ToString("L14", rad16));
+ }
+ }
+
+ [TestFixture]
+ public class CollectionOrSink
+ {
+ private HashedArrayList<int> list;
+
+
+ [SetUp]
+ public void Init() { list = new HashedArrayList<int>(); }
+
+ [Test]
+ public void Choose()
+ {
+ list.Add(7);
+ Assert.AreEqual(7, list.Choose());
+ }
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void BadChoose()
+ {
+ list.Choose();
+ }
+
+
+ [Test]
+ public void CountEtAl()
+ {
+ Assert.AreEqual(0, list.Count);
+ Assert.IsTrue(list.IsEmpty);
+ Assert.IsFalse(list.AllowsDuplicates);
+ Assert.IsTrue(list.Add(5));
+ Assert.AreEqual(1, list.Count);
+ Assert.IsFalse(list.IsEmpty);
+ Assert.IsFalse(list.Add(5));
+ Assert.AreEqual(1, list.Count);
+ Assert.IsFalse(list.IsEmpty);
+ Assert.IsTrue(list.Add(8));
+ Assert.AreEqual(2, list.Count);
+ }
+
+
+ [Test]
+ public void AddAll()
+ {
+ list.Add(3); list.Add(4); list.Add(5);
+
+ HashedArrayList<int> list2 = new HashedArrayList<int>();
+
+ list2.AddAll(list);
+ Assert.IsTrue(IC.eq(list2, 3, 4, 5));
+ list.AddAll(list2);
+ Assert.IsTrue(IC.eq(list2, 3, 4, 5));
+ Assert.IsTrue(IC.eq(list, 3, 4, 5));
+ }
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+ }
+
+ [TestFixture]
+ public class FindPredicate
+ {
+ private HashedArrayList<int> list;
+ Fun<int, bool> pred;
+
+ [SetUp]
+ public void Init()
+ {
+ list = new HashedArrayList<int>(TenEqualityComparer.Default);
+ pred = delegate(int i) { return i % 5 == 0; };
+ }
+
+ [TearDown]
+ public void Dispose() { list = null; }
+
+ [Test]
+ public void Find()
+ {
+ int i;
+ Assert.IsFalse(list.Find(pred, out i));
+ list.AddAll<int>(new int[] { 4, 22, 67, 37 });
+ Assert.IsFalse(list.Find(pred, out i));
+ list.AddAll<int>(new int[] { 45, 122, 675, 137 });
+ Assert.IsTrue(list.Find(pred, out i));
+ Assert.AreEqual(45, i);
+ }
+
+ [Test]
+ public void FindLast()
+ {
+ int i;
+ Assert.IsFalse(list.FindLast(pred, out i));
+ list.AddAll<int>(new int[] { 4, 22, 67, 37 });
+ Assert.IsFalse(list.FindLast(pred, out i));
+ list.AddAll<int>(new int[] { 45, 122, 675, 137 });
+ Assert.IsTrue(list.FindLast(pred, out i));
+ Assert.AreEqual(675, i);
+ }
+
+ [Test]
+ public void FindIndex()
+ {
+ Assert.IsFalse(0 <= list.FindIndex(pred));
+ list.AddAll<int>(new int[] { 4, 22, 67, 37 });
+ Assert.IsFalse(0 <= list.FindIndex(pred));
+ list.AddAll<int>(new int[] { 45, 122, 675, 137 });
+ Assert.AreEqual(4, list.FindIndex(pred));
+ }
+
+ [Test]
+ public void FindLastIndex()
+ {
+ Assert.IsFalse(0 <= list.FindLastIndex(pred));
+ list.AddAll<int>(new int[] { 4, 22, 67, 37 });
+ Assert.IsFalse(0 <= list.FindLastIndex(pred));
+ list.AddAll<int>(new int[] { 45, 122, 675, 137 });
+ Assert.AreEqual(6, list.FindLastIndex(pred));
+ }
+ }
+
+ [TestFixture]
+ public class UniqueItems
+ {
+ private HashedArrayList<int> list;
+
+ [SetUp]
+ public void Init() { list = new HashedArrayList<int>(); }
+
+ [TearDown]
+ public void Dispose() { list = null; }
+
+ [Test]
+ public void Test()
+ {
+ Assert.IsTrue(IC.seteq(list.UniqueItems()));
+ Assert.IsTrue(IC.seteq(list.ItemMultiplicities()));
+ list.AddAll<int>(new int[] { 7, 9, 7 });
+ Assert.IsTrue(IC.seteq(list.UniqueItems(), 7, 9));
+ Assert.IsTrue(IC.seteq(list.ItemMultiplicities(), 7, 1, 9, 1));
+ }
+ }
+
+ [TestFixture]
+ public class ArrayTest
+ {
+ private HashedArrayList<int> list;
+
+ int[] a;
+
+
+ [SetUp]
+ public void Init()
+ {
+ list = new HashedArrayList<int>();
+ a = new int[10];
+ for (int i = 0; i < 10; i++)
+ a[i] = 1000 + i;
+ }
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+
+
+ private string aeq(int[] a, params int[] b)
+ {
+ if (a.Length != b.Length)
+ return "Lengths differ: " + a.Length + " != " + b.Length;
+
+ for (int i = 0; i < a.Length; i++)
+ if (a[i] != b[i])
+ return String.Format("{0}'th elements differ: {1} != {2}", i, a[i], b[i]);
+
+ return "Alles klar";
+ }
+
+
+ [Test]
+ public void ToArray()
+ {
+ Assert.AreEqual("Alles klar", aeq(list.ToArray()));
+ list.Add(7);
+ list.Add(8);
+ Assert.AreEqual("Alles klar", aeq(list.ToArray(), 7, 8));
+ }
+
+
+ [Test]
+ public void CopyTo()
+ {
+ list.CopyTo(a, 1);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009));
+ list.Add(6);
+ list.CopyTo(a, 2);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 6, 1003, 1004, 1005, 1006, 1007, 1008, 1009));
+ list.Add(4);
+ list.Add(5);
+ list.Add(9);
+ list.CopyTo(a, 4);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 6, 1003, 6, 4, 5, 9, 1008, 1009));
+ list.Clear();
+ list.Add(7);
+ list.CopyTo(a, 9);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 6, 1003, 6, 4, 5, 9, 1008, 7));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void CopyToBad()
+ {
+ list.CopyTo(a, 11);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void CopyToBad2()
+ {
+ list.CopyTo(a, -1);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void CopyToTooFar()
+ {
+ list.Add(3);
+ list.Add(4);
+ list.CopyTo(a, 9);
+ }
+ }
+
+
+
+ [TestFixture]
+ public class Sync
+ {
+ private HashedArrayList<int> list;
+
+
+ [SetUp]
+ public void Init()
+ {
+ list = new HashedArrayList<int>();
+ }
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+
+
+ [Test]
+ public void Get()
+ {
+ Assert.IsNotNull(list.SyncRoot);
+ }
+ }
+ }
+
+
+
+
+ namespace EditableCollection
+ {
+ [TestFixture]
+ public class Searching
+ {
+ private HashedArrayList<int> list;
+
+
+ [SetUp]
+ public void Init() { list = new HashedArrayList<int>(); }
+
+
+ [Test]
+ [ExpectedException(typeof(NullReferenceException))]
+ public void NullEqualityComparerinConstructor1()
+ {
+ new HashedArrayList<int>(null);
+ }
+
+ [Test]
+ [ExpectedException(typeof(NullReferenceException))]
+ public void NullEqualityComparerinConstructor2()
+ {
+ new HashedArrayList<int>(5, null);
+ }
+
+ [Test]
+ public void Contains()
+ {
+ Assert.IsFalse(list.Contains(5));
+ list.Add(5);
+ Assert.IsTrue(list.Contains(5));
+ Assert.IsFalse(list.Contains(7));
+ list.Add(8);
+ list.Add(10);
+ Assert.IsTrue(list.Contains(5));
+ Assert.IsFalse(list.Contains(7));
+ Assert.IsTrue(list.Contains(8));
+ Assert.IsTrue(list.Contains(10));
+ list.Remove(8);
+ Assert.IsTrue(list.Contains(5));
+ Assert.IsFalse(list.Contains(7));
+ Assert.IsFalse(list.Contains(8));
+ Assert.IsTrue(list.Contains(10));
+ }
+
+ [Test]
+ public void BadAdd()
+ {
+ Assert.IsTrue(list.Add(5));
+ Assert.IsTrue(list.Add(8));
+ Assert.IsFalse(list.Add(5));
+ }
+
+
+ [Test]
+ public void ContainsCount()
+ {
+ Assert.AreEqual(0, list.ContainsCount(5));
+ list.Add(5);
+ Assert.AreEqual(1, list.ContainsCount(5));
+ Assert.AreEqual(0, list.ContainsCount(7));
+ list.Add(8);
+ Assert.AreEqual(1, list.ContainsCount(5));
+ Assert.AreEqual(0, list.ContainsCount(7));
+ Assert.AreEqual(1, list.ContainsCount(8));
+ }
+
+
+ [Test]
+ public void RemoveAllCopies()
+ {
+ list.Add(5); list.Add(7);
+ Assert.AreEqual(1, list.ContainsCount(5));
+ Assert.AreEqual(1, list.ContainsCount(7));
+ list.RemoveAllCopies(5);
+ Assert.AreEqual(0, list.ContainsCount(5));
+ Assert.AreEqual(1, list.ContainsCount(7));
+ list.Add(5); list.Add(8);
+ list.RemoveAllCopies(8);
+ Assert.IsTrue(IC.eq(list, 7, 5));
+ }
+
+
+ [Test]
+ public void FindAll()
+ {
+ Fun<int, bool> f = delegate(int i) { return i % 2 == 0; };
+
+ Assert.IsTrue(list.FindAll(f).IsEmpty);
+ list.Add(5); list.Add(8); list.Add(10);
+ Assert.IsTrue(((HashedArrayList<int>)list.FindAll(f)).Check());
+ Assert.IsTrue(IC.eq(list.FindAll(f), 8, 10));
+ }
+
+
+ [Test]
+ public void ContainsAll()
+ {
+ HashedArrayList<int> list2 = new HashedArrayList<int>();
+
+ Assert.IsTrue(list.ContainsAll(list2));
+ list2.Add(4);
+ Assert.IsFalse(list.ContainsAll(list2));
+ list.Add(4);
+ Assert.IsTrue(list.ContainsAll(list2));
+ list.Add(5);
+ Assert.IsTrue(list.ContainsAll(list2));
+ }
+
+
+ [Test]
+ public void RetainAll()
+ {
+ HashedArrayList<int> list2 = new HashedArrayList<int>();
+
+ list.Add(4); list.Add(5); list.Add(6);
+ list2.Add(5); list2.Add(4); list2.Add(7);
+ list.RetainAll(list2);
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4, 5));
+ list.Add(5); list.Add(4); list.Add(6);
+ list2.Clear();
+ list2.Add(5); list2.Add(5); list2.Add(6);
+ list.RetainAll(list2);
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 5, 6));
+ list2.Clear();
+ list2.Add(7); list2.Add(8); list2.Add(9);
+ list.RetainAll(list2);
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list));
+ }
+
+
+ [Test]
+ public void RemoveAll()
+ {
+ HashedArrayList<int> list2 = new HashedArrayList<int>();
+
+ list.Add(4); list.Add(5); list.Add(6);
+ list2.Add(5); list2.Add(4); list2.Add(7);
+ list.RemoveAll(list2);
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 6));
+ list.Add(5); list.Add(4); list.Add(6);
+ list2.Clear();
+ list2.Add(6); list2.Add(5);
+ list.RemoveAll(list2);
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4));
+ list2.Clear();
+ list2.Add(7); list2.Add(8); list2.Add(9);
+ list.RemoveAll(list2);
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4));
+ }
+
+
+ [Test]
+ public void Remove()
+ {
+ list.Add(4); list.Add(5); list.Add(6);
+ Assert.IsFalse(list.Remove(2));
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(list.Remove(4));
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 5, 6));
+ Assert.AreEqual(6, list.RemoveLast());
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 5));
+ list.Add(7);
+ Assert.AreEqual(5, list.RemoveFirst());
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 7));
+ }
+
+
+ [Test]
+ public void Clear()
+ {
+ list.Add(7); list.Add(6);
+ list.Clear();
+ Assert.IsTrue(list.IsEmpty);
+ }
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+ }
+ }
+
+
+
+
+ namespace IIndexed
+ {
+ [TestFixture]
+ public class Searching
+ {
+ private IIndexed<int> dit;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new HashedArrayList<int>();
+ }
+
+
+ [Test]
+ public void IndexOf()
+ {
+ Assert.AreEqual(~0, dit.IndexOf(6));
+ dit.Add(7);
+ Assert.AreEqual(~1, dit.IndexOf(6));
+ Assert.AreEqual(~1, dit.LastIndexOf(6));
+ Assert.AreEqual(0, dit.IndexOf(7));
+ dit.Add(5); dit.Add(7); dit.Add(8); dit.Add(7);
+ Assert.AreEqual(~3, dit.IndexOf(6));
+ Assert.AreEqual(0, dit.IndexOf(7));
+ Assert.AreEqual(0, dit.LastIndexOf(7));
+ Assert.AreEqual(2, dit.IndexOf(8));
+ Assert.AreEqual(1, dit.LastIndexOf(5));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class Removing
+ {
+ private IIndexed<int> dit;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new HashedArrayList<int>();
+ }
+
+
+ [Test]
+ public void RemoveAt()
+ {
+ dit.Add(5); dit.Add(7); dit.Add(9); dit.Add(1); dit.Add(2);
+ Assert.AreEqual(7, dit.RemoveAt(1));
+ Assert.IsTrue(((HashedArrayList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 5, 9, 1, 2));
+ Assert.AreEqual(5, dit.RemoveAt(0));
+ Assert.IsTrue(((HashedArrayList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 9, 1, 2));
+ Assert.AreEqual(2, dit.RemoveAt(2));
+ Assert.IsTrue(((HashedArrayList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 9, 1));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void RemoveAtBad0()
+ {
+ dit.RemoveAt(0);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void RemoveAtBadM1()
+ {
+ dit.RemoveAt(-1);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void RemoveAtBad1()
+ {
+ dit.Add(8);
+ dit.RemoveAt(1);
+ }
+
+
+ [Test]
+ public void RemoveInterval()
+ {
+ dit.RemoveInterval(0, 0);
+ dit.Add(10); dit.Add(20); dit.Add(30); dit.Add(40); dit.Add(50); dit.Add(60);
+ dit.RemoveInterval(3, 0);
+ Assert.IsTrue(((HashedArrayList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 10, 20, 30, 40, 50, 60));
+ dit.RemoveInterval(3, 1);
+ Assert.IsTrue(((HashedArrayList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 10, 20, 30, 50, 60));
+ dit.RemoveInterval(1, 3);
+ Assert.IsTrue(((HashedArrayList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 10, 60));
+ dit.RemoveInterval(0, 2);
+ Assert.IsTrue(((HashedArrayList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit));
+ dit.Add(10); dit.Add(20); dit.Add(30); dit.Add(40); dit.Add(50); dit.Add(60);
+ dit.RemoveInterval(0, 2);
+ Assert.IsTrue(((HashedArrayList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 30, 40, 50, 60));
+ dit.RemoveInterval(2, 2);
+ Assert.IsTrue(((HashedArrayList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 30, 40));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = null;
+ }
+ }
+ }
+
+
+
+
+ namespace IList
+ {
+ [TestFixture]
+ public class Searching
+ {
+ private IList<int> lst;
+
+
+ [SetUp]
+ public void Init() { lst = new HashedArrayList<int>(); }
+
+
+ [TearDown]
+ public void Dispose() { lst = null; }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void FirstBad()
+ {
+ int f = lst.First;
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void LastBad()
+ {
+ int f = lst.Last;
+ }
+
+
+ [Test]
+ public void FirstLast()
+ {
+ lst.Add(19);
+ Assert.AreEqual(19, lst.First);
+ Assert.AreEqual(19, lst.Last);
+ lst.Add(34); lst.InsertFirst(12);
+ Assert.AreEqual(12, lst.First);
+ Assert.AreEqual(34, lst.Last);
+ }
+
+
+ [Test]
+ public void This()
+ {
+ lst.Add(34);
+ Assert.AreEqual(34, lst[0]);
+ lst[0] = 56;
+ Assert.AreEqual(56, lst.First);
+ lst.Add(7); lst.Add(77); lst.Add(777); lst.Add(7777);
+ lst[0] = 45; lst[2] = 78; lst[4] = 101;
+ Assert.IsTrue(IC.eq(lst, 45, 7, 78, 777, 101));
+ }
+
+ [Test]
+ public void ThisWithUpdates()
+ {
+ HashedArrayList<KeyValuePair<int, int>> pairlist = new HashedArrayList<KeyValuePair<int, int>>(new KeyValuePairEqualityComparer<int, int>());
+ pairlist.Add(new KeyValuePair<int, int>(10, 50));
+ pairlist.Add(new KeyValuePair<int, int>(11, 51));
+ pairlist.Add(new KeyValuePair<int, int>(12, 52));
+ pairlist.Add(new KeyValuePair<int, int>(13, 53));
+ pairlist[2] = new KeyValuePair<int, int>(12, 102);
+ Assert.IsTrue(pairlist.Check());
+ Assert.AreEqual(new KeyValuePair<int, int>(12, 102), pairlist[2]);
+ pairlist[2] = new KeyValuePair<int, int>(22, 202);
+ Assert.IsTrue(pairlist.Check());
+ Assert.AreEqual(new KeyValuePair<int, int>(22, 202), pairlist[2]);
+ pairlist[1] = new KeyValuePair<int, int>(12, 303);
+ Assert.IsTrue(pairlist.Check());
+ Assert.AreEqual(new KeyValuePair<int, int>(12, 303), pairlist[1]);
+ Assert.AreEqual(new KeyValuePair<int, int>(22, 202), pairlist[2]);
+ }
+
+ [Test]
+ [ExpectedException(typeof(DuplicateNotAllowedException))]
+ public void ThisWithUpdatesBad()
+ {
+ HashedArrayList<KeyValuePair<int, int>> pairlist = new HashedArrayList<KeyValuePair<int, int>>(new KeyValuePairEqualityComparer<int, int>());
+ pairlist.Add(new KeyValuePair<int, int>(10, 50));
+ pairlist.Add(new KeyValuePair<int, int>(11, 51));
+ pairlist.Add(new KeyValuePair<int, int>(12, 52));
+ pairlist.Add(new KeyValuePair<int, int>(13, 53));
+ pairlist[2] = new KeyValuePair<int, int>(11, 102);
+ }
+
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void ThisBadEmptyGet()
+ {
+ int f = lst[0];
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void ThisBadLowGet()
+ {
+ lst.Add(7);
+
+ int f = lst[-1];
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void ThisBadHiGet()
+ {
+ lst.Add(6);
+
+ int f = lst[1];
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void ThisBadEmptySet()
+ {
+ lst[0] = 4;
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void ThisBadLowSet()
+ {
+ lst.Add(7);
+ lst[-1] = 9;
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void ThisBadHiSet()
+ {
+ lst.Add(6);
+ lst[1] = 11;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class Inserting
+ {
+ private IList<int> lst;
+
+
+ [SetUp]
+ public void Init() { lst = new HashedArrayList<int>(); }
+
+
+ [TearDown]
+ public void Dispose() { lst = null; }
+
+
+ [Test]
+ public void Insert()
+ {
+ lst.Insert(0, 5);
+ Assert.IsTrue(IC.eq(lst, 5));
+ lst.Insert(0, 7);
+ Assert.IsTrue(IC.eq(lst, 7, 5));
+ lst.Insert(1, 4);
+ Assert.IsTrue(IC.eq(lst, 7, 4, 5));
+ lst.Insert(3, 2);
+ Assert.IsTrue(IC.eq(lst, 7, 4, 5, 2));
+ }
+
+ [Test]
+ [ExpectedException(typeof(DuplicateNotAllowedException))]
+ public void InsertDuplicate()
+ {
+ lst.Insert(0, 5);
+ Assert.IsTrue(IC.eq(lst, 5));
+ lst.Insert(0, 7);
+ Assert.IsTrue(IC.eq(lst, 7, 5));
+ lst.Insert(1, 5);
+ }
+
+ [Test]
+ public void InsertAllDuplicate1()
+ {
+ lst.Insert(0, 3);
+ Assert.IsTrue(IC.eq(lst, 3));
+ lst.Insert(0, 7);
+ Assert.IsTrue(IC.eq(lst, 7, 3));
+ try
+ {
+ lst.InsertAll<int>(1, new int[] { 1, 2, 3, 4 });
+ }
+ catch (DuplicateNotAllowedException)
+ {
+ }
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 1, 2, 3));
+ }
+
+ [Test]
+ public void InsertAllDuplicate2()
+ {
+ lst.Insert(0, 3);
+ Assert.IsTrue(IC.eq(lst, 3));
+ lst.Insert(0, 7);
+ Assert.IsTrue(IC.eq(lst, 7, 3));
+ try
+ {
+ lst.InsertAll<int>(1, new int[] { 5, 6, 5, 8 });
+ }
+ catch (DuplicateNotAllowedException)
+ {
+ }
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 5, 6, 3));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void BadInsertLow()
+ {
+ lst.Add(7);
+ lst.Insert(-1, 9);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void BadInsertHi()
+ {
+ lst.Add(6);
+ lst.Insert(2, 11);
+ }
+
+
+ [Test]
+ public void FIFO()
+ {
+ for (int i = 0; i < 7; i++)
+ lst.Add(2 * i);
+
+ Assert.IsFalse(lst.FIFO);
+ Assert.AreEqual(12, lst.Remove());
+ Assert.AreEqual(10, lst.Remove());
+ lst.FIFO = true;
+ Assert.AreEqual(0, lst.Remove());
+ Assert.AreEqual(2, lst.Remove());
+ lst.FIFO = false;
+ Assert.AreEqual(8, lst.Remove());
+ Assert.AreEqual(6, lst.Remove());
+ }
+
+
+ [Test]
+ public void InsertFirstLast()
+ {
+ lst.InsertFirst(4);
+ lst.InsertLast(5);
+ lst.InsertFirst(14);
+ lst.InsertLast(15);
+ lst.InsertFirst(24);
+ lst.InsertLast(25);
+ lst.InsertFirst(34);
+ lst.InsertLast(55);
+ Assert.IsTrue(IC.eq(lst, 34, 24, 14, 4, 5, 15, 25, 55));
+ }
+
+
+ [Test]
+ public void InsertFirst()
+ {
+ lst.Add(2);
+ lst.Add(3);
+ lst.Add(4);
+ lst.Add(5);
+ lst.ViewOf(2).InsertFirst(7);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 2, 3, 4, 5));
+ lst.ViewOf(3).InsertFirst(8);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 2, 8, 3, 4, 5));
+ lst.ViewOf(5).InsertFirst(9);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 2, 8, 3, 4, 9, 5));
+ }
+
+
+ [Test]
+ public void BadFirst()
+ {
+ lst.Add(2);
+ lst.Add(3);
+ lst.Add(2);
+ lst.Add(5);
+ Assert.IsNull(lst.ViewOf(4));
+ }
+
+
+ [Test]
+ public void InsertAfter()
+ {
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ lst.Add(4);
+ lst.Add(5);
+ lst.LastViewOf(2).InsertLast(7);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 1, 2, 7, 3, 4, 5));
+ lst.LastViewOf(1).InsertLast(8);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 1, 8, 2, 7, 3, 4, 5));
+ lst.LastViewOf(5).InsertLast(9);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 1, 8, 2, 7, 3, 4, 5, 9));
+ }
+
+
+ [Test]
+ public void BadInsertAfter()
+ {
+ lst.Add(2);
+ lst.Add(3);
+ lst.Add(6);
+ lst.Add(5);
+ Assert.IsNull(lst.ViewOf(4));
+ }
+
+
+ [Test]
+ public void InsertAll()
+ {
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ lst.Add(4);
+
+ IList<int> lst2 = new HashedArrayList<int>();
+
+ lst2.Add(7); lst2.Add(8); lst2.Add(9);
+ lst.InsertAll(0, lst2);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 8, 9, 1, 2, 3, 4));
+ lst.RemoveAll(lst2);
+ lst.InsertAll(4, lst2);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 1, 2, 3, 4, 7, 8, 9));
+ lst.RemoveAll(lst2);
+ lst.InsertAll(2, lst2);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 1, 2, 7, 8, 9, 3, 4));
+ }
+
+ [Test]
+ [ExpectedException(typeof(DuplicateNotAllowedException))]
+ public void InsertAllBad()
+ {
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ lst.Add(4);
+
+ IList<int> lst2 = new HashedArrayList<int>();
+
+ lst2.Add(5); lst2.Add(2); lst2.Add(9);
+ lst.InsertAll(0, lst2);
+ }
+
+
+ [Test]
+ public void Map()
+ {
+ Fun<int, string> m = delegate(int i) { return "<<" + i + ">>"; };
+ IList<string> r = lst.Map(m);
+
+ Assert.IsTrue(((HashedArrayList<string>)r).Check());
+ Assert.IsTrue(r.IsEmpty);
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ lst.Add(4);
+ r = lst.Map(m);
+ Assert.IsTrue(((HashedArrayList<string>)r).Check());
+ Assert.AreEqual(4, r.Count);
+ for (int i = 0; i < 4; i++)
+ Assert.AreEqual("<<" + (i + 1) + ">>", r[i]);
+ }
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void BadMapper()
+ {
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ Fun<int, bool> m = delegate(int i) { if (i == 2) lst.Add(7); return true; };
+ lst.Map(m);
+ }
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void ModifyingFindAll()
+ {
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ Fun<int, bool> m = delegate(int i) { if (i == 2) lst.Add(7); return true; };
+ lst.FindAll(m);
+ }
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void BadMapperView()
+ {
+ lst = lst.View(0, 0);
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ Fun<int, bool> m = delegate(int i) { if (i == 2) lst.Add(7); return true; };
+ lst.Map(m);
+ }
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void ModifyingFindAllView()
+ {
+ lst = lst.View(0, 0);
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ Fun<int, bool> m = delegate(int i) { if (i == 2) lst.Add(7); return true; };
+ lst.FindAll(m);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void BadRemove() { lst.Remove(); }
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void BadRemoveFirst() { lst.RemoveFirst(); }
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void BadRemoveLast() { lst.RemoveLast(); }
+
+
+ [Test]
+ public void RemoveFirstLast()
+ {
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ lst.Add(4);
+ Assert.AreEqual(1, lst.RemoveFirst());
+ Assert.AreEqual(4, lst.RemoveLast());
+ Assert.AreEqual(2, lst.RemoveFirst());
+ Assert.AreEqual(3, lst.RemoveLast());
+ Assert.IsTrue(lst.IsEmpty);
+ }
+
+
+ [Test]
+ public void Reverse()
+ {
+ for (int i = 0; i < 10; i++)
+ lst.Add(i);
+
+ lst.Reverse();
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0));
+ lst.View(0, 3).Reverse();
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 8, 9, 6, 5, 4, 3, 2, 1, 0));
+ lst.View(7, 0).Reverse();
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 8, 9, 6, 5, 4, 3, 2, 1, 0));
+ lst.View(7, 3).Reverse();
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 8, 9, 6, 5, 4, 3, 0, 1, 2));
+ lst.View(5, 1).Reverse();
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 8, 9, 6, 5, 4, 3, 0, 1, 2));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void BadReverse()
+ {
+ for (int i = 0; i < 10; i++)
+ lst.Add(i);
+
+ lst.View(8, 3).Reverse();
+ }
+ }
+
+
+ [TestFixture]
+ public class Combined
+ {
+ private IList<KeyValuePair<int, int>> lst;
+
+
+ [SetUp]
+ public void Init()
+ {
+ lst = new HashedArrayList<KeyValuePair<int, int>>(new KeyValuePairEqualityComparer<int, int>());
+ for (int i = 0; i < 10; i++)
+ lst.Add(new KeyValuePair<int, int>(i, i + 30));
+ }
+
+
+ [TearDown]
+ public void Dispose() { lst = null; }
+
+
+ [Test]
+ public void Find()
+ {
+ KeyValuePair<int, int> p = new KeyValuePair<int, int>(3, 78);
+
+ Assert.IsTrue(lst.Find(ref p));
+ Assert.AreEqual(3, p.Key);
+ Assert.AreEqual(33, p.Value);
+ p = new KeyValuePair<int, int>(13, 78);
+ Assert.IsFalse(lst.Find(ref p));
+ }
+
+
+ [Test]
+ public void FindOrAdd()
+ {
+ KeyValuePair<int, int> p = new KeyValuePair<int, int>(3, 78);
+
+ Assert.IsTrue(lst.FindOrAdd(ref p));
+ Assert.AreEqual(3, p.Key);
+ Assert.AreEqual(33, p.Value);
+ p = new KeyValuePair<int, int>(13, 79);
+ Assert.IsFalse(lst.FindOrAdd(ref p));
+ Assert.AreEqual(13, lst[10].Key);
+ Assert.AreEqual(79, lst[10].Value);
+ }
+
+
+ [Test]
+ public void Update()
+ {
+ KeyValuePair<int, int> p = new KeyValuePair<int, int>(3, 78);
+
+ Assert.IsTrue(lst.Update(p));
+ Assert.AreEqual(3, lst[3].Key);
+ Assert.AreEqual(78, lst[3].Value);
+ p = new KeyValuePair<int, int>(13, 78);
+ Assert.IsFalse(lst.Update(p));
+ }
+
+
+ [Test]
+ public void UpdateOrAdd()
+ {
+ KeyValuePair<int, int> p = new KeyValuePair<int, int>(3, 78);
+
+ Assert.IsTrue(lst.UpdateOrAdd(p));
+ Assert.AreEqual(3, lst[3].Key);
+ Assert.AreEqual(78, lst[3].Value);
+ p = new KeyValuePair<int, int>(13, 79);
+ Assert.IsFalse(lst.UpdateOrAdd(p));
+ Assert.AreEqual(13, lst[10].Key);
+ Assert.AreEqual(79, lst[10].Value);
+ }
+
+
+ [Test]
+ public void RemoveWithReturn()
+ {
+ KeyValuePair<int, int> p = new KeyValuePair<int, int>(3, 78);
+
+ Assert.IsTrue(lst.Remove(p, out p));
+ Assert.AreEqual(3, p.Key);
+ Assert.AreEqual(33, p.Value);
+ Assert.AreEqual(4, lst[3].Key);
+ Assert.AreEqual(34, lst[3].Value);
+ p = new KeyValuePair<int, int>(13, 78);
+ Assert.IsFalse(lst.Remove(p, out p));
+ }
+ }
+
+
+ [TestFixture]
+ public class Sorting
+ {
+ private IList<int> lst;
+
+
+ [SetUp]
+ public void Init() { lst = new HashedArrayList<int>(); }
+
+
+ [TearDown]
+ public void Dispose() { lst = null; }
+
+
+ [Test]
+ public void Sort()
+ {
+ lst.Add(5); lst.Add(6); lst.Add(55); lst.Add(7); lst.Add(3);
+ Assert.IsFalse(lst.IsSorted(new IC()));
+ lst.Sort(new IC());
+ Assert.IsTrue(lst.IsSorted());
+ Assert.IsTrue(lst.IsSorted(new IC()));
+ Assert.IsTrue(IC.eq(lst, 3, 5, 6, 7, 55));
+ }
+ }
+ }
+
+
+
+
+ namespace Range
+ {
+ [TestFixture]
+ public class Range
+ {
+ private IList<int> lst;
+
+
+ [SetUp]
+ public void Init() { lst = new HashedArrayList<int>(); }
+
+
+ [TearDown]
+ public void Dispose() { lst = null; }
+
+
+ [Test]
+ public void GetRange()
+ {
+ //Assert.IsTrue(IC.eq(lst[0, 0)));
+ for (int i = 0; i < 10; i++) lst.Add(i);
+
+ Assert.IsTrue(IC.eq(lst[0, 3], 0, 1, 2));
+ Assert.IsTrue(IC.eq(lst[3, 3], 3, 4, 5));
+ Assert.IsTrue(IC.eq(lst[6, 3], 6, 7, 8));
+ Assert.IsTrue(IC.eq(lst[6, 4], 6, 7, 8, 9));
+ }
+
+
+ [Test]
+ public void Backwards()
+ {
+ for (int i = 0; i < 10; i++) lst.Add(i);
+
+ Assert.IsTrue(IC.eq(lst.Backwards(), 9, 8, 7, 6, 5, 4, 3, 2, 1, 0));
+ Assert.IsTrue(IC.eq(lst[0, 3].Backwards(), 2, 1, 0));
+ Assert.IsTrue(IC.eq(lst[3, 3].Backwards(), 5, 4, 3));
+ Assert.IsTrue(IC.eq(lst[6, 4].Backwards(), 9, 8, 7, 6));
+ }
+
+
+ [Test]
+ public void DirectionAndCount()
+ {
+ for (int i = 0; i < 10; i++) lst.Add(i);
+
+ Assert.AreEqual(EnumerationDirection.Forwards, lst.Direction);
+ Assert.AreEqual(EnumerationDirection.Forwards, lst[3, 4].Direction);
+ Assert.AreEqual(EnumerationDirection.Backwards, lst[3, 4].Backwards().Direction);
+ Assert.AreEqual(EnumerationDirection.Backwards, lst.Backwards().Direction);
+ Assert.AreEqual(4, lst[3, 4].Count);
+ Assert.AreEqual(4, lst[3, 4].Backwards().Count);
+ Assert.AreEqual(10, lst.Backwards().Count);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void MoveNextAfterUpdate()
+ {
+ for (int i = 0; i < 10; i++) lst.Add(i);
+
+ foreach (int i in lst)
+ {
+ lst.Add(45 + i);
+ }
+ }
+ }
+ }
+
+
+
+
+ namespace View
+ {
+ [TestFixture]
+ public class Simple
+ {
+ HashedArrayList<int> list;
+ HashedArrayList<int> view;
+
+
+ [SetUp]
+ public void Init()
+ {
+ list = new HashedArrayList<int>();
+ list.Add(0); list.Add(1); list.Add(2); list.Add(3);
+ view = (HashedArrayList<int>)list.View(1, 2);
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ list = null;
+ view = null;
+ }
+
+
+ void check()
+ {
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(view.Check());
+ }
+
+ [Test]
+ public void InsertPointer()
+ {
+ IList<int> view2 = list.View(2, 0);
+ list.Insert(view2, 7);
+ check();
+ list.Insert(list, 8);
+ check();
+ view.Insert(view2, 9);
+ check();
+ view.Insert(list.View(3, 2), 10);
+ check();
+ view.Insert(list.ViewOf(0), 11);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 11, 1, 9, 7, 2, 10, 3, 8));
+ Assert.IsTrue(IC.eq(view, 11, 1, 9, 7, 2, 10));
+ }
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void InsertPointerBad1()
+ {
+ view.Insert(list.View(0, 0), 7);
+ }
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void InsertPointerBad2()
+ {
+ view.Insert(list, 7);
+ }
+
+ [Test]
+ [ExpectedException(typeof(IncompatibleViewException))]
+ public void InsertPointerBad3()
+ {
+ list.Insert(new ArrayList<int>(), 7);
+ }
+
+ [Test]
+ [ExpectedException(typeof(IncompatibleViewException))]
+ public void InsertPointerBad4()
+ {
+ list.Insert(new ArrayList<int>().View(0, 0), 7);
+ }
+
+
+ [Test]
+ public void Span()
+ {
+ IList<int> span = list.View(1, 0).Span(list.View(2, 0));
+ Assert.IsTrue(span.Check());
+ Assert.AreEqual(1, span.Offset);
+ Assert.AreEqual(1, span.Count);
+ span = list.View(0, 2).Span(list.View(2, 2));
+ Assert.IsTrue(span.Check());
+ Assert.AreEqual(0, span.Offset);
+ Assert.AreEqual(4, span.Count);
+ span = list.View(3, 1).Span(list.View(1, 1));
+ Assert.IsNull(span);
+ }
+
+ [Test]
+ public void ViewOf()
+ {
+ for (int i = 0; i < 4; i++)
+ list.Add(i);
+ IList<int> v = view.ViewOf(2);
+ Assert.IsTrue(v.Check());
+ Assert.IsTrue(IC.eq(v, 2));
+ Assert.AreEqual(2, v.Offset);
+ v = list.ViewOf(2);
+ Assert.IsTrue(v.Check());
+ Assert.IsTrue(IC.eq(v, 2));
+ Assert.AreEqual(2, v.Offset);
+ v = list.LastViewOf(2);
+ Assert.IsTrue(v.Check());
+ Assert.IsTrue(IC.eq(v, 2));
+ Assert.AreEqual(2, v.Offset);
+ }
+
+ [Test]
+ public void BadViewOf()
+ {
+ Assert.IsNull(view.ViewOf(5));
+ Assert.IsNull(view.LastViewOf(5));
+ Assert.IsNull(view.ViewOf(3));
+ Assert.IsNull(view.LastViewOf(3));
+ Assert.IsNull(view.ViewOf(0));
+ Assert.IsNull(view.LastViewOf(0));
+ }
+
+
+ [Test]
+ public void ArrayStuff()
+ {
+ Assert.IsTrue(IC.eq(view.ToArray(), 1, 2));
+ int[] extarray = new int[5];
+ view.CopyTo(extarray, 2);
+ Assert.IsTrue(IC.eq(extarray, 0, 0, 1, 2, 0));
+ }
+
+
+ [Test]
+ public void Add()
+ {
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 1, 2, 3));
+ Assert.IsTrue(IC.eq(view, 1, 2));
+ view.InsertFirst(10);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 10, 1, 2, 3));
+ Assert.IsTrue(IC.eq(view, 10, 1, 2));
+ view.Clear();
+ Assert.IsFalse(view.IsReadOnly);
+ Assert.IsFalse(view.AllowsDuplicates);
+ Assert.IsTrue(view.IsEmpty);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 3));
+ Assert.IsTrue(IC.eq(view));
+ view.Add(8);
+ Assert.IsFalse(view.IsEmpty);
+ Assert.IsFalse(view.AllowsDuplicates);
+ Assert.IsFalse(view.IsReadOnly);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 8, 3));
+ Assert.IsTrue(IC.eq(view, 8));
+ view.Add(12);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 8, 12, 3));
+ Assert.IsTrue(IC.eq(view, 8, 12));
+ view./*ViewOf(12).*/InsertLast(15);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 8, 12, 15, 3));
+ Assert.IsTrue(IC.eq(view, 8, 12, 15));
+ view.ViewOf(12).InsertFirst(18);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 8, 18, 12, 15, 3));
+ Assert.IsTrue(IC.eq(view, 8, 18, 12, 15));
+
+ HashedArrayList<int> lst2 = new HashedArrayList<int>();
+
+ lst2.Add(90); lst2.Add(92);
+ view.AddAll(lst2);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 8, 18, 12, 15, 90, 92, 3));
+ Assert.IsTrue(IC.eq(view, 8, 18, 12, 15, 90, 92));
+ view.InsertLast(66);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 8, 18, 12, 15, 90, 92, 66, 3));
+ Assert.IsTrue(IC.eq(view, 8, 18, 12, 15, 90, 92, 66));
+ }
+
+
+ [Test]
+ public void Bxxx()
+ {
+ Assert.IsTrue(IC.eq(view.Backwards(), 2, 1));
+ Assert.AreSame(list, view.Underlying);
+ Assert.IsNull(list.Underlying);
+ Assert.AreEqual(EnumerationDirection.Forwards, view.Direction);
+ Assert.AreEqual(EnumerationDirection.Backwards, view.Backwards().Direction);
+ Assert.AreEqual(0, list.Offset);
+ Assert.AreEqual(1, view.Offset);
+ }
+
+
+ [Test]
+ public void Contains()
+ {
+ Assert.IsTrue(view.Contains(1));
+ Assert.IsFalse(view.Contains(0));
+
+ HashedArrayList<int> lst2 = new HashedArrayList<int>();
+
+ lst2.Add(2);
+ Assert.IsTrue(view.ContainsAll(lst2));
+ lst2.Add(3);
+ Assert.IsFalse(view.ContainsAll(lst2));
+ Assert.AreEqual(Speed.Constant, view.ContainsSpeed);
+ Assert.AreEqual(2, view.Count);
+ view.Add(1);
+ Assert.AreEqual(1, view.ContainsCount(2));
+ Assert.AreEqual(1, view.ContainsCount(1));
+ Assert.AreEqual(2, view.Count);
+ }
+
+
+ [Test]
+ public void CreateView()
+ {
+ HashedArrayList<int> view2 = (HashedArrayList<int>)view.View(1, 0);
+
+ Assert.AreSame(list, view2.Underlying);
+ }
+
+
+ [Test]
+ public void FIFO()
+ {
+ Assert.IsFalse(view.FIFO);
+ view.FIFO = true;
+ view.Add(23); view.Add(24); view.Add(25);
+ check();
+ Assert.IsTrue(IC.eq(view, 1, 2, 23, 24, 25));
+ Assert.AreEqual(1, view.Remove());
+ check();
+ Assert.IsTrue(IC.eq(view, 2, 23, 24, 25));
+ view.FIFO = false;
+ Assert.IsFalse(view.FIFO);
+ Assert.AreEqual(25, view.Remove());
+ check();
+ Assert.IsTrue(IC.eq(view, 2, 23, 24));
+ }
+
+
+ [Test]
+ public void MapEtc()
+ {
+ HashedArrayList<double> dbl = (HashedArrayList<double>)view.Map(new Fun<int, double>(delegate(int i) { return i / 10.0; }));
+
+ Assert.IsTrue(dbl.Check());
+ Assert.AreEqual(0.1, dbl[0]);
+ Assert.AreEqual(0.2, dbl[1]);
+ for (int i = 0; i < 10; i++) view.Add(i);
+
+ HashedArrayList<int> list2 = (HashedArrayList<int>)view.FindAll(new Fun<int, bool>(delegate(int i) { return i % 4 == 1; }));
+
+ Assert.IsTrue(list2.Check());
+ Assert.IsTrue(IC.eq(list2, 1, 5, 9));
+ }
+
+
+ [Test]
+ public void FL()
+ {
+ Assert.AreEqual(1, view.First);
+ Assert.AreEqual(2, view.Last);
+ }
+
+
+ [Test]
+ public void Indexing()
+ {
+ list.Clear();
+ for (int i = 0; i < 20; i++) list.Add(i);
+
+ view = (HashedArrayList<int>)list.View(5, 7);
+ for (int i = 0; i < 7; i++) Assert.AreEqual(i + 5, view[i]);
+
+ for (int i = 0; i < 7; i++) Assert.AreEqual(i, view.IndexOf(i + 5));
+
+ for (int i = 0; i < 7; i++) Assert.AreEqual(i, view.LastIndexOf(i + 5));
+ }
+
+
+ [Test]
+ public void Insert()
+ {
+ view.Insert(0, 34);
+ view.Insert(1, 35);
+ view.Insert(4, 36);
+ Assert.IsTrue(view.Check());
+ Assert.IsTrue(IC.eq(view, 34, 35, 1, 2, 36));
+
+ IList<int> list2 = new HashedArrayList<int>();
+
+ list2.Add(40); list2.Add(41);
+ view.InsertAll(3, list2);
+ Assert.IsTrue(view.Check());
+ Assert.IsTrue(IC.eq(view, 34, 35, 1, 40, 41, 2, 36));
+ }
+
+
+ [Test]
+ public void Sort()
+ {
+ view.Add(45); view.Add(47); view.Add(46); view.Add(48);
+ Assert.IsFalse(view.IsSorted(new IC()));
+ view.Sort(new IC());
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 1, 2, 45, 46, 47, 48, 3));
+ Assert.IsTrue(IC.eq(view, 1, 2, 45, 46, 47, 48));
+ }
+
+
+ [Test]
+ public void Remove()
+ {
+ view.Add(1); view.Add(5); view.Add(3); view.Add(1); view.Add(3); view.Add(0);
+ Assert.IsTrue(IC.eq(view, 1, 2, 5));
+ Assert.IsTrue(view.Remove(1));
+ check();
+ Assert.IsTrue(IC.eq(view, 2, 5));
+ Assert.IsFalse(view.Remove(1));
+ check();
+ Assert.IsTrue(IC.eq(view, 2, 5));
+ Assert.IsFalse(view.Remove(0));
+ check();
+ Assert.IsTrue(IC.eq(view, 2, 5));
+ view.RemoveAllCopies(3);
+ check();
+ Assert.IsTrue(IC.eq(view, 2, 5));
+ Assert.IsTrue(IC.eq(list, 0, 2, 5, 3));
+ view.Add(1); view.Add(5); view.Add(3); view.Add(1); view.Add(3); view.Add(0);
+ Assert.IsTrue(IC.eq(view, 2, 5, 1));
+
+ HashedArrayList<int> l2 = new HashedArrayList<int>();
+
+ l2.Add(1); l2.Add(2); l2.Add(2); l2.Add(3); l2.Add(1);
+ view.RemoveAll(l2);
+ check();
+ Assert.IsTrue(IC.eq(view, 5));
+ view.RetainAll(l2);
+ check();
+ Assert.IsTrue(IC.eq(view));
+ view.Add(2); view.Add(4); view.Add(5);
+ Assert.AreEqual(2, view.RemoveAt(0));
+ Assert.AreEqual(5, view.RemoveAt(1));
+ Assert.AreEqual(4, view.RemoveAt(0));
+ check();
+ Assert.IsTrue(IC.eq(view));
+ view.Add(8); view.Add(6); view.Add(78);
+ Assert.AreEqual(8, view.RemoveFirst());
+ Assert.AreEqual(78, view.RemoveLast());
+ view.Add(2); view.Add(5); view.Add(3); view.Add(1);
+ view.RemoveInterval(1, 2);
+ check();
+ Assert.IsTrue(IC.eq(view, 6, 1));
+ }
+
+
+ [Test]
+ public void Reverse()
+ {
+ view.Clear();
+ for (int i = 0; i < 10; i++) view.Add(10 + i);
+
+ view.View(3, 4).Reverse();
+ check();
+ Assert.IsTrue(IC.eq(view, 10, 11, 12, 16, 15, 14, 13, 17, 18, 19));
+ view.Reverse();
+ Assert.IsTrue(IC.eq(view, 19, 18, 17, 13, 14, 15, 16, 12, 11, 10));
+ Assert.IsTrue(IC.eq(list, 0, 19, 18, 17, 13, 14, 15, 16, 12, 11, 10, 3));
+ }
+
+
+ [Test]
+ public void Slide()
+ {
+ view.Slide(1);
+ check();
+ Assert.IsTrue(IC.eq(view, 2, 3));
+ view.Slide(-2);
+ check();
+ Assert.IsTrue(IC.eq(view, 0, 1));
+ view.Slide(0, 3);
+ check();
+ Assert.IsTrue(IC.eq(view, 0, 1, 2));
+ view.Slide(2, 1);
+ check();
+ Assert.IsTrue(IC.eq(view, 2));
+ view.Slide(-1, 0);
+ check();
+ Assert.IsTrue(IC.eq(view));
+ view.Add(28);
+ Assert.IsTrue(IC.eq(list, 0, 28, 1, 2, 3));
+ }
+ [Test]
+ public void Iterate()
+ {
+ list.Clear();
+ view = null;
+ foreach (int i in new int[] { 2, 4, 8, 13, 6, 1, 10, 11 }) list.Add(i);
+
+ view = (HashedArrayList<int>)list.View(list.Count - 2, 2);
+ int j = 666;
+ while (true)
+ {
+ //Console.WriteLine("View: {0}: {1} --> {2}", view.Count, view.First, view.Last);
+ if ((view.Last - view.First) % 2 == 1)
+ view.Insert(1, j++);
+ check();
+ if (view.Offset == 0)
+ break;
+ else
+ view.Slide(-1, 2);
+ }
+ //foreach (int cell in list) Console.Write(" " + cell);
+ //Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 2, 4, 8, 668, 13, 6, 1, 667, 10, 666, 11));
+ }
+
+
+ [Test]
+ public void SyncRoot()
+ {
+ Assert.AreSame(view.SyncRoot, list.SyncRoot);
+ }
+ }
+
+ [TestFixture]
+ public class MulipleViews
+ {
+ IList<int> list;
+ IList<int>[][] views;
+ [SetUp]
+ public void Init()
+ {
+ list = new HashedArrayList<int>();
+ for (int i = 0; i < 6; i++)
+ list.Add(i);
+ views = new IList<int>[7][];
+ for (int i = 0; i < 7; i++)
+ {
+ views[i] = new IList<int>[7 - i];
+ for (int j = 0; j < 7 - i; j++)
+ views[i][j] = list.View(i, j);
+ }
+ }
+ [TearDown]
+ public void Dispose()
+ {
+ list = null;
+ views = null;
+ }
+ [Test]
+ public void Insert()
+ {
+ Assert.IsTrue(list.Check(), "list check before insert");
+ list.Insert(3, 777);
+ Assert.IsTrue(list.Check(), "list check after insert");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i < 3 || (i == 3 && j == 0) ? i : i + 1, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(i < 3 && i + j > 3 ? j + 1 : j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+ [Test]
+ public void RemoveAt()
+ {
+ Assert.IsTrue(list.Check(), "list check before remove");
+ list.RemoveAt(3);
+ Assert.IsTrue(list.Check(), "list check after remove");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i <= 3 ? i : i - 1, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(i <= 3 && i + j > 3 ? j - 1 : j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+
+ [Test]
+ public void RemoveInterval()
+ {
+ Assert.IsTrue(list.Check(), "list check before remove");
+ list.RemoveInterval(3, 2);
+ Assert.IsTrue(list.Check(), "list check after remove");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i <= 3 ? i : i <= 5 ? 3 : i - 2, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(j == 0 ? 0 : i <= 3 && i + j > 4 ? j - 2 : i > 4 || i + j <= 3 ? j : j - 1, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+
+ [Test]
+ public void InsertAtEnd()
+ {
+ Assert.IsTrue(list.Check(), "list check before insert");
+ list.InsertLast(777);
+ Assert.IsTrue(list.Check(), "list check after insert");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+ [Test]
+ public void RemoveAtEnd()
+ {
+ Assert.IsTrue(list.Check(), "list check before remove");
+ list.RemoveAt(5);
+ Assert.IsTrue(list.Check(), "list check after remove");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i <= 5 ? i : i - 1, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(i <= 5 && i + j > 5 ? j - 1 : j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+ [Test]
+ public void InsertAtStart()
+ {
+ Assert.IsTrue(list.Check(), "list check before insert");
+ list.Insert(0, 777);
+ Assert.IsTrue(list.Check(), "list check after insert");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i == 0 && j == 0 ? 0 : i + 1, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+ [Test]
+ public void RemoveAtStart()
+ {
+ Assert.IsTrue(list.Check(), "list check before remove");
+ list.RemoveAt(0);
+ Assert.IsTrue(list.Check(), "list check after remove");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i == 0 ? i : i - 1, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(i == 0 && j > 0 ? j - 1 : j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+ [Test]
+ public void Clear()
+ {
+ Assert.IsTrue(list.Check(), "list check before clear");
+ //for (int i = 0; i < 7; i++)
+ //for (int j = 0; j < 7 - i; j++)
+ //Console.WriteLine("// view[{0}][{1}] : {2}", i, j, ((HashedArrayList<int>) views[i][j]).GetHashCode());
+ views[2][3].Clear();
+ Assert.IsTrue(list.Check(), "list check after clear");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i < 2 ? i : i < 6 ? 2 : i - 3, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(s(i, j), views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+
+ private int s(int i, int j)
+ {
+ if (j == 0) return 0;
+ int k = i + j - 1; //end
+ if (i > 4 || k <= 1) return j;
+ if (i >= 2) return k > 4 ? k - 4 : 0;
+ if (i <= 2) return k >= 4 ? j - 3 : 2 - i;
+ return -1;
+ }
+ [Test]
+ public void InsertAll()
+ {
+ IList<int> list2 = new HashedArrayList<int>();
+ for (int i = 0; i < 5; i++) { list2.Add(100 + i); }
+ Assert.IsTrue(list.Check(), "list check before insertAll");
+ list.InsertAll(3, list2);
+ Assert.IsTrue(list.Check(), "list check after insertAll");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i < 3 || (i == 3 && j == 0) ? i : i + 5, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(i < 3 && i + j > 3 ? j + 5 : j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+
+ [Test]
+ public void AddAll()
+ {
+ IList<int> list2 = new HashedArrayList<int>();
+ for (int i = 0; i < 5; i++) { list2.Add(100 + i); }
+ Assert.IsTrue(list.Check(), "list check before AddAll");
+ list.View(1, 2).AddAll(list2);
+ Assert.IsTrue(list.Check(), "list check after AddAll");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i < 3 || (i == 3 && j == 0) ? i : i + 5, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(i < 3 && i + j > 3 ? j + 5 : j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+
+ [Test]
+ public void Remove()
+ {
+ for (int i = 0; i < 7; i++)
+ {
+ for (int j = 0; j < 7 - i; j++)
+ {
+ list = new HashedArrayList<int>();
+ for (int k = 0; k < 6; k++) list.Add(k);
+ HashedArrayList<int> v = (HashedArrayList<int>)list.View(i, j);
+ list.Remove(3);
+ Assert.IsTrue(list.Check(), "list check after Remove, i=" + i + ", j=" + j);
+ }
+ }
+ }
+ [Test]
+ public void RemoveAll1()
+ {
+ IList<int> list2 = new HashedArrayList<int>();
+ list2.Add(1); list2.Add(3); list2.Add(4);
+
+ for (int i = 0; i < 7; i++)
+ {
+ for (int j = 0; j < 7 - i; j++)
+ {
+ list = new HashedArrayList<int>();
+ for (int k = 0; k < 6; k++) list.Add(k);
+ HashedArrayList<int> v = (HashedArrayList<int>)list.View(i, j);
+ list.RemoveAll(list2);
+ Assert.IsTrue(list.Check(), "list check after RemoveAll, i=" + i + ", j=" + j);
+ }
+ }
+ }
+ [Test]
+ public void RemoveAll2()
+ {
+ IList<int> list2 = new HashedArrayList<int>();
+ list2.Add(1); list2.Add(3); list2.Add(4);
+ Assert.IsTrue(list.Check(), "list check before RemoveAll");
+ list.RemoveAll(list2);
+
+ Assert.AreEqual(0, views[0][0].Offset, "view [0][0] offset");
+ Assert.AreEqual(0, views[0][1].Offset, "view [0][1] offset");
+ Assert.AreEqual(0, views[0][2].Offset, "view [0][2] offset");
+ Assert.AreEqual(0, views[0][3].Offset, "view [0][3] offset");
+ Assert.AreEqual(0, views[0][4].Offset, "view [0][4] offset");
+ Assert.AreEqual(0, views[0][5].Offset, "view [0][5] offset");
+ Assert.AreEqual(0, views[0][6].Offset, "view [0][6] offset");
+ Assert.AreEqual(1, views[1][0].Offset, "view [1][0] offset");
+ Assert.AreEqual(1, views[1][1].Offset, "view [1][1] offset");
+ Assert.AreEqual(1, views[1][2].Offset, "view [1][2] offset");
+ Assert.AreEqual(1, views[1][3].Offset, "view [1][3] offset");
+ Assert.AreEqual(1, views[1][4].Offset, "view [1][4] offset");
+ Assert.AreEqual(1, views[1][5].Offset, "view [1][5] offset");
+ Assert.AreEqual(1, views[2][0].Offset, "view [2][0] offset");
+ Assert.AreEqual(1, views[2][1].Offset, "view [2][1] offset");
+ Assert.AreEqual(1, views[2][2].Offset, "view [2][2] offset");
+ Assert.AreEqual(1, views[2][3].Offset, "view [2][3] offset");
+ Assert.AreEqual(1, views[2][4].Offset, "view [2][4] offset");
+ Assert.AreEqual(2, views[3][0].Offset, "view [3][0] offset");
+ Assert.AreEqual(2, views[3][1].Offset, "view [3][1] offset");
+ Assert.AreEqual(2, views[3][2].Offset, "view [3][2] offset");
+ Assert.AreEqual(2, views[3][3].Offset, "view [3][3] offset");
+ Assert.AreEqual(2, views[4][0].Offset, "view [4][0] offset");
+ Assert.AreEqual(2, views[4][1].Offset, "view [4][1] offset");
+ Assert.AreEqual(2, views[4][2].Offset, "view [4][2] offset");
+ Assert.AreEqual(2, views[5][0].Offset, "view [5][0] offset");
+ Assert.AreEqual(2, views[5][1].Offset, "view [5][1] offset");
+ Assert.AreEqual(3, views[6][0].Offset, "view [6][0] offset");
+
+ Assert.AreEqual(0, views[0][0].Count, "view [0][0] count");
+ Assert.AreEqual(1, views[0][1].Count, "view [0][1] count");
+ Assert.AreEqual(1, views[0][2].Count, "view [0][2] count");
+ Assert.AreEqual(2, views[0][3].Count, "view [0][3] count");
+ Assert.AreEqual(2, views[0][4].Count, "view [0][4] count");
+ Assert.AreEqual(2, views[0][5].Count, "view [0][5] count");
+ Assert.AreEqual(3, views[0][6].Count, "view [0][6] count");
+ Assert.AreEqual(0, views[1][0].Count, "view [1][0] count");
+ Assert.AreEqual(0, views[1][1].Count, "view [1][1] count");
+ Assert.AreEqual(1, views[1][2].Count, "view [1][2] count");
+ Assert.AreEqual(1, views[1][3].Count, "view [1][3] count");
+ Assert.AreEqual(1, views[1][4].Count, "view [1][4] count");
+ Assert.AreEqual(2, views[1][5].Count, "view [1][5] count");
+ Assert.AreEqual(0, views[2][0].Count, "view [2][0] count");
+ Assert.AreEqual(1, views[2][1].Count, "view [2][1] count");
+ Assert.AreEqual(1, views[2][2].Count, "view [2][2] count");
+ Assert.AreEqual(1, views[2][3].Count, "view [2][3] count");
+ Assert.AreEqual(2, views[2][4].Count, "view [2][4] count");
+ Assert.AreEqual(0, views[3][0].Count, "view [3][0] count");
+ Assert.AreEqual(0, views[3][1].Count, "view [3][1] count");
+ Assert.AreEqual(0, views[3][2].Count, "view [3][2] count");
+ Assert.AreEqual(1, views[3][3].Count, "view [3][3] count");
+ Assert.AreEqual(0, views[4][0].Count, "view [4][0] count");
+ Assert.AreEqual(0, views[4][1].Count, "view [4][1] count");
+ Assert.AreEqual(1, views[4][2].Count, "view [4][2] count");
+ Assert.AreEqual(0, views[5][0].Count, "view [5][0] count");
+ Assert.AreEqual(1, views[5][1].Count, "view [5][1] count");
+ Assert.AreEqual(0, views[6][0].Count, "view [6][0] count");
+
+ Assert.IsTrue(list.Check(), "list check after RemoveAll");
+ }
+
+ [Test]
+ public void RetainAll()
+ {
+ IList<int> list2 = new HashedArrayList<int>();
+ list2.Add(2); list2.Add(4); list2.Add(5);
+ Assert.IsTrue(list.Check(), "list check before RetainAll");
+ list.RetainAll(list2);
+ Assert.AreEqual(0, views[0][0].Offset, "view [0][0] offset");
+ Assert.AreEqual(0, views[0][1].Offset, "view [0][1] offset");
+ Assert.AreEqual(0, views[0][2].Offset, "view [0][2] offset");
+ Assert.AreEqual(0, views[0][3].Offset, "view [0][3] offset");
+ Assert.AreEqual(0, views[0][4].Offset, "view [0][4] offset");
+ Assert.AreEqual(0, views[0][5].Offset, "view [0][5] offset");
+ Assert.AreEqual(0, views[0][6].Offset, "view [0][6] offset");
+ Assert.AreEqual(0, views[1][0].Offset, "view [1][0] offset");
+ Assert.AreEqual(0, views[1][1].Offset, "view [1][1] offset");
+ Assert.AreEqual(0, views[1][2].Offset, "view [1][2] offset");
+ Assert.AreEqual(0, views[1][3].Offset, "view [1][3] offset");
+ Assert.AreEqual(0, views[1][4].Offset, "view [1][4] offset");
+ Assert.AreEqual(0, views[1][5].Offset, "view [1][5] offset");
+ Assert.AreEqual(0, views[2][0].Offset, "view [2][0] offset");
+ Assert.AreEqual(0, views[2][1].Offset, "view [2][1] offset");
+ Assert.AreEqual(0, views[2][2].Offset, "view [2][2] offset");
+ Assert.AreEqual(0, views[2][3].Offset, "view [2][3] offset");
+ Assert.AreEqual(0, views[2][4].Offset, "view [2][4] offset");
+ Assert.AreEqual(1, views[3][0].Offset, "view [3][0] offset");
+ Assert.AreEqual(1, views[3][1].Offset, "view [3][1] offset");
+ Assert.AreEqual(1, views[3][2].Offset, "view [3][2] offset");
+ Assert.AreEqual(1, views[3][3].Offset, "view [3][3] offset");
+ Assert.AreEqual(1, views[4][0].Offset, "view [4][0] offset");
+ Assert.AreEqual(1, views[4][1].Offset, "view [4][1] offset");
+ Assert.AreEqual(1, views[4][2].Offset, "view [4][2] offset");
+ Assert.AreEqual(2, views[5][0].Offset, "view [5][0] offset");
+ Assert.AreEqual(2, views[5][1].Offset, "view [5][1] offset");
+ Assert.AreEqual(3, views[6][0].Offset, "view [6][0] offset");
+
+ Assert.AreEqual(0, views[0][0].Count, "view [0][0] count");
+ Assert.AreEqual(0, views[0][1].Count, "view [0][1] count");
+ Assert.AreEqual(0, views[0][2].Count, "view [0][2] count");
+ Assert.AreEqual(1, views[0][3].Count, "view [0][3] count");
+ Assert.AreEqual(1, views[0][4].Count, "view [0][4] count");
+ Assert.AreEqual(2, views[0][5].Count, "view [0][5] count");
+ Assert.AreEqual(3, views[0][6].Count, "view [0][6] count");
+ Assert.AreEqual(0, views[1][0].Count, "view [1][0] count");
+ Assert.AreEqual(0, views[1][1].Count, "view [1][1] count");
+ Assert.AreEqual(1, views[1][2].Count, "view [1][2] count");
+ Assert.AreEqual(1, views[1][3].Count, "view [1][3] count");
+ Assert.AreEqual(2, views[1][4].Count, "view [1][4] count");
+ Assert.AreEqual(3, views[1][5].Count, "view [1][5] count");
+ Assert.AreEqual(0, views[2][0].Count, "view [2][0] count");
+ Assert.AreEqual(1, views[2][1].Count, "view [2][1] count");
+ Assert.AreEqual(1, views[2][2].Count, "view [2][2] count");
+ Assert.AreEqual(2, views[2][3].Count, "view [2][3] count");
+ Assert.AreEqual(3, views[2][4].Count, "view [2][4] count");
+ Assert.AreEqual(0, views[3][0].Count, "view [3][0] count");
+ Assert.AreEqual(0, views[3][1].Count, "view [3][1] count");
+ Assert.AreEqual(1, views[3][2].Count, "view [3][2] count");
+ Assert.AreEqual(2, views[3][3].Count, "view [3][3] count");
+ Assert.AreEqual(0, views[4][0].Count, "view [4][0] count");
+ Assert.AreEqual(1, views[4][1].Count, "view [4][1] count");
+ Assert.AreEqual(2, views[4][2].Count, "view [4][2] count");
+ Assert.AreEqual(0, views[5][0].Count, "view [5][0] count");
+ Assert.AreEqual(1, views[5][1].Count, "view [5][1] count");
+ Assert.AreEqual(0, views[6][0].Count, "view [6][0] count");
+
+ Assert.IsTrue(list.Check(), "list check after RetainAll");
+ }
+
+ [Test]
+ public void RemoveAllCopies()
+ {
+ IList<int> list2 = new HashedArrayList<int>();
+ list2.Add(0); list2.Add(2); list2.Add(82); list2.Add(92); list2.Add(5); list2.Add(2); list2.Add(1);
+ for (int i = 0; i < 7; i++)
+ {
+ for (int j = 0; j < 7 - i; j++)
+ {
+ list = new HashedArrayList<int>();
+ list.AddAll(list2);
+ HashedArrayList<int> v = (HashedArrayList<int>)list.View(i, j);
+ list.RemoveAllCopies(2);
+ Assert.IsTrue(list.Check(), "list check after RemoveAllCopies, i=" + i + ", j=" + j);
+ }
+ }
+ }
+
+ private void checkDisposed(bool reverse, int start, int count)
+ {
+ int k = 0;
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ if (i + j <= start || i >= start + count || (i <= start && i + j >= start + count) || (reverse && start <= i && start + count >= i + j))
+ {
+ try
+ {
+ k = views[i][j].Count;
+ }
+ catch (ViewDisposedException)
+ {
+ Assert.Fail("view[" + i + "][" + j + "] threw");
+ }
+ Assert.AreEqual(j, views[i][j].Count, "view[" + i + "][" + j + "] size");
+ if (reverse && ((j > 0 && start <= i && start + count >= i + j) || (j == 0 && start < i && start + count > i)))
+ Assert.AreEqual(start + (start + count - i - j), views[i][j].Offset, "view[" + i + "][" + j + "] offset (mirrored)");
+ else
+ Assert.AreEqual(i, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ }
+ else
+ {
+ try
+ {
+ k = views[i][j].Count;
+ Assert.Fail("view[" + i + "][" + j + "] no throw");
+ }
+ catch (ViewDisposedException) { }
+ }
+ }
+ }
+
+ [Test]
+ public void Reverse()
+ {
+ int start = 2, count = 3;
+ IList<int> list2 = list.View(start, count);
+ Assert.IsTrue(list.Check(), "list check before Reverse");
+ list2.Reverse();
+ Assert.IsTrue(list.Check(), "list check after Reverse");
+ checkDisposed(true, start, count);
+ }
+
+ [Test]
+ public void Sort()
+ {
+ int start = 2, count = 3;
+ IList<int> list2 = list.View(start, count);
+ Assert.IsTrue(list.Check(), "list check before Sort");
+ list2.Sort();
+ Assert.IsTrue(list.Check(), "list check after Sort");
+ checkDisposed(false, start, count);
+ }
+ [Test]
+ public void Shuffle()
+ {
+ int start = 2, count = 3;
+ IList<int> list2 = list.View(start, count);
+ Assert.IsTrue(list.Check(), "list check before Shuffle");
+ list2.Shuffle();
+ Assert.IsTrue(list.Check(), "list check after Shuffle");
+ checkDisposed(false, start, count);
+ }
+
+
+ }
+
+ }
+
+ namespace HashingAndEquals
+ {
+ [TestFixture]
+ public class IIndexed
+ {
+ private ISequenced<int> dit, dat, dut;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new HashedArrayList<int>();
+ dat = new HashedArrayList<int>();
+ dut = new HashedArrayList<int>();
+ }
+
+
+ [Test]
+ public void EmptyEmpty()
+ {
+ Assert.IsTrue(dit.SequencedEquals(dat));
+ }
+
+
+ [Test]
+ public void EmptyNonEmpty()
+ {
+ dit.Add(3);
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ Assert.IsFalse(dat.SequencedEquals(dit));
+ }
+
+ [Test]
+ public void HashVal()
+ {
+ Assert.AreEqual(CHC.sequencedhashcode(), dit.GetSequencedHashCode());
+ dit.Add(3);
+ Assert.AreEqual(CHC.sequencedhashcode(3), dit.GetSequencedHashCode());
+ dit.Add(7);
+ Assert.AreEqual(CHC.sequencedhashcode(3, 7), dit.GetSequencedHashCode());
+ Assert.AreEqual(CHC.sequencedhashcode(), dut.GetSequencedHashCode());
+ dut.Add(7);
+ Assert.AreEqual(CHC.sequencedhashcode(7), dut.GetSequencedHashCode());
+ dut.Add(3);
+ Assert.AreEqual(CHC.sequencedhashcode(7, 3), dut.GetSequencedHashCode());
+ }
+
+
+ [Test]
+ public void EqualHashButDifferent()
+ {
+ dit.Add(0); dit.Add(31);
+ dat.Add(1); dat.Add(0);
+ Assert.AreEqual(dit.GetSequencedHashCode(), dat.GetSequencedHashCode());
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ }
+
+
+ [Test]
+ public void Normal()
+ {
+ dit.Add(3);
+ dit.Add(7);
+ dat.Add(3);
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ Assert.IsFalse(dat.SequencedEquals(dit));
+ dat.Add(7);
+ Assert.IsTrue(dit.SequencedEquals(dat));
+ Assert.IsTrue(dat.SequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void WrongOrder()
+ {
+ dit.Add(3);
+ dut.Add(3);
+ Assert.IsTrue(dit.SequencedEquals(dut));
+ Assert.IsTrue(dut.SequencedEquals(dit));
+ dit.Add(7);
+ ((HashedArrayList<int>)dut).InsertFirst(7);
+ Assert.IsFalse(dit.SequencedEquals(dut));
+ Assert.IsFalse(dut.SequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void Reflexive()
+ {
+ Assert.IsTrue(dit.SequencedEquals(dit));
+ dit.Add(3);
+ Assert.IsTrue(dit.SequencedEquals(dit));
+ dit.Add(7);
+ Assert.IsTrue(dit.SequencedEquals(dit));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = null;
+ dat = null;
+ dut = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class IEditableCollection
+ {
+ private ICollection<int> dit, dat, dut;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new HashedArrayList<int>();
+ dat = new HashedArrayList<int>();
+ dut = new HashedArrayList<int>();
+ }
+
+
+ [Test]
+ public void EmptyEmpty()
+ {
+ Assert.IsTrue(dit.UnsequencedEquals(dat));
+ }
+
+
+ [Test]
+ public void EmptyNonEmpty()
+ {
+ dit.Add(3);
+ Assert.IsFalse(dit.UnsequencedEquals(dat));
+ Assert.IsFalse(dat.UnsequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void HashVal()
+ {
+ Assert.AreEqual(CHC.unsequencedhashcode(), dit.GetUnsequencedHashCode());
+ dit.Add(3);
+ Assert.AreEqual(CHC.unsequencedhashcode(3), dit.GetUnsequencedHashCode());
+ dit.Add(7);
+ Assert.AreEqual(CHC.unsequencedhashcode(3, 7), dit.GetUnsequencedHashCode());
+ Assert.AreEqual(CHC.unsequencedhashcode(), dut.GetUnsequencedHashCode());
+ dut.Add(3);
+ Assert.AreEqual(CHC.unsequencedhashcode(3), dut.GetUnsequencedHashCode());
+ dut.Add(7);
+ Assert.AreEqual(CHC.unsequencedhashcode(7, 3), dut.GetUnsequencedHashCode());
+ }
+
+
+ [Test]
+ public void EqualHashButDifferent()
+ {
+ dit.Add(-1657792980); dit.Add(-1570288808);
+ dat.Add(1862883298); dat.Add(-272461342);
+ Assert.AreEqual(dit.GetUnsequencedHashCode(), dat.GetUnsequencedHashCode());
+ Assert.IsFalse(dit.UnsequencedEquals(dat));
+ }
+
+
+ [Test]
+ public void Normal()
+ {
+ dit.Add(3);
+ dit.Add(7);
+ dat.Add(3);
+ Assert.IsFalse(dit.UnsequencedEquals(dat));
+ Assert.IsFalse(dat.UnsequencedEquals(dit));
+ dat.Add(7);
+ Assert.IsTrue(dit.UnsequencedEquals(dat));
+ Assert.IsTrue(dat.UnsequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void WrongOrder()
+ {
+ dit.Add(3);
+ dut.Add(3);
+ Assert.IsTrue(dit.UnsequencedEquals(dut));
+ Assert.IsTrue(dut.UnsequencedEquals(dit));
+ dit.Add(7);
+ dut.Add(7);
+ Assert.IsTrue(dit.UnsequencedEquals(dut));
+ Assert.IsTrue(dut.UnsequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void Reflexive()
+ {
+ Assert.IsTrue(dit.UnsequencedEquals(dit));
+ dit.Add(3);
+ Assert.IsTrue(dit.UnsequencedEquals(dit));
+ dit.Add(7);
+ Assert.IsTrue(dit.UnsequencedEquals(dit));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = null;
+ dat = null;
+ dut = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class MultiLevelUnorderedOfUnOrdered
+ {
+ private ICollection<int> dit, dat, dut;
+
+ private ICollection<ICollection<int>> Dit, Dat, Dut;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new HashedArrayList<int>();
+ dat = new HashedArrayList<int>();
+ dut = new HashedArrayList<int>();
+ dit.Add(2); dit.Add(1);
+ dat.Add(1); dat.Add(2);
+ dut.Add(3);
+ Dit = new HashedArrayList<ICollection<int>>();
+ Dat = new HashedArrayList<ICollection<int>>();
+ Dut = new HashedArrayList<ICollection<int>>();
+ }
+
+
+ [Test]
+ public void Check()
+ {
+ Assert.IsTrue(dit.UnsequencedEquals(dat));
+ Assert.IsFalse(dit.UnsequencedEquals(dut));
+ }
+
+
+ [Test]
+ public void Multi()
+ {
+ Dit.Add(dit); Dit.Add(dut); Dit.Add(dit);
+ Dat.Add(dut); Dat.Add(dit); Dat.Add(dat);
+ Assert.IsTrue(Dit.UnsequencedEquals(Dat));
+ Assert.IsFalse(Dit.UnsequencedEquals(Dut));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = dat = dut = null;
+ Dit = Dat = Dut = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class MultiLevelOrderedOfUnOrdered
+ {
+ private ICollection<int> dit, dat, dut;
+
+ private ISequenced<ICollection<int>> Dit, Dat, Dut;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new HashedArrayList<int>();
+ dat = new HashedArrayList<int>();
+ dut = new HashedArrayList<int>();
+ dit.Add(2); dit.Add(1);
+ dat.Add(1); dat.Add(2);
+ dut.Add(3);
+ Dit = new HashedArrayList<ICollection<int>>();
+ Dat = new HashedArrayList<ICollection<int>>();
+ Dut = new HashedArrayList<ICollection<int>>();
+ }
+
+
+ [Test]
+ public void Check()
+ {
+ Assert.IsTrue(dit.UnsequencedEquals(dat));
+ Assert.IsFalse(dit.UnsequencedEquals(dut));
+ }
+
+
+ [Test]
+ public void Multi()
+ {
+ Dit.Add(dit); Dit.Add(dut); Dit.Add(dit);
+ Dat.Add(dut); Dat.Add(dit); Dat.Add(dat);
+ Dut.Add(dit); Dut.Add(dut); Dut.Add(dat);
+ Assert.IsFalse(Dit.SequencedEquals(Dat));
+ Assert.IsTrue(Dit.SequencedEquals(Dut));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = dat = dut = null;
+ Dit = Dat = Dut = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class MultiLevelUnOrderedOfOrdered
+ {
+ private ISequenced<int> dit, dat, dut, dot;
+
+ private ICollection<ISequenced<int>> Dit, Dat, Dut, Dot;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new HashedArrayList<int>();
+ dat = new HashedArrayList<int>();
+ dut = new HashedArrayList<int>();
+ dot = new HashedArrayList<int>();
+ dit.Add(2); dit.Add(1);
+ dat.Add(1); dat.Add(2);
+ dut.Add(3);
+ dot.Add(2); dot.Add(1);
+ Dit = new HashedArrayList<ISequenced<int>>();
+ Dat = new HashedArrayList<ISequenced<int>>();
+ Dut = new HashedArrayList<ISequenced<int>>();
+ Dot = new HashedArrayList<ISequenced<int>>();
+ }
+
+
+ [Test]
+ public void Check()
+ {
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ Assert.IsTrue(dit.SequencedEquals(dot));
+ Assert.IsFalse(dit.SequencedEquals(dut));
+ }
+
+
+ [Test]
+ public void Multi()
+ {
+ Dit.Add(dit); Dit.Add(dut); Dit.Add(dit);
+ Dat.Add(dut); Dat.Add(dit); Dat.Add(dat);
+ Dut.Add(dot); Dut.Add(dut); Dut.Add(dit);
+ Dot.Add(dit); Dot.Add(dit); Dot.Add(dut);
+ Assert.IsTrue(Dit.UnsequencedEquals(Dut));
+ Assert.IsFalse(Dit.UnsequencedEquals(Dat));
+ Assert.IsTrue(Dit.UnsequencedEquals(Dot));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = dat = dut = dot = null;
+ Dit = Dat = Dut = Dot = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class MultiLevelOrderedOfOrdered
+ {
+ private ISequenced<int> dit, dat, dut, dot;
+
+ private ISequenced<ISequenced<int>> Dit, Dat, Dut, Dot;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new HashedArrayList<int>();
+ dat = new HashedArrayList<int>();
+ dut = new HashedArrayList<int>();
+ dot = new HashedArrayList<int>();
+ dit.Add(2); dit.Add(1); //{2,1}
+ dat.Add(1); dat.Add(2); //{1,2}
+ dut.Add(3); //{3}
+ dot.Add(2); dot.Add(1); //{2,1}
+ Dit = new HashedArrayList<ISequenced<int>>();
+ Dat = new HashedArrayList<ISequenced<int>>();
+ Dut = new HashedArrayList<ISequenced<int>>();
+ Dot = new HashedArrayList<ISequenced<int>>();
+ }
+
+
+ [Test]
+ public void Check()
+ {
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ Assert.IsTrue(dit.SequencedEquals(dot));
+ Assert.IsFalse(dit.SequencedEquals(dut));
+ }
+
+
+ [Test]
+ public void Multi()
+ {
+ Dit.Add(dit); Dit.Add(dut); Dit.Add(dit); // {{2,1},{3}}
+ Dat.Add(dut); Dat.Add(dit); Dat.Add(dat); // {{3},{2,1},{1,2}}
+ Dut.Add(dot); Dut.Add(dut); Dut.Add(dit); // {{2,1},{3}}
+ Dot.Add(dit); Dot.Add(dit); Dot.Add(dut); // {{2,1},{3}}
+ Assert.IsTrue(Dit.SequencedEquals(Dut));
+ Assert.IsFalse(Dit.SequencedEquals(Dat));
+ Assert.IsTrue(Dit.SequencedEquals(Dot));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = dat = dut = dot = null;
+ Dit = Dat = Dut = Dot = null;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/1.0/Test/arrays/SortedArrayTests.cs b/mcs/class/Mono.C5/1.0/Test/arrays/SortedArrayTests.cs
new file mode 100644
index 00000000000..4cc4e1a2d64
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/Test/arrays/SortedArrayTests.cs
@@ -0,0 +1,2356 @@
+/*
+ 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 C5;
+using NUnit.Framework;
+using SCG = System.Collections.Generic;
+
+namespace C5UnitTests.arrays.sorted
+{
+ using CollectionOfInt = SortedArray<int>;
+
+ [TestFixture]
+ public class GenericTesters
+ {
+ [Test]
+ public void TestEvents()
+ {
+ Fun<CollectionOfInt> factory = delegate() { return new CollectionOfInt(TenEqualityComparer.Default); };
+ new C5UnitTests.Templates.Events.SortedIndexedTester<CollectionOfInt>().Test(factory);
+ }
+
+ [Test]
+ public void Extensible()
+ {
+ C5UnitTests.Templates.Extensible.Clone.Tester<CollectionOfInt>();
+ C5UnitTests.Templates.Extensible.Serialization.Tester<CollectionOfInt>();
+ }
+ }
+
+ static class Factory
+ {
+ public static ICollection<T> New<T>() { return new SortedArray<T>(); }
+ }
+
+
+ [TestFixture]
+ public class Formatting
+ {
+ ICollection<int> coll;
+ IFormatProvider rad16;
+ [SetUp]
+ public void Init() { coll = Factory.New<int>(); rad16 = new RadixFormatProvider(16); }
+ [TearDown]
+ public void Dispose() { coll = null; rad16 = null; }
+ [Test]
+ public void Format()
+ {
+ Assert.AreEqual("{ }", coll.ToString());
+ coll.AddAll<int>(new int[] { -4, 28, 129, 65530 });
+ Assert.AreEqual("{ -4, 28, 129, 65530 }", coll.ToString());
+ Assert.AreEqual("{ -4, 1C, 81, FFFA }", coll.ToString(null, rad16));
+ Assert.AreEqual("{ -4, 28, 129... }", coll.ToString("L14", null));
+ Assert.AreEqual("{ -4, 1C, 81... }", coll.ToString("L14", rad16));
+ }
+ }
+
+ [TestFixture]
+ public class Ranges
+ {
+ private SortedArray<int> array;
+
+ private SCG.IComparer<int> c;
+
+
+ [SetUp]
+ public void Init()
+ {
+ c = new IC();
+ array = new SortedArray<int>(c);
+ for (int i = 1; i <= 10; i++)
+ {
+ array.Add(i * 2);
+ }
+ }
+
+
+ [Test]
+ public void Enumerator()
+ {
+ SCG.IEnumerator<int> e = array.RangeFromTo(5, 17).GetEnumerator();
+ int i = 3;
+
+ while (e.MoveNext())
+ {
+ Assert.AreEqual(2 * i++, e.Current);
+ }
+
+ Assert.AreEqual(9, i);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void Enumerator3()
+ {
+ SCG.IEnumerator<int> e = array.RangeFromTo(5, 17).GetEnumerator();
+
+ e.MoveNext();
+ array.Add(67);
+ e.MoveNext();
+ }
+
+
+ [Test]
+ public void Remove()
+ {
+ int[] all = new int[] { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 };
+
+ array.RemoveRangeFrom(18);
+ Assert.IsTrue(IC.eq(array, new int[] { 2, 4, 6, 8, 10, 12, 14, 16 }));
+ array.RemoveRangeFrom(28);
+ Assert.IsTrue(IC.eq(array, new int[] { 2, 4, 6, 8, 10, 12, 14, 16 }));
+ array.RemoveRangeFrom(13);
+ Assert.IsTrue(IC.eq(array, new int[] { 2, 4, 6, 8, 10, 12 }));
+ array.RemoveRangeFrom(2);
+ Assert.IsTrue(IC.eq(array));
+ foreach (int i in all) array.Add(i);
+
+ array.RemoveRangeTo(10);
+ Assert.IsTrue(IC.eq(array, new int[] { 10, 12, 14, 16, 18, 20 }));
+ array.RemoveRangeTo(2);
+ Assert.IsTrue(IC.eq(array, new int[] { 10, 12, 14, 16, 18, 20 }));
+ array.RemoveRangeTo(21);
+ Assert.IsTrue(IC.eq(array));
+ foreach (int i in all) array.Add(i);
+
+ array.RemoveRangeFromTo(4, 8);
+ Assert.IsTrue(IC.eq(array, 2, 8, 10, 12, 14, 16, 18, 20));
+ array.RemoveRangeFromTo(14, 28);
+ Assert.IsTrue(IC.eq(array, 2, 8, 10, 12));
+ array.RemoveRangeFromTo(0, 9);
+ Assert.IsTrue(IC.eq(array, 10, 12));
+ array.RemoveRangeFromTo(0, 81);
+ Assert.IsTrue(IC.eq(array));
+ }
+
+ [Test]
+ public void Normal()
+ {
+ int[] all = new int[] { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 };
+
+ Assert.IsTrue(IC.eq(array, all));
+ Assert.IsTrue(IC.eq(array.RangeAll(), all));
+ Assert.AreEqual(10, array.RangeAll().Count);
+ Assert.IsTrue(IC.eq(array.RangeFrom(11), new int[] { 12, 14, 16, 18, 20 }));
+ Assert.AreEqual(5, array.RangeFrom(11).Count);
+ Assert.IsTrue(IC.eq(array.RangeFrom(12), new int[] { 12, 14, 16, 18, 20 }));
+ Assert.IsTrue(IC.eq(array.RangeFrom(2), all));
+ Assert.IsTrue(IC.eq(array.RangeFrom(1), all));
+ Assert.IsTrue(IC.eq(array.RangeFrom(21), new int[] { }));
+ Assert.IsTrue(IC.eq(array.RangeFrom(20), new int[] { 20 }));
+ Assert.IsTrue(IC.eq(array.RangeTo(8), new int[] { 2, 4, 6 }));
+ Assert.IsTrue(IC.eq(array.RangeTo(7), new int[] { 2, 4, 6 }));
+ Assert.AreEqual(3, array.RangeTo(7).Count);
+ Assert.IsTrue(IC.eq(array.RangeTo(2), new int[] { }));
+ Assert.IsTrue(IC.eq(array.RangeTo(1), new int[] { }));
+ Assert.IsTrue(IC.eq(array.RangeTo(3), new int[] { 2 }));
+ Assert.IsTrue(IC.eq(array.RangeTo(20), new int[] { 2, 4, 6, 8, 10, 12, 14, 16, 18 }));
+ Assert.IsTrue(IC.eq(array.RangeTo(21), all));
+ Assert.IsTrue(IC.eq(array.RangeFromTo(7, 12), new int[] { 8, 10 }));
+ Assert.IsTrue(IC.eq(array.RangeFromTo(6, 11), new int[] { 6, 8, 10 }));
+ Assert.IsTrue(IC.eq(array.RangeFromTo(1, 12), new int[] { 2, 4, 6, 8, 10 }));
+ Assert.AreEqual(5, array.RangeFromTo(1, 12).Count);
+ Assert.IsTrue(IC.eq(array.RangeFromTo(2, 12), new int[] { 2, 4, 6, 8, 10 }));
+ Assert.IsTrue(IC.eq(array.RangeFromTo(6, 21), new int[] { 6, 8, 10, 12, 14, 16, 18, 20 }));
+ Assert.IsTrue(IC.eq(array.RangeFromTo(6, 20), new int[] { 6, 8, 10, 12, 14, 16, 18 }));
+ }
+
+
+ [Test]
+ public void Backwards()
+ {
+ int[] all = new int[] { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 };
+ int[] lla = new int[] { 20, 18, 16, 14, 12, 10, 8, 6, 4, 2 };
+
+ Assert.IsTrue(IC.eq(array, all));
+ Assert.IsTrue(IC.eq(array.RangeAll().Backwards(), lla));
+ Assert.IsTrue(IC.eq(array.RangeFrom(11).Backwards(), new int[] { 20, 18, 16, 14, 12 }));
+ Assert.IsTrue(IC.eq(array.RangeFrom(12).Backwards(), new int[] { 20, 18, 16, 14, 12 }));
+ Assert.IsTrue(IC.eq(array.RangeFrom(2).Backwards(), lla));
+ Assert.IsTrue(IC.eq(array.RangeFrom(1).Backwards(), lla));
+ Assert.IsTrue(IC.eq(array.RangeFrom(21).Backwards(), new int[] { }));
+ Assert.IsTrue(IC.eq(array.RangeFrom(20).Backwards(), new int[] { 20 }));
+ Assert.IsTrue(IC.eq(array.RangeTo(8).Backwards(), new int[] { 6, 4, 2 }));
+ Assert.IsTrue(IC.eq(array.RangeTo(7).Backwards(), new int[] { 6, 4, 2 }));
+ Assert.IsTrue(IC.eq(array.RangeTo(2).Backwards(), new int[] { }));
+ Assert.IsTrue(IC.eq(array.RangeTo(1).Backwards(), new int[] { }));
+ Assert.IsTrue(IC.eq(array.RangeTo(3).Backwards(), new int[] { 2 }));
+ Assert.IsTrue(IC.eq(array.RangeTo(20).Backwards(), new int[] { 18, 16, 14, 12, 10, 8, 6, 4, 2}));
+ Assert.IsTrue(IC.eq(array.RangeTo(21).Backwards(), lla));
+ Assert.IsTrue(IC.eq(array.RangeFromTo(7, 12).Backwards(), new int[] { 10, 8 }));
+ Assert.IsTrue(IC.eq(array.RangeFromTo(6, 11).Backwards(), new int[] { 10, 8, 6 }));
+ Assert.IsTrue(IC.eq(array.RangeFromTo(1, 12).Backwards(), new int[] { 10, 8, 6, 4, 2 }));
+ Assert.IsTrue(IC.eq(array.RangeFromTo(2, 12).Backwards(), new int[] { 10, 8, 6, 4, 2 }));
+ Assert.IsTrue(IC.eq(array.RangeFromTo(6, 21).Backwards(), new int[] { 20, 18, 16, 14, 12, 10, 8, 6 }));
+ Assert.IsTrue(IC.eq(array.RangeFromTo(6, 20).Backwards(), new int[] { 18, 16, 14, 12, 10, 8, 6 }));
+ }
+
+ [Test]
+ public void Direction()
+ {
+ Assert.AreEqual(EnumerationDirection.Forwards, array.Direction);
+ Assert.AreEqual(EnumerationDirection.Forwards, array.RangeFrom(20).Direction);
+ Assert.AreEqual(EnumerationDirection.Forwards, array.RangeTo(7).Direction);
+ Assert.AreEqual(EnumerationDirection.Forwards, array.RangeFromTo(1, 12).Direction);
+ Assert.AreEqual(EnumerationDirection.Forwards, array.RangeAll().Direction);
+ Assert.AreEqual(EnumerationDirection.Backwards, array.Backwards().Direction);
+ Assert.AreEqual(EnumerationDirection.Backwards, array.RangeFrom(20).Backwards().Direction);
+ Assert.AreEqual(EnumerationDirection.Backwards, array.RangeTo(7).Backwards().Direction);
+ Assert.AreEqual(EnumerationDirection.Backwards, array.RangeFromTo(1, 12).Backwards().Direction);
+ Assert.AreEqual(EnumerationDirection.Backwards, array.RangeAll().Backwards().Direction);
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ array = null;
+ c = null;
+ }
+ }
+
+ [TestFixture]
+ public class BagItf
+ {
+ private SortedArray<int> array;
+
+
+ [SetUp]
+ public void Init()
+ {
+ array = new SortedArray<int>(new IC());
+ for (int i = 10; i < 20; i++)
+ {
+ array.Add(i);
+ array.Add(i + 10);
+ }
+ }
+
+
+ [Test]
+ public void Both()
+ {
+ Assert.AreEqual(0, array.ContainsCount(7));
+ Assert.AreEqual(1, array.ContainsCount(10));
+ array.RemoveAllCopies(10);
+ Assert.AreEqual(0, array.ContainsCount(10));
+ array.RemoveAllCopies(7);
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ array = null;
+ }
+ }
+
+
+ [TestFixture]
+ public class Div
+ {
+ private SortedArray<int> array;
+
+
+ [SetUp]
+ public void Init()
+ {
+ array = new SortedArray<int>(new IC());
+ }
+
+ [Test]
+ [ExpectedException(typeof(NullReferenceException))]
+ public void NullEqualityComparerinConstructor1()
+ {
+ new SortedArray<int>(null);
+ }
+
+ [Test]
+ [ExpectedException(typeof(NullReferenceException))]
+ public void NullEqualityComparerinConstructor2()
+ {
+ new SortedArray<int>(5, null);
+ }
+
+ [Test]
+ [ExpectedException(typeof(NullReferenceException))]
+ public void NullEqualityComparerinConstructor3()
+ {
+ new SortedArray<int>(5, null, EqualityComparer<int>.Default);
+ }
+
+ [Test]
+ [ExpectedException(typeof(NullReferenceException))]
+ public void NullEqualityComparerinConstructor4()
+ {
+ new SortedArray<int>(5, Comparer<int>.Default, null);
+ }
+
+ [Test]
+ [ExpectedException(typeof(NullReferenceException))]
+ public void NullEqualityComparerinConstructor5()
+ {
+ new SortedArray<int>(5, null, null);
+ }
+
+ [Test]
+ public void Choose()
+ {
+ array.Add(7);
+ Assert.AreEqual(7, array.Choose());
+ }
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void BadChoose()
+ {
+ array.Choose();
+ }
+
+
+
+ private void loadup()
+ {
+ for (int i = 10; i < 20; i++)
+ {
+ array.Add(i);
+ array.Add(i + 10);
+ }
+ }
+
+
+ [Test]
+ public void NoDuplicatesEtc()
+ {
+ Assert.IsFalse(array.AllowsDuplicates);
+ loadup();
+ Assert.IsFalse(array.AllowsDuplicates);
+ Assert.AreEqual(Speed.Log, array.ContainsSpeed);
+ Assert.IsTrue(array.Comparer.Compare(2, 3) < 0);
+ Assert.IsTrue(array.Comparer.Compare(4, 3) > 0);
+ Assert.IsTrue(array.Comparer.Compare(3, 3) == 0);
+ }
+
+ [Test]
+ public void Add()
+ {
+ Assert.IsTrue(array.Add(17));
+ Assert.IsFalse(array.Add(17));
+ Assert.IsTrue(array.Add(18));
+ Assert.IsFalse(array.Add(18));
+ Assert.AreEqual(2, array.Count);
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ array = null;
+ }
+ }
+
+
+ [TestFixture]
+ public class FindOrAdd
+ {
+ private SortedArray<KeyValuePair<int,string>> bag;
+
+
+ [SetUp]
+ public void Init()
+ {
+ bag = new SortedArray<KeyValuePair<int,string>>(new KeyValuePairComparer<int,string>(new IC()));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ bag = null;
+ }
+
+
+ [Test]
+ public void Test()
+ {
+ KeyValuePair<int,string> p = new KeyValuePair<int,string>(3, "tre");
+
+ Assert.IsFalse(bag.FindOrAdd(ref p));
+ p.Value = "drei";
+ Assert.IsTrue(bag.FindOrAdd(ref p));
+ Assert.AreEqual("tre", p.Value);
+ p.Value = "three";
+ Assert.AreEqual(1, bag.ContainsCount(p));
+ Assert.AreEqual("tre", bag[0].Value);
+ }
+ }
+
+ [TestFixture]
+ public class FindPredicate
+ {
+ private SortedArray<int> list;
+ Fun<int, bool> pred;
+
+ [SetUp]
+ public void Init()
+ {
+ list = new SortedArray<int>(TenEqualityComparer.Default);
+ pred = delegate(int i) { return i % 5 == 0; };
+ }
+
+ [TearDown]
+ public void Dispose() { list = null; }
+
+ [Test]
+ public void Find()
+ {
+ int i;
+ Assert.IsFalse(list.Find(pred, out i));
+ list.AddAll<int>(new int[] { 4, 22, 67, 37 });
+ Assert.IsFalse(list.Find(pred, out i));
+ list.AddAll<int>(new int[] { 45, 122, 675, 137 });
+ Assert.IsTrue(list.Find(pred, out i));
+ Assert.AreEqual(45, i);
+ }
+
+ [Test]
+ public void FindLast()
+ {
+ int i;
+ Assert.IsFalse(list.FindLast(pred, out i));
+ list.AddAll<int>(new int[] { 4, 22, 67, 37 });
+ Assert.IsFalse(list.FindLast(pred, out i));
+ list.AddAll<int>(new int[] { 45, 122, 675, 137 });
+ Assert.IsTrue(list.FindLast(pred, out i));
+ Assert.AreEqual(675, i);
+ }
+
+ [Test]
+ public void FindIndex()
+ {
+ Assert.IsFalse(0 <= list.FindIndex(pred));
+ list.AddAll<int>(new int[] { 4, 22, 67, 37 });
+ Assert.IsFalse(0 <= list.FindIndex(pred));
+ list.AddAll<int>(new int[] { 45, 122, 675, 137 });
+ Assert.AreEqual(3, list.FindIndex(pred));
+ }
+
+ [Test]
+ public void FindLastIndex()
+ {
+ Assert.IsFalse(0 <= list.FindLastIndex(pred));
+ list.AddAll<int>(new int[] { 4, 22, 67, 37 });
+ Assert.IsFalse(0 <= list.FindLastIndex(pred));
+ list.AddAll<int>(new int[] { 45, 122, 675, 137 });
+ Assert.AreEqual(7, list.FindLastIndex(pred));
+ }
+ }
+
+ [TestFixture]
+ public class UniqueItems
+ {
+ private SortedArray<int> list;
+
+ [SetUp]
+ public void Init() { list = new SortedArray<int>(); }
+
+ [TearDown]
+ public void Dispose() { list = null; }
+
+ [Test]
+ public void Test()
+ {
+ Assert.IsTrue(IC.seteq(list.UniqueItems()));
+ Assert.IsTrue(IC.seteq(list.ItemMultiplicities()));
+ list.AddAll<int>(new int[] { 7, 9, 7 });
+ Assert.IsTrue(IC.seteq(list.UniqueItems(), 7, 9));
+ Assert.IsTrue(IC.seteq(list.ItemMultiplicities(), 7, 1, 9, 1));
+ }
+ }
+
+ [TestFixture]
+ public class ArrayTest
+ {
+ private SortedArray<int> tree;
+
+ int[] a;
+
+
+ [SetUp]
+ public void Init()
+ {
+ tree = new SortedArray<int>(new IC());
+ a = new int[10];
+ for (int i = 0; i < 10; i++)
+ a[i] = 1000 + i;
+ }
+
+
+ [TearDown]
+ public void Dispose() { tree = null; }
+
+
+ private string aeq(int[] a, params int[] b)
+ {
+ if (a.Length != b.Length)
+ return "Lengths differ: " + a.Length + " != " + b.Length;
+
+ for (int i = 0; i < a.Length; i++)
+ if (a[i] != b[i])
+ return String.Format("{0}'th elements differ: {1} != {2}", i, a[i], b[i]);
+
+ return "Alles klar";
+ }
+
+
+ [Test]
+ public void ToArray()
+ {
+ Assert.AreEqual("Alles klar", aeq(tree.ToArray()));
+ tree.Add(7);
+ tree.Add(4);
+ Assert.AreEqual("Alles klar", aeq(tree.ToArray(), 4, 7));
+ }
+
+
+ [Test]
+ public void CopyTo()
+ {
+ tree.CopyTo(a, 1);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009));
+ tree.Add(6);
+ tree.CopyTo(a, 2);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 6, 1003, 1004, 1005, 1006, 1007, 1008, 1009));
+ tree.Add(4);
+ tree.Add(9);
+ tree.CopyTo(a, 4);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 6, 1003, 4, 6, 9, 1007, 1008, 1009));
+ tree.Clear();
+ tree.Add(7);
+ tree.CopyTo(a, 9);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 6, 1003, 4, 6, 9, 1007, 1008, 7));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void CopyToBad()
+ {
+ tree.CopyTo(a, 11);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void CopyToBad2()
+ {
+ tree.CopyTo(a, -1);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void CopyToTooFar()
+ {
+ tree.Add(3);
+ tree.Add(4);
+ tree.CopyTo(a, 9);
+ }
+ }
+
+
+ [TestFixture]
+ public class Combined
+ {
+ private IIndexedSorted<KeyValuePair<int,int>> lst;
+
+
+ [SetUp]
+ public void Init()
+ {
+ lst = new SortedArray<KeyValuePair<int,int>>(new KeyValuePairComparer<int,int>(new IC()));
+ for (int i = 0; i < 10; i++)
+ lst.Add(new KeyValuePair<int,int>(i, i + 30));
+ }
+
+
+ [TearDown]
+ public void Dispose() { lst = null; }
+
+
+ [Test]
+ public void Find()
+ {
+ KeyValuePair<int,int> p = new KeyValuePair<int,int>(3, 78);
+
+ Assert.IsTrue(lst.Find(ref p));
+ Assert.AreEqual(3, p.Key);
+ Assert.AreEqual(33, p.Value);
+ p = new KeyValuePair<int,int>(13, 78);
+ Assert.IsFalse(lst.Find(ref p));
+ }
+
+
+ [Test]
+ public void FindOrAdd()
+ {
+ KeyValuePair<int,int> p = new KeyValuePair<int,int>(3, 78);
+
+ Assert.IsTrue(lst.FindOrAdd(ref p));
+ Assert.AreEqual(3, p.Key);
+ Assert.AreEqual(33, p.Value);
+ p = new KeyValuePair<int,int>(13, 79);
+ Assert.IsFalse(lst.FindOrAdd(ref p));
+ Assert.AreEqual(13, lst[10].Key);
+ Assert.AreEqual(79, lst[10].Value);
+ }
+
+
+ [Test]
+ public void Update()
+ {
+ KeyValuePair<int,int> p = new KeyValuePair<int,int>(3, 78);
+
+ Assert.IsTrue(lst.Update(p));
+ Assert.AreEqual(3, lst[3].Key);
+ Assert.AreEqual(78, lst[3].Value);
+ p = new KeyValuePair<int,int>(13, 78);
+ Assert.IsFalse(lst.Update(p));
+ }
+
+
+ [Test]
+ public void UpdateOrAdd()
+ {
+ KeyValuePair<int,int> p = new KeyValuePair<int,int>(3, 78);
+
+ Assert.IsTrue(lst.UpdateOrAdd(p));
+ Assert.AreEqual(3, lst[3].Key);
+ Assert.AreEqual(78, lst[3].Value);
+ p = new KeyValuePair<int,int>(13, 79);
+ Assert.IsFalse(lst.UpdateOrAdd(p));
+ Assert.AreEqual(13, lst[10].Key);
+ Assert.AreEqual(79, lst[10].Value);
+ }
+
+
+ [Test]
+ public void RemoveWithReturn()
+ {
+ KeyValuePair<int,int> p = new KeyValuePair<int,int>(3, 78);
+
+ Assert.IsTrue(lst.Remove(p, out p));
+ Assert.AreEqual(3, p.Key);
+ Assert.AreEqual(33, p.Value);
+ Assert.AreEqual(4, lst[3].Key);
+ Assert.AreEqual(34, lst[3].Value);
+ p = new KeyValuePair<int,int>(13, 78);
+ Assert.IsFalse(lst.Remove(p, out p));
+ }
+ }
+
+
+ [TestFixture]
+ public class Remove
+ {
+ private SortedArray<int> array;
+
+
+ [SetUp]
+ public void Init()
+ {
+ array = new SortedArray<int>(new IC());
+ for (int i = 10; i < 20; i++)
+ {
+ array.Add(i);
+ array.Add(i + 10);
+ }
+ }
+
+
+ [Test]
+ public void SmallTrees()
+ {
+ array.Clear();
+ array.Add(7);
+ array.Add(9);
+ Assert.IsTrue(array.Remove(7));
+ Assert.IsTrue(array.Check());
+ }
+
+
+ [Test]
+ public void ByIndex()
+ {
+ //Remove root!
+ int n = array.Count;
+ int i = array[10];
+
+ array.RemoveAt(10);
+ Assert.IsTrue(array.Check());
+ Assert.IsFalse(array.Contains(i));
+ Assert.AreEqual(n - 1, array.Count);
+
+ //Low end
+ i = array.FindMin();
+ array.RemoveAt(0);
+ Assert.IsTrue(array.Check());
+ Assert.IsFalse(array.Contains(i));
+ Assert.AreEqual(n - 2, array.Count);
+
+ //high end
+ i = array.FindMax();
+ array.RemoveAt(array.Count - 1);
+ Assert.IsTrue(array.Check());
+ Assert.IsFalse(array.Contains(i));
+ Assert.AreEqual(n - 3, array.Count);
+
+ //Some leaf
+ i = 18;
+ array.RemoveAt(7);
+ Assert.IsTrue(array.Check());
+ Assert.IsFalse(array.Contains(i));
+ Assert.AreEqual(n - 4, array.Count);
+ }
+
+
+ [Test]
+ public void AlmostEmpty()
+ {
+ //Almost empty
+ array.Clear();
+ array.Add(3);
+ array.RemoveAt(0);
+ Assert.IsTrue(array.Check());
+ Assert.IsFalse(array.Contains(3));
+ Assert.AreEqual(0, array.Count);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException), "Index out of range for sequenced collectionvalue")]
+ public void Empty()
+ {
+ array.Clear();
+ array.RemoveAt(0);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException), "Index out of range for sequenced collectionvalue")]
+ public void HighIndex()
+ {
+ array.RemoveAt(array.Count);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException), "Index out of range for sequenced collectionvalue")]
+ public void LowIndex()
+ {
+ array.RemoveAt(-1);
+ }
+
+
+ [Test]
+ public void Normal()
+ {
+ Assert.IsFalse(array.Remove(-20));
+
+ //No demote case, with move_item
+ Assert.IsTrue(array.Remove(20));
+ Assert.IsTrue(array.Check());
+ Assert.IsFalse(array.Remove(20));
+
+ //plain case 2
+ Assert.IsTrue(array.Remove(14));
+ Assert.IsTrue(array.Check(), "Bad tree");
+
+ //case 1b
+ Assert.IsTrue(array.Remove(25));
+ Assert.IsTrue(array.Check(), "Bad tree");
+
+ //case 1c
+ Assert.IsTrue(array.Remove(29));
+ Assert.IsTrue(array.Check(), "Bad tree");
+
+ //1a (terminating)
+ Assert.IsTrue(array.Remove(10));
+ Assert.IsTrue(array.Check(), "Bad tree");
+
+ //2+1b
+ Assert.IsTrue(array.Remove(12));
+ Assert.IsTrue(array.Remove(11));
+
+ //1a+1b
+ Assert.IsTrue(array.Remove(18));
+ Assert.IsTrue(array.Remove(13));
+ Assert.IsTrue(array.Remove(15));
+
+ //2+1c
+ for (int i = 0; i < 10; i++)
+ array.Add(50 - 2 * i);
+
+ Assert.IsTrue(array.Remove(42));
+ Assert.IsTrue(array.Remove(38));
+ Assert.IsTrue(array.Remove(28));
+ Assert.IsTrue(array.Remove(40));
+
+ //
+ Assert.IsTrue(array.Remove(16));
+ Assert.IsTrue(array.Remove(23));
+ Assert.IsTrue(array.Remove(17));
+ Assert.IsTrue(array.Remove(19));
+ Assert.IsTrue(array.Remove(50));
+ Assert.IsTrue(array.Remove(26));
+ Assert.IsTrue(array.Remove(21));
+ Assert.IsTrue(array.Remove(22));
+ Assert.IsTrue(array.Remove(24));
+ for (int i = 0; i < 48; i++)
+ array.Remove(i);
+
+ //Almost empty tree:
+ Assert.IsFalse(array.Remove(26));
+ Assert.IsTrue(array.Remove(48));
+ Assert.IsTrue(array.Check(), "Bad tree");
+
+ //Empty tree:
+ Assert.IsFalse(array.Remove(26));
+ Assert.IsTrue(array.Check(), "Bad tree");
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ array = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class PredecessorStructure
+ {
+ private SortedArray<int> tree;
+
+
+ [SetUp]
+ public void Init()
+ {
+ tree = new SortedArray<int>(new IC());
+ }
+
+
+ private void loadup()
+ {
+ for (int i = 0; i < 20; i++)
+ tree.Add(2 * i);
+ }
+
+
+ [Test]
+ public void Predecessor()
+ {
+ loadup();
+ Assert.AreEqual(6, tree.Predecessor(7));
+ Assert.AreEqual(6, tree.Predecessor(8));
+
+ //The bottom
+ Assert.AreEqual(0, tree.Predecessor(1));
+
+ //The top
+ Assert.AreEqual(38, tree.Predecessor(39));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void PredecessorTooLow1()
+ {
+ tree.Predecessor(-2);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void PredecessorTooLow2()
+ {
+ tree.Predecessor(0);
+ }
+
+
+ [Test]
+ public void WeakPredecessor()
+ {
+ loadup();
+ Assert.AreEqual(6, tree.WeakPredecessor(7));
+ Assert.AreEqual(8, tree.WeakPredecessor(8));
+
+ //The bottom
+ Assert.AreEqual(0, tree.WeakPredecessor(1));
+ Assert.AreEqual(0, tree.WeakPredecessor(0));
+
+ //The top
+ Assert.AreEqual(38, tree.WeakPredecessor(39));
+ Assert.AreEqual(38, tree.WeakPredecessor(38));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void WeakPredecessorTooLow1()
+ {
+ tree.WeakPredecessor(-1);
+ }
+
+
+ [Test]
+ public void Successor()
+ {
+ loadup();
+ Assert.AreEqual(8, tree.Successor(7));
+ Assert.AreEqual(10, tree.Successor(8));
+
+ //The bottom
+ Assert.AreEqual(2, tree.Successor(0));
+ Assert.AreEqual(0, tree.Successor(-1));
+
+ //The top
+ Assert.AreEqual(38, tree.Successor(37));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void SuccessorTooHigh1()
+ {
+ tree.Successor(38);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void SuccessorTooHigh2()
+ {
+ tree.Successor(39);
+ }
+
+
+ [Test]
+ public void WeakSuccessor()
+ {
+ loadup();
+ Assert.AreEqual(6, tree.WeakSuccessor(6));
+ Assert.AreEqual(8, tree.WeakSuccessor(7));
+
+ //The bottom
+ Assert.AreEqual(0, tree.WeakSuccessor(-1));
+ Assert.AreEqual(0, tree.WeakSuccessor(0));
+
+ //The top
+ Assert.AreEqual(38, tree.WeakSuccessor(37));
+ Assert.AreEqual(38, tree.WeakSuccessor(38));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void WeakSuccessorTooHigh1()
+ {
+ tree.WeakSuccessor(39);
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ tree = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class PriorityQueue
+ {
+ private SortedArray<int> tree;
+
+
+ [SetUp]
+ public void Init()
+ {
+ tree = new SortedArray<int>(new IC());
+ }
+
+
+ private void loadup()
+ {
+ foreach (int i in new int[] { 1, 2, 3, 4 })
+ tree.Add(i);
+ }
+
+
+ [Test]
+ public void Normal()
+ {
+ loadup();
+ Assert.AreEqual(1, tree.FindMin());
+ Assert.AreEqual(4, tree.FindMax());
+ Assert.AreEqual(1, tree.DeleteMin());
+ Assert.AreEqual(4, tree.DeleteMax());
+ Assert.IsTrue(tree.Check(), "Bad tree");
+ Assert.AreEqual(2, tree.FindMin());
+ Assert.AreEqual(3, tree.FindMax());
+ Assert.AreEqual(2, tree.DeleteMin());
+ Assert.AreEqual(3, tree.DeleteMax());
+ Assert.IsTrue(tree.Check(), "Bad tree");
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void Empty1()
+ {
+ tree.FindMin();
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void Empty2()
+ {
+ tree.FindMax();
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void Empty3()
+ {
+ tree.DeleteMin();
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void Empty4()
+ {
+ tree.DeleteMax();
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ tree = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class IndexingAndCounting
+ {
+ private SortedArray<int> array;
+
+
+ [SetUp]
+ public void Init()
+ {
+ array = new SortedArray<int>(new IC());
+ }
+
+
+ private void populate()
+ {
+ array.Add(30);
+ array.Add(50);
+ array.Add(10);
+ array.Add(70);
+ }
+
+
+ [Test]
+ public void ToArray()
+ {
+ populate();
+
+ int[] a = array.ToArray();
+
+ Assert.AreEqual(4, a.Length);
+ Assert.AreEqual(10, a[0]);
+ Assert.AreEqual(30, a[1]);
+ Assert.AreEqual(50, a[2]);
+ Assert.AreEqual(70, a[3]);
+ }
+
+
+ [Test]
+ public void GoodIndex()
+ {
+ Assert.AreEqual(~0, array.IndexOf(20));
+ Assert.AreEqual(~0, array.LastIndexOf(20));
+ populate();
+ Assert.AreEqual(10, array[0]);
+ Assert.AreEqual(30, array[1]);
+ Assert.AreEqual(50, array[2]);
+ Assert.AreEqual(70, array[3]);
+ Assert.AreEqual(0, array.IndexOf(10));
+ Assert.AreEqual(1, array.IndexOf(30));
+ Assert.AreEqual(2, array.IndexOf(50));
+ Assert.AreEqual(3, array.IndexOf(70));
+ Assert.AreEqual(~1, array.IndexOf(20));
+ Assert.AreEqual(~0, array.IndexOf(0));
+ Assert.AreEqual(~4, array.IndexOf(90));
+ Assert.AreEqual(0, array.LastIndexOf(10));
+ Assert.AreEqual(1, array.LastIndexOf(30));
+ Assert.AreEqual(2, array.LastIndexOf(50));
+ Assert.AreEqual(3, array.LastIndexOf(70));
+ Assert.AreEqual(~1, array.LastIndexOf(20));
+ Assert.AreEqual(~0, array.LastIndexOf(0));
+ Assert.AreEqual(~4, array.LastIndexOf(90));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void IndexTooLarge()
+ {
+ populate();
+ Console.WriteLine(array[4]);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void IndexTooSmall()
+ {
+ populate();
+ Console.WriteLine(array[-1]);
+ }
+
+
+ [Test]
+ public void FilledTreeOutsideInput()
+ {
+ populate();
+ Assert.AreEqual(0, array.CountFrom(90));
+ Assert.AreEqual(0, array.CountFromTo(-20, 0));
+ Assert.AreEqual(0, array.CountFromTo(80, 100));
+ Assert.AreEqual(0, array.CountTo(0));
+ Assert.AreEqual(4, array.CountTo(90));
+ Assert.AreEqual(4, array.CountFromTo(-20, 90));
+ Assert.AreEqual(4, array.CountFrom(0));
+ }
+
+
+ [Test]
+ public void FilledTreeIntermediateInput()
+ {
+ populate();
+ Assert.AreEqual(3, array.CountFrom(20));
+ Assert.AreEqual(1, array.CountFromTo(20, 40));
+ Assert.AreEqual(2, array.CountTo(40));
+ }
+
+
+ [Test]
+ public void FilledTreeMatchingInput()
+ {
+ populate();
+ Assert.AreEqual(3, array.CountFrom(30));
+ Assert.AreEqual(2, array.CountFromTo(30, 70));
+ Assert.AreEqual(0, array.CountFromTo(50, 30));
+ Assert.AreEqual(0, array.CountFromTo(50, 50));
+ Assert.AreEqual(0, array.CountTo(10));
+ Assert.AreEqual(2, array.CountTo(50));
+ }
+
+
+ [Test]
+ public void CountEmptyTree()
+ {
+ Assert.AreEqual(0, array.CountFrom(20));
+ Assert.AreEqual(0, array.CountFromTo(20, 40));
+ Assert.AreEqual(0, array.CountTo(40));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ array = null;
+ }
+ }
+
+
+
+
+ namespace ModificationCheck
+ {
+ [TestFixture]
+ public class Enumerator
+ {
+ private SortedArray<int> tree;
+
+ private SCG.IEnumerator<int> e;
+
+
+ [SetUp]
+ public void Init()
+ {
+ tree = new SortedArray<int>(new IC());
+ for (int i = 0; i < 10; i++)
+ tree.Add(i);
+
+ e = tree.GetEnumerator();
+ }
+
+
+ [Test]
+ public void CurrentAfterModification()
+ {
+ e.MoveNext();
+ tree.Add(34);
+ Assert.AreEqual(0, e.Current);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void MoveNextAfterAdd()
+ {
+ e.MoveNext();
+ tree.Add(34);
+ e.MoveNext();
+ }
+
+
+
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void MoveNextAfterRemove()
+ {
+ e.MoveNext();
+ tree.Remove(34);
+ e.MoveNext();
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void MoveNextAfterClear()
+ {
+ e.MoveNext();
+ tree.Clear();
+ e.MoveNext();
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ tree = null;
+ e = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class RangeEnumerator
+ {
+ private SortedArray<int> tree;
+
+ private SCG.IEnumerator<int> e;
+
+
+ [SetUp]
+ public void Init()
+ {
+ tree = new SortedArray<int>(new IC());
+ for (int i = 0; i < 10; i++)
+ tree.Add(i);
+
+ e = tree.RangeFromTo(3, 7).GetEnumerator();
+ }
+
+
+ [Test]
+ public void CurrentAfterModification()
+ {
+ e.MoveNext();
+ tree.Add(34);
+ Assert.AreEqual(3, e.Current);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void MoveNextAfterAdd()
+ {
+ tree.Add(34);
+ e.MoveNext();
+ }
+
+
+
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void MoveNextAfterRemove()
+ {
+ tree.Remove(34);
+ e.MoveNext();
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void MoveNextAfterClear()
+ {
+ tree.Clear();
+ e.MoveNext();
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ tree = null;
+ e = null;
+ }
+ }
+ }
+
+ namespace HigherOrder
+ {
+ internal class CubeRoot: IComparable<int>
+ {
+ private int c;
+
+
+ internal CubeRoot(int c) { this.c = c; }
+
+
+ public int CompareTo(int that) { return c - that * that * that; }
+
+ public bool Equals(int that) { return c == that * that * that; }
+
+ }
+
+
+
+ class Interval: IComparable<int>
+ {
+ private int b, t;
+
+
+ internal Interval(int b, int t) { this.b = b; this.t = t; }
+
+
+ public int CompareTo(int that) { return that < b ? 1 : that > t ? -1 : 0; }
+
+ public bool Equals(int that) { return that >= b && that <= t; }
+ }
+
+
+
+ [TestFixture]
+ public class Simple
+ {
+ private SortedArray<int> array;
+
+ private SCG.IComparer<int> ic;
+
+
+ [SetUp]
+ public void Init()
+ {
+ ic = new IC();
+ array = new SortedArray<int>(ic);
+ }
+
+
+ private bool never(int i) { return false; }
+
+
+ private bool always(int i) { return true; }
+
+
+ private bool even(int i) { return i % 2 == 0; }
+
+
+ private string themap(int i) { return String.Format("AA {0,4} BB", i); }
+
+
+ private string badmap(int i) { return String.Format("AA {0} BB", i); }
+
+
+ private int appfield1;
+
+ private int appfield2;
+
+
+ private void apply(int i) { appfield1++; appfield2 += i * i; }
+
+
+ [Test]
+ public void Apply()
+ {
+ Simple simple1 = new Simple();
+
+ array.Apply(new Act<int>(simple1.apply));
+ Assert.AreEqual(0, simple1.appfield1);
+ Assert.AreEqual(0, simple1.appfield2);
+
+ Simple simple2 = new Simple();
+
+ for (int i = 0; i < 10; i++) array.Add(i);
+
+ array.Apply(new Act<int>(simple2.apply));
+ Assert.AreEqual(10, simple2.appfield1);
+ Assert.AreEqual(285, simple2.appfield2);
+ }
+
+
+ [Test]
+ public void All()
+ {
+ Assert.IsTrue(array.All(new Fun<int, bool>(never)));
+ Assert.IsTrue(array.All(new Fun<int, bool>(even)));
+ Assert.IsTrue(array.All(new Fun<int, bool>(always)));
+ for (int i = 0; i < 10; i++) array.Add(i);
+
+ Assert.IsFalse(array.All(new Fun<int, bool>(never)));
+ Assert.IsFalse(array.All(new Fun<int, bool>(even)));
+ Assert.IsTrue(array.All(new Fun<int, bool>(always)));
+ array.Clear();
+ for (int i = 0; i < 10; i++) array.Add(i * 2);
+
+ Assert.IsFalse(array.All(new Fun<int, bool>(never)));
+ Assert.IsTrue(array.All(new Fun<int, bool>(even)));
+ Assert.IsTrue(array.All(new Fun<int, bool>(always)));
+ array.Clear();
+ for (int i = 0; i < 10; i++) array.Add(i * 2 + 1);
+
+ Assert.IsFalse(array.All(new Fun<int, bool>(never)));
+ Assert.IsFalse(array.All(new Fun<int, bool>(even)));
+ Assert.IsTrue(array.All(new Fun<int, bool>(always)));
+ }
+
+
+ [Test]
+ public void Exists()
+ {
+ Assert.IsFalse(array.Exists(new Fun<int, bool>(never)));
+ Assert.IsFalse(array.Exists(new Fun<int, bool>(even)));
+ Assert.IsFalse(array.Exists(new Fun<int, bool>(always)));
+ for (int i = 0; i < 10; i++) array.Add(i);
+
+ Assert.IsFalse(array.Exists(new Fun<int, bool>(never)));
+ Assert.IsTrue(array.Exists(new Fun<int, bool>(even)));
+ Assert.IsTrue(array.Exists(new Fun<int, bool>(always)));
+ array.Clear();
+ for (int i = 0; i < 10; i++) array.Add(i * 2);
+
+ Assert.IsFalse(array.Exists(new Fun<int, bool>(never)));
+ Assert.IsTrue(array.Exists(new Fun<int, bool>(even)));
+ Assert.IsTrue(array.Exists(new Fun<int, bool>(always)));
+ array.Clear();
+ for (int i = 0; i < 10; i++) array.Add(i * 2 + 1);
+
+ Assert.IsFalse(array.Exists(new Fun<int, bool>(never)));
+ Assert.IsFalse(array.Exists(new Fun<int, bool>(even)));
+ Assert.IsTrue(array.Exists(new Fun<int, bool>(always)));
+ }
+
+
+ [Test]
+ public void FindAll()
+ {
+ Assert.AreEqual(0, array.FindAll(new Fun<int, bool>(never)).Count);
+ for (int i = 0; i < 10; i++)
+ array.Add(i);
+
+ Assert.AreEqual(0, array.FindAll(new Fun<int, bool>(never)).Count);
+ Assert.AreEqual(10, array.FindAll(new Fun<int, bool>(always)).Count);
+ Assert.AreEqual(5, array.FindAll(new Fun<int, bool>(even)).Count);
+ Assert.IsTrue(((SortedArray<int>)array.FindAll(new Fun<int, bool>(even))).Check());
+ }
+
+
+ [Test]
+ public void Map()
+ {
+ Assert.AreEqual(0, array.Map(new Fun<int,string>(themap), new SC()).Count);
+ for (int i = 0; i < 11; i++)
+ array.Add(i * i * i);
+
+ IIndexedSorted<string> res = array.Map(new Fun<int,string>(themap), new SC());
+
+ Assert.IsTrue(((SortedArray<string>)res).Check());
+ Assert.AreEqual(11, res.Count);
+ Assert.AreEqual("AA 0 BB", res[0]);
+ Assert.AreEqual("AA 27 BB", res[3]);
+ Assert.AreEqual("AA 125 BB", res[5]);
+ Assert.AreEqual("AA 1000 BB", res[10]);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentException), "mapper not monotonic")]
+ public void BadMap()
+ {
+ for (int i = 0; i < 11; i++)
+ array.Add(i * i * i);
+
+ ISorted<string> res = array.Map(new Fun<int,string>(badmap), new SC());
+ }
+
+
+ [Test]
+ public void Cut()
+ {
+ for (int i = 0; i < 10; i++)
+ array.Add(i);
+
+ int low, high;
+ bool lval, hval;
+
+ Assert.IsTrue(array.Cut(new CubeRoot(27), out low, out lval, out high, out hval));
+ Assert.IsTrue(lval && hval);
+ Assert.AreEqual(4, high);
+ Assert.AreEqual(2, low);
+ Assert.IsFalse(array.Cut(new CubeRoot(30), out low, out lval, out high, out hval));
+ Assert.IsTrue(lval && hval);
+ Assert.AreEqual(4, high);
+ Assert.AreEqual(3, low);
+ }
+
+
+ [Test]
+ public void CutInt()
+ {
+ for (int i = 0; i < 10; i++)
+ array.Add(2 * i);
+
+ int low, high;
+ bool lval, hval;
+
+ Assert.IsFalse(array.Cut(new IC(3), out low, out lval, out high, out hval));
+ Assert.IsTrue(lval && hval);
+ Assert.AreEqual(4, high);
+ Assert.AreEqual(2, low);
+ Assert.IsTrue(array.Cut(new IC(6), out low, out lval, out high, out hval));
+ Assert.IsTrue(lval && hval);
+ Assert.AreEqual(8, high);
+ Assert.AreEqual(4, low);
+ }
+
+
+ [Test]
+ public void CutInterval()
+ {
+ for (int i = 0; i < 10; i++)
+ array.Add(2 * i);
+
+ int lo, hi;
+ bool lv, hv;
+
+ Assert.IsTrue(array.Cut(new Interval(5, 9), out lo, out lv, out hi, out hv));
+ Assert.IsTrue(lv && hv);
+ Assert.AreEqual(10, hi);
+ Assert.AreEqual(4, lo);
+ Assert.IsTrue(array.Cut(new Interval(6, 10), out lo, out lv, out hi, out hv));
+ Assert.IsTrue(lv && hv);
+ Assert.AreEqual(12, hi);
+ Assert.AreEqual(4, lo);
+ for (int i = 0; i < 100; i++)
+ array.Add(2 * i);
+
+ array.Cut(new Interval(77, 105), out lo, out lv, out hi, out hv);
+ Assert.IsTrue(lv && hv);
+ Assert.AreEqual(106, hi);
+ Assert.AreEqual(76, lo);
+ array.Cut(new Interval(5, 7), out lo, out lv, out hi, out hv);
+ Assert.IsTrue(lv && hv);
+ Assert.AreEqual(8, hi);
+ Assert.AreEqual(4, lo);
+ array.Cut(new Interval(80, 110), out lo, out lv, out hi, out hv);
+ Assert.IsTrue(lv && hv);
+ Assert.AreEqual(112, hi);
+ Assert.AreEqual(78, lo);
+ }
+
+
+ [Test]
+ public void UpperCut()
+ {
+ for (int i = 0; i < 10; i++)
+ array.Add(i);
+
+ int l, h;
+ bool lv, hv;
+
+ Assert.IsFalse(array.Cut(new CubeRoot(1000), out l, out lv, out h, out hv));
+ Assert.IsTrue(lv && !hv);
+ Assert.AreEqual(9, l);
+ Assert.IsFalse(array.Cut(new CubeRoot(-50), out l, out lv, out h, out hv));
+ Assert.IsTrue(!lv && hv);
+ Assert.AreEqual(0, h);
+ }
+
+
+ [TearDown]
+ public void Dispose() { ic = null; array = null; }
+ }
+ }
+
+
+
+
+ namespace MultiOps
+ {
+ [TestFixture]
+ public class AddAll
+ {
+ private int sqr(int i) { return i * i; }
+
+
+ SortedArray<int> array;
+
+
+ [SetUp]
+ public void Init() { array = new SortedArray<int>(new IC()); }
+
+
+ [Test]
+ public void EmptyEmpty()
+ {
+ array.AddAll(new FunEnumerable(0, new Fun<int,int>(sqr)));
+ Assert.AreEqual(0, array.Count);
+ Assert.IsTrue(array.Check());
+ }
+
+
+ [Test]
+ public void SomeEmpty()
+ {
+ for (int i = 4; i < 9; i++) array.Add(i);
+
+ array.AddAll(new FunEnumerable(0, new Fun<int,int>(sqr)));
+ Assert.AreEqual(5, array.Count);
+ Assert.IsTrue(array.Check());
+ }
+
+
+ [Test]
+ public void EmptySome()
+ {
+ array.AddAll(new FunEnumerable(4, new Fun<int,int>(sqr)));
+ Assert.AreEqual(4, array.Count);
+ Assert.IsTrue(array.Check());
+ Assert.AreEqual(0, array[0]);
+ Assert.AreEqual(1, array[1]);
+ Assert.AreEqual(4, array[2]);
+ Assert.AreEqual(9, array[3]);
+ }
+
+
+ [Test]
+ public void SomeSome()
+ {
+ for (int i = 3; i < 9; i++) array.Add(i);
+
+ array.AddAll(new FunEnumerable(4, new Fun<int,int>(sqr)));
+ Assert.AreEqual(9, array.Count);
+ Assert.IsTrue(array.Check());
+ Assert.IsTrue(IC.eq(array, 0, 1, 3,4, 5, 6, 7, 8, 9));
+ }
+
+
+ [TearDown]
+ public void Dispose() { array = null; }
+ }
+
+
+
+ [TestFixture]
+ public class AddSorted
+ {
+ private int sqr(int i) { return i * i; }
+
+
+ private int bad(int i) { return i * (5 - i); }
+
+
+ SortedArray<int> array;
+
+
+ [SetUp]
+ public void Init() { array = new SortedArray<int>(new IC()); }
+
+
+ [Test]
+ public void EmptyEmpty()
+ {
+ array.AddSorted(new FunEnumerable(0, new Fun<int,int>(sqr)));
+ Assert.AreEqual(0, array.Count);
+ Assert.IsTrue(array.Check());
+ }
+
+
+
+ [Test]
+ public void SomeEmpty()
+ {
+ for (int i = 4; i < 9; i++) array.Add(i);
+
+ array.AddSorted(new FunEnumerable(0, new Fun<int,int>(sqr)));
+ Assert.AreEqual(5, array.Count);
+ Assert.IsTrue(array.Check());
+ }
+
+
+
+ [Test]
+ public void EmptySome()
+ {
+ array.AddSorted(new FunEnumerable(4, new Fun<int,int>(sqr)));
+ Assert.AreEqual(4, array.Count);
+ Assert.IsTrue(array.Check());
+ Assert.AreEqual(0, array[0]);
+ Assert.AreEqual(1, array[1]);
+ Assert.AreEqual(4, array[2]);
+ Assert.AreEqual(9, array[3]);
+ }
+
+
+
+ [Test]
+ public void SomeSome()
+ {
+ for (int i = 3; i < 9; i++) array.Add(i);
+
+ array.AddSorted(new FunEnumerable(4, new Fun<int,int>(sqr)));
+ Assert.AreEqual(9, array.Count);
+ Assert.IsTrue(array.Check());
+ Assert.IsTrue(IC.eq(array, 0, 1, 3, 4, 5, 6, 7, 8, 9));
+ }
+
+ [Test]
+ [ExpectedException(typeof(ArgumentException), "Argument not sorted")]
+ public void EmptyBad()
+ {
+ array.AddSorted(new FunEnumerable(9, new Fun<int,int>(bad)));
+ }
+
+
+ [TearDown]
+ public void Dispose() { array = null; }
+ }
+
+ [TestFixture]
+ public class Rest
+ {
+ SortedArray<int> array, array2;
+
+
+ [SetUp]
+ public void Init()
+ {
+ array = new SortedArray<int>(new IC());
+ array2 = new SortedArray<int>(new IC());
+ for (int i = 0; i < 10; i++)
+ array.Add(i);
+
+ for (int i = 0; i < 10; i++)
+ array2.Add(2 * i);
+ }
+
+
+ [Test]
+ public void RemoveAll()
+ {
+ array.RemoveAll(array2.RangeFromTo(3, 7));
+ Assert.AreEqual(8, array.Count);
+ Assert.IsTrue(array.Check());
+ Assert.IsTrue(IC.eq(array, 0, 1, 2, 3, 5, 7, 8, 9));
+ array.RemoveAll(array2.RangeFromTo(3, 7));
+ Assert.AreEqual(8, array.Count);
+ Assert.IsTrue(array.Check());
+ Assert.IsTrue(IC.eq(array, 0, 1, 2, 3, 5, 7, 8, 9));
+ array.RemoveAll(array2.RangeFromTo(13, 17));
+ Assert.AreEqual(8, array.Count);
+ Assert.IsTrue(array.Check());
+ Assert.IsTrue(IC.eq(array, 0, 1, 2, 3, 5, 7, 8, 9));
+ array.RemoveAll(array2.RangeFromTo(3, 17));
+ Assert.AreEqual(7, array.Count);
+ Assert.IsTrue(array.Check());
+ Assert.IsTrue(IC.eq(array, 0, 1, 2, 3, 5, 7, 9));
+ for (int i = 0; i < 10; i++) array2.Add(i);
+
+ array.RemoveAll(array2.RangeFromTo(-1, 10));
+ Assert.AreEqual(0, array.Count);
+ Assert.IsTrue(array.Check());
+ Assert.IsTrue(IC.eq(array));
+ }
+
+
+ [Test]
+ public void RetainAll()
+ {
+ array.RetainAll(array2.RangeFromTo(3, 17));
+ Assert.AreEqual(3, array.Count);
+ Assert.IsTrue(array.Check());
+ Assert.IsTrue(IC.eq(array, 4, 6, 8));
+ array.RetainAll(array2.RangeFromTo(1, 17));
+ Assert.AreEqual(3, array.Count);
+ Assert.IsTrue(array.Check());
+ Assert.IsTrue(IC.eq(array, 4, 6, 8));
+ array.RetainAll(array2.RangeFromTo(3, 5));
+ Assert.AreEqual(1, array.Count);
+ Assert.IsTrue(array.Check());
+ Assert.IsTrue(IC.eq(array, 4));
+ array.RetainAll(array2.RangeFromTo(7, 17));
+ Assert.AreEqual(0, array.Count);
+ Assert.IsTrue(array.Check());
+ Assert.IsTrue(IC.eq(array));
+ for (int i = 0; i < 10; i++) array.Add(i);
+
+ array.RetainAll(array2.RangeFromTo(5, 5));
+ Assert.AreEqual(0, array.Count);
+ Assert.IsTrue(array.Check());
+ Assert.IsTrue(IC.eq(array));
+ for (int i = 0; i < 10; i++) array.Add(i);
+
+ array.RetainAll(array2.RangeFromTo(15, 25));
+ Assert.AreEqual(0, array.Count);
+ Assert.IsTrue(array.Check());
+ Assert.IsTrue(IC.eq(array));
+ }
+
+
+ [Test]
+ public void ContainsAll()
+ {
+ Assert.IsFalse(array.ContainsAll(array2));
+ Assert.IsTrue(array.ContainsAll(array));
+ array2.Clear();
+ Assert.IsTrue(array.ContainsAll(array2));
+ array.Clear();
+ Assert.IsTrue(array.ContainsAll(array2));
+ array2.Add(8);
+ Assert.IsFalse(array.ContainsAll(array2));
+ }
+
+
+ [Test]
+ public void RemoveInterval()
+ {
+ array.RemoveInterval(3, 4);
+ Assert.IsTrue(array.Check());
+ Assert.AreEqual(6, array.Count);
+ Assert.IsTrue(IC.eq(array, 0, 1, 2, 7, 8, 9));
+ array.RemoveInterval(2, 3);
+ Assert.IsTrue(array.Check());
+ Assert.AreEqual(3, array.Count);
+ Assert.IsTrue(IC.eq(array, 0, 1, 9));
+ array.RemoveInterval(0, 3);
+ Assert.IsTrue(array.Check());
+ Assert.AreEqual(0, array.Count);
+ Assert.IsTrue(IC.eq(array));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void RemoveRangeBad1()
+ {
+ array.RemoveInterval(-3, 8);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void RemoveRangeBad2()
+ {
+ array.RemoveInterval(3, -8);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void RemoveRangeBad3()
+ {
+ array.RemoveInterval(3, 8);
+ }
+
+
+ [Test]
+ public void GetRange()
+ {
+ SCG.IEnumerable<int> e = array[3, 3];
+
+ Assert.IsTrue(IC.eq(e, 3, 4, 5));
+ e = array[3, 0];
+ Assert.IsTrue(IC.eq(e));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void GetRangeBad1()
+ {
+ object foo = array[-3, 0];
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void GetRangeBad2()
+ {
+ object foo = array[3, -1];
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void GetRangeBad3()
+ {
+ object foo = array[3, 8];
+ }
+
+
+ [TearDown]
+ public void Dispose() { array = null; array2 = null; }
+ }
+ }
+
+
+
+
+ namespace Sync
+ {
+ [TestFixture]
+ public class SyncRoot
+ {
+ private SortedArray<int> tree;
+
+ int sz = 5000;
+
+
+ [Test]
+ public void Safe()
+ {
+ System.Threading.Thread t1 = new System.Threading.Thread(new System.Threading.ThreadStart(safe1));
+ System.Threading.Thread t2 = new System.Threading.Thread(new System.Threading.ThreadStart(safe2));
+
+ t1.Start();
+ t2.Start();
+ t1.Join();
+ t2.Join();
+ Assert.AreEqual(2 * sz + 1, tree.Count);
+ Assert.IsTrue(tree.Check());
+ }
+
+
+ //[Test]
+ public void UnSafe()
+ {
+ bool bad = false;
+
+ for (int i = 0; i < 10; i++)
+ {
+ System.Threading.Thread t1 = new System.Threading.Thread(new System.Threading.ThreadStart(unsafe1));
+ System.Threading.Thread t2 = new System.Threading.Thread(new System.Threading.ThreadStart(unsafe2));
+
+ t1.Start();
+ t2.Start();
+ t1.Join();
+ t2.Join();
+ if (bad = 2 * sz + 1 != tree.Count)
+ {
+ Console.WriteLine("{0}::Unsafe(): bad at {1}", GetType(), i);
+ break;
+ }
+ }
+
+ Assert.IsTrue(bad, "No sync problems!");
+ }
+
+
+ [Test]
+ public void SafeUnSafe()
+ {
+ System.Threading.Thread t1 = new System.Threading.Thread(new System.Threading.ThreadStart(unsafe1));
+ System.Threading.Thread t2 = new System.Threading.Thread(new System.Threading.ThreadStart(unsafe2));
+
+ t1.Start();
+ t1.Join();
+ t2.Start();
+ t2.Join();
+ Assert.AreEqual(2 * sz + 1, tree.Count);
+ }
+
+
+ [SetUp]
+ public void Init() { tree = new SortedArray<int>(new IC()); }
+
+
+ private void unsafe1()
+ {
+ for (int i = 0; i < 2 * sz; i++)
+ tree.Add(i * 2);
+
+ for (int i = 1; i < sz; i++)
+ tree.Remove(i * 4);
+ }
+
+
+ private void safe1()
+ {
+ for (int i = 0; i < 2 * sz; i++)
+ lock (tree.SyncRoot)
+ tree.Add(i * 2);
+
+ for (int i = 1; i < sz; i++)
+ lock (tree.SyncRoot)
+ tree.Remove(i * 4);
+ }
+
+
+ private void unsafe2()
+ {
+ for (int i = 2 * sz; i > 0; i--)
+ tree.Add(i * 2 + 1);
+
+ for (int i = sz; i > 0; i--)
+ tree.Remove(i * 4 + 1);
+ }
+
+
+ private void safe2()
+ {
+ for (int i = 2 * sz; i > 0; i--)
+ lock (tree.SyncRoot)
+ tree.Add(i * 2 + 1);
+
+ for (int i = sz; i > 0; i--)
+ lock (tree.SyncRoot)
+ tree.Remove(i * 4 + 1);
+ }
+
+
+ [TearDown]
+ public void Dispose() { tree = null; }
+ }
+
+
+
+ //[TestFixture]
+ public class ConcurrentQueries
+ {
+ private SortedArray<int> tree;
+
+ int sz = 500000;
+
+
+ [SetUp]
+ public void Init()
+ {
+ tree = new SortedArray<int>(new IC());
+ for (int i = 0; i < sz; i++)
+ {
+ tree.Add(i);
+ }
+ }
+
+
+
+ class A
+ {
+ public int count = 0;
+
+ SortedArray<int> t;
+
+
+ public A(SortedArray<int> t) { this.t = t; }
+
+
+ public void a(int i) { count++; }
+
+
+ public void traverse() { t.Apply(new Act<int>(a)); }
+ }
+
+
+
+
+ [Test]
+ public void Safe()
+ {
+ A a = new A(tree);
+
+ a.traverse();
+ Assert.AreEqual(sz, a.count);
+ }
+
+
+ [Test]
+ public void RegrettablyUnsafe()
+ {
+ System.Threading.Thread[] t = new System.Threading.Thread[10];
+ A[] a = new A[10];
+ for (int i = 0; i < 10; i++)
+ {
+ a[i] = new A(tree);
+ t[i] = new System.Threading.Thread(new System.Threading.ThreadStart(a[i].traverse));
+ }
+
+ for (int i = 0; i < 10; i++)
+ t[i].Start();
+ for (int i = 0; i < 10; i++)
+ t[i].Join();
+ for (int i = 0; i < 10; i++)
+ Assert.AreEqual(sz,a[i].count);
+
+ }
+
+
+ [TearDown]
+ public void Dispose() { tree = null; }
+ }
+ }
+
+
+
+
+ namespace Hashing
+ {
+ [TestFixture]
+ public class ISequenced
+ {
+ private ISequenced<int> dit, dat, dut;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new SortedArray<int>(8,Comparer<int>.Default, EqualityComparer<int>.Default);
+ dat = new SortedArray<int>(8,Comparer<int>.Default, EqualityComparer<int>.Default);
+ dut = new SortedArray<int>(8,new RevIC(), EqualityComparer<int>.Default);
+ }
+
+
+ [Test]
+ public void EmptyEmpty()
+ {
+ Assert.IsTrue(dit.SequencedEquals(dat));
+ }
+
+
+ [Test]
+ public void EmptyNonEmpty()
+ {
+ dit.Add(3);
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ Assert.IsFalse(dat.SequencedEquals(dit));
+ }
+
+ [Test]
+ public void HashVal()
+ {
+ Assert.AreEqual(CHC.sequencedhashcode(), dit.GetSequencedHashCode());
+ dit.Add(3);
+ Assert.AreEqual(CHC.sequencedhashcode(3), dit.GetSequencedHashCode());
+ dit.Add(7);
+ Assert.AreEqual(CHC.sequencedhashcode(3, 7), dit.GetSequencedHashCode());
+ Assert.AreEqual(CHC.sequencedhashcode(), dut.GetSequencedHashCode());
+ dut.Add(3);
+ Assert.AreEqual(CHC.sequencedhashcode(3), dut.GetSequencedHashCode());
+ dut.Add(7);
+ Assert.AreEqual(CHC.sequencedhashcode(7, 3), dut.GetSequencedHashCode());
+ }
+
+
+ [Test]
+ public void Normal()
+ {
+ dit.Add(3);
+ dit.Add(7);
+ dat.Add(3);
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ Assert.IsFalse(dat.SequencedEquals(dit));
+ dat.Add(7);
+ Assert.IsTrue(dit.SequencedEquals(dat));
+ Assert.IsTrue(dat.SequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void WrongOrder()
+ {
+ dit.Add(3);
+ dut.Add(3);
+ Assert.IsTrue(dit.SequencedEquals(dut));
+ Assert.IsTrue(dut.SequencedEquals(dit));
+ dit.Add(7);
+ dut.Add(7);
+ Assert.IsFalse(dit.SequencedEquals(dut));
+ Assert.IsFalse(dut.SequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void Reflexive()
+ {
+ Assert.IsTrue(dit.SequencedEquals(dit));
+ dit.Add(3);
+ Assert.IsTrue(dit.SequencedEquals(dit));
+ dit.Add(7);
+ Assert.IsTrue(dit.SequencedEquals(dit));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = null;
+ dat = null;
+ dut = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class IEditableCollection
+ {
+ private ICollection<int> dit, dat, dut;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new SortedArray<int>(8,Comparer<int>.Default, EqualityComparer<int>.Default);
+ dat = new SortedArray<int>(8,Comparer<int>.Default, EqualityComparer<int>.Default);
+ dut = new SortedArray<int>(8,new RevIC(), EqualityComparer<int>.Default);
+ }
+
+
+ [Test]
+ public void EmptyEmpty()
+ {
+ Assert.IsTrue(dit.UnsequencedEquals(dat));
+ }
+
+
+ [Test]
+ public void EmptyNonEmpty()
+ {
+ dit.Add(3);
+ Assert.IsFalse(dit.UnsequencedEquals(dat));
+ Assert.IsFalse(dat.UnsequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void HashVal()
+ {
+ Assert.AreEqual(CHC.unsequencedhashcode(), dit.GetUnsequencedHashCode());
+ dit.Add(3);
+ Assert.AreEqual(CHC.unsequencedhashcode(3), dit.GetUnsequencedHashCode());
+ dit.Add(7);
+ Assert.AreEqual(CHC.unsequencedhashcode(3, 7), dit.GetUnsequencedHashCode());
+ Assert.AreEqual(CHC.unsequencedhashcode(), dut.GetUnsequencedHashCode());
+ dut.Add(3);
+ Assert.AreEqual(CHC.unsequencedhashcode(3), dut.GetUnsequencedHashCode());
+ dut.Add(7);
+ Assert.AreEqual(CHC.unsequencedhashcode(7, 3), dut.GetUnsequencedHashCode());
+ }
+
+
+ [Test]
+ public void Normal()
+ {
+ dit.Add(3);
+ dit.Add(7);
+ dat.Add(3);
+ Assert.IsFalse(dit.UnsequencedEquals(dat));
+ Assert.IsFalse(dat.UnsequencedEquals(dit));
+ dat.Add(7);
+ Assert.IsTrue(dit.UnsequencedEquals(dat));
+ Assert.IsTrue(dat.UnsequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void WrongOrder()
+ {
+ dit.Add(3);
+ dut.Add(3);
+ Assert.IsTrue(dit.UnsequencedEquals(dut));
+ Assert.IsTrue(dut.UnsequencedEquals(dit));
+ dit.Add(7);
+ dut.Add(7);
+ Assert.IsTrue(dit.UnsequencedEquals(dut));
+ Assert.IsTrue(dut.UnsequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void Reflexive()
+ {
+ Assert.IsTrue(dit.UnsequencedEquals(dit));
+ dit.Add(3);
+ Assert.IsTrue(dit.UnsequencedEquals(dit));
+ dit.Add(7);
+ Assert.IsTrue(dit.UnsequencedEquals(dit));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = null;
+ dat = null;
+ dut = null;
+ }
+ }
+
+ }
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/1.0/Test/hashing/HashBagTests.cs b/mcs/class/Mono.C5/1.0/Test/hashing/HashBagTests.cs
new file mode 100644
index 00000000000..bfd9da8425f
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/Test/hashing/HashBagTests.cs
@@ -0,0 +1,599 @@
+/*
+ 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 C5;
+using NUnit.Framework;
+using SCG = System.Collections.Generic;
+namespace C5UnitTests.hashtable.bag
+{
+ using CollectionOfInt = HashBag<int>;
+
+ [TestFixture]
+ public class GenericTesters
+ {
+ [Test]
+ public void TestEvents()
+ {
+ Fun<CollectionOfInt> factory = delegate() { return new CollectionOfInt(TenEqualityComparer.Default); };
+ new C5UnitTests.Templates.Events.CollectionTester<CollectionOfInt>().Test(factory);
+ }
+
+ [Test]
+ public void Extensible()
+ {
+ C5UnitTests.Templates.Extensible.Clone.Tester<CollectionOfInt>();
+ C5UnitTests.Templates.Extensible.Serialization.Tester<CollectionOfInt>();
+ }
+ }
+
+ static class Factory
+ {
+ public static ICollection<T> New<T>() { return new HashBag<T>(); }
+ }
+
+
+ [TestFixture]
+ public class Formatting
+ {
+ ICollection<int> coll;
+ IFormatProvider rad16;
+ [SetUp]
+ public void Init() { coll = Factory.New<int>(); rad16 = new RadixFormatProvider(16); }
+ [TearDown]
+ public void Dispose() { coll = null; rad16 = null; }
+ [Test]
+ public void Format()
+ {
+ Assert.AreEqual("{{ }}", coll.ToString());
+ coll.AddAll<int>(new int[] { -4, 28, 129, 65530, -4, 28 });
+ Assert.AreEqual("{{ 65530(*1), -4(*2), 28(*2), 129(*1) }}", coll.ToString());
+ Assert.AreEqual("{{ FFFA(*1), -4(*2), 1C(*2), 81(*1) }}", coll.ToString(null, rad16));
+ Assert.AreEqual("{{ 65530(*1), -4(*2)... }}", coll.ToString("L18", null));
+ Assert.AreEqual("{{ FFFA(*1), -4(*2)... }}", coll.ToString("L18", rad16));
+ }
+ }
+
+ [TestFixture]
+ public class Combined
+ {
+ private ICollection<KeyValuePair<int, int>> lst;
+
+
+ [SetUp]
+ public void Init()
+ {
+ lst = new HashBag<KeyValuePair<int, int>>(new KeyValuePairEqualityComparer<int, int>());
+ for (int i = 0; i < 10; i++)
+ lst.Add(new KeyValuePair<int, int>(i, i + 30));
+ }
+
+
+ [TearDown]
+ public void Dispose() { lst = null; }
+
+
+ [Test]
+ public void Find()
+ {
+ KeyValuePair<int, int> p = new KeyValuePair<int, int>(3, 78);
+
+ Assert.IsTrue(lst.Find(ref p));
+ Assert.AreEqual(3, p.Key);
+ Assert.AreEqual(33, p.Value);
+ p = new KeyValuePair<int, int>(13, 78);
+ Assert.IsFalse(lst.Find(ref p));
+ }
+
+
+ [Test]
+ public void FindOrAdd()
+ {
+ KeyValuePair<int, int> p = new KeyValuePair<int, int>(3, 78);
+ KeyValuePair<int, int> q = new KeyValuePair<int, int>();
+
+ Assert.IsTrue(lst.FindOrAdd(ref p));
+ Assert.AreEqual(3, p.Key);
+ Assert.AreEqual(33, p.Value);
+ p = new KeyValuePair<int, int>(13, 79);
+ Assert.IsFalse(lst.FindOrAdd(ref p));
+ q.Key = 13;
+ Assert.IsTrue(lst.Find(ref q));
+ Assert.AreEqual(13, q.Key);
+ Assert.AreEqual(79, q.Value);
+ }
+
+
+ [Test]
+ public void Update()
+ {
+ KeyValuePair<int, int> p = new KeyValuePair<int, int>(3, 78);
+ KeyValuePair<int, int> q = new KeyValuePair<int, int>();
+
+ Assert.IsTrue(lst.Update(p));
+ q.Key = 3;
+ Assert.IsTrue(lst.Find(ref q));
+ Assert.AreEqual(3, q.Key);
+ Assert.AreEqual(78, q.Value);
+ p = new KeyValuePair<int, int>(13, 78);
+ Assert.IsFalse(lst.Update(p));
+ }
+
+
+ [Test]
+ public void UpdateOrAdd()
+ {
+ KeyValuePair<int, int> p = new KeyValuePair<int, int>(3, 78);
+ KeyValuePair<int, int> q = new KeyValuePair<int, int>();
+
+ Assert.IsTrue(lst.UpdateOrAdd(p));
+ q.Key = 3;
+ Assert.IsTrue(lst.Find(ref q));
+ Assert.AreEqual(3, q.Key);
+ Assert.AreEqual(78, q.Value);
+ p = new KeyValuePair<int, int>(13, 79);
+ Assert.IsFalse(lst.UpdateOrAdd(p));
+ q.Key = 13;
+ Assert.IsTrue(lst.Find(ref q));
+ Assert.AreEqual(13, q.Key);
+ Assert.AreEqual(79, q.Value);
+ }
+
+
+ [Test]
+ public void RemoveWithReturn()
+ {
+ KeyValuePair<int, int> p = new KeyValuePair<int, int>(3, 78);
+ //KeyValuePair<int, int> q = new KeyValuePair<int, int>();
+
+ Assert.IsTrue(lst.Remove(p, out p));
+ Assert.AreEqual(3, p.Key);
+ Assert.AreEqual(33, p.Value);
+ p = new KeyValuePair<int, int>(13, 78);
+ Assert.IsFalse(lst.Remove(p, out p));
+ }
+ }
+
+
+
+ [TestFixture]
+ public class CollectionOrSink
+ {
+ private HashBag<int> hashbag;
+
+
+ [SetUp]
+ public void Init() { hashbag = new HashBag<int>(); }
+
+ [Test]
+ [ExpectedException(typeof(NullReferenceException))]
+ public void NullEqualityComparerinConstructor1()
+ {
+ new HashBag<int>(null);
+ }
+
+ [Test]
+ [ExpectedException(typeof(NullReferenceException))]
+ public void NullEqualityComparerinConstructor2()
+ {
+ new HashBag<int>(5, null);
+ }
+
+ [Test]
+ [ExpectedException(typeof(NullReferenceException))]
+ public void NullEqualityComparerinConstructor3()
+ {
+ new HashBag<int>(5, 0.5, null);
+ }
+
+ [Test]
+ public void Choose()
+ {
+ hashbag.Add(7);
+ Assert.AreEqual(7, hashbag.Choose());
+ }
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void BadChoose()
+ {
+ hashbag.Choose();
+ }
+
+
+ [Test]
+ public void CountEtAl()
+ {
+ Assert.IsFalse(hashbag.IsReadOnly);
+ Assert.IsFalse(hashbag.SyncRoot == null);
+ Assert.AreEqual(0, hashbag.Count);
+ Assert.IsTrue(hashbag.IsEmpty);
+ Assert.IsTrue(hashbag.AllowsDuplicates);
+ Assert.IsTrue(hashbag.Add(0));
+ Assert.AreEqual(1, hashbag.Count);
+ Assert.IsFalse(hashbag.IsEmpty);
+ Assert.IsTrue(hashbag.Add(5));
+ Assert.AreEqual(2, hashbag.Count);
+ Assert.IsTrue(hashbag.Add(5));
+ Assert.AreEqual(3, hashbag.Count);
+ Assert.IsFalse(hashbag.IsEmpty);
+ Assert.IsTrue(hashbag.Add(8));
+ Assert.AreEqual(4, hashbag.Count);
+ Assert.AreEqual(2, hashbag.ContainsCount(5));
+ Assert.AreEqual(1, hashbag.ContainsCount(8));
+ Assert.AreEqual(1, hashbag.ContainsCount(0));
+ }
+
+
+ [Test]
+ public void AddAll()
+ {
+ hashbag.Add(3); hashbag.Add(4); hashbag.Add(4); hashbag.Add(5); hashbag.Add(4);
+
+ HashBag<int> hashbag2 = new HashBag<int>();
+
+ hashbag2.AddAll(hashbag);
+ Assert.IsTrue(IC.seteq(hashbag2, 3, 4, 4, 4, 5));
+ hashbag.Add(9);
+ hashbag.AddAll(hashbag2);
+ Assert.IsTrue(IC.seteq(hashbag2, 3, 4, 4, 4, 5));
+ Assert.IsTrue(IC.seteq(hashbag, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 9));
+ }
+
+
+ [Test]
+ public void ContainsCount()
+ {
+ Assert.AreEqual(0, hashbag.ContainsCount(5));
+ hashbag.Add(5);
+ Assert.AreEqual(1, hashbag.ContainsCount(5));
+ Assert.AreEqual(0, hashbag.ContainsCount(7));
+ hashbag.Add(8);
+ Assert.AreEqual(1, hashbag.ContainsCount(5));
+ Assert.AreEqual(0, hashbag.ContainsCount(7));
+ Assert.AreEqual(1, hashbag.ContainsCount(8));
+ hashbag.Add(5);
+ Assert.AreEqual(2, hashbag.ContainsCount(5));
+ Assert.AreEqual(0, hashbag.ContainsCount(7));
+ Assert.AreEqual(1, hashbag.ContainsCount(8));
+ }
+
+
+ [Test]
+ public void RemoveAllCopies()
+ {
+ hashbag.Add(5); hashbag.Add(7); hashbag.Add(5);
+ Assert.AreEqual(2, hashbag.ContainsCount(5));
+ Assert.AreEqual(1, hashbag.ContainsCount(7));
+ hashbag.RemoveAllCopies(5);
+ Assert.AreEqual(0, hashbag.ContainsCount(5));
+ Assert.AreEqual(1, hashbag.ContainsCount(7));
+ hashbag.Add(5); hashbag.Add(8); hashbag.Add(5);
+ hashbag.RemoveAllCopies(8);
+ Assert.IsTrue(IC.eq(hashbag, 7, 5, 5));
+ }
+
+
+ [Test]
+ public void ContainsAll()
+ {
+ HashBag<int> list2 = new HashBag<int>();
+
+ Assert.IsTrue(hashbag.ContainsAll(list2));
+ list2.Add(4);
+ Assert.IsFalse(hashbag.ContainsAll(list2));
+ hashbag.Add(4);
+ Assert.IsTrue(hashbag.ContainsAll(list2));
+ hashbag.Add(5);
+ Assert.IsTrue(hashbag.ContainsAll(list2));
+ list2.Add(20);
+ Assert.IsFalse(hashbag.ContainsAll(list2));
+ hashbag.Add(20);
+ Assert.IsTrue(hashbag.ContainsAll(list2));
+ list2.Add(4);
+ Assert.IsFalse(hashbag.ContainsAll(list2));
+ hashbag.Add(4);
+ Assert.IsTrue(hashbag.ContainsAll(list2));
+ }
+
+
+ [Test]
+ public void RetainAll()
+ {
+ HashBag<int> list2 = new HashBag<int>();
+
+ hashbag.Add(4); hashbag.Add(5); hashbag.Add(4); hashbag.Add(6); hashbag.Add(4);
+ list2.Add(5); list2.Add(4); list2.Add(7); list2.Add(4);
+ hashbag.RetainAll(list2);
+ Assert.IsTrue(IC.seteq(hashbag, 4, 4, 5));
+ hashbag.Add(6);
+ list2.Clear();
+ list2.Add(7); list2.Add(8); list2.Add(9);
+ hashbag.RetainAll(list2);
+ Assert.IsTrue(IC.eq(hashbag));
+ }
+
+
+ [Test]
+ public void RemoveAll()
+ {
+ HashBag<int> list2 = new HashBag<int>();
+
+ hashbag.Add(4); hashbag.Add(5); hashbag.Add(6); hashbag.Add(4); hashbag.Add(5);
+ list2.Add(5); list2.Add(4); list2.Add(7); list2.Add(4);
+ hashbag.RemoveAll(list2);
+ Assert.IsTrue(IC.seteq(hashbag, 5, 6));
+ hashbag.Add(5); hashbag.Add(4);
+ list2.Clear();
+ list2.Add(6); list2.Add(5);
+ hashbag.RemoveAll(list2);
+ Assert.IsTrue(IC.seteq(hashbag, 4, 5));
+ list2.Clear();
+ list2.Add(7); list2.Add(8); list2.Add(9);
+ hashbag.RemoveAll(list2);
+ Assert.IsTrue(IC.seteq(hashbag, 4, 5));
+ }
+
+
+ [Test]
+ public void Remove()
+ {
+ hashbag.Add(4); hashbag.Add(4); hashbag.Add(5); hashbag.Add(4); hashbag.Add(6);
+ Assert.IsFalse(hashbag.Remove(2));
+ Assert.IsTrue(hashbag.Remove(4));
+ Assert.IsTrue(IC.seteq(hashbag, 4, 4, 5, 6));
+ hashbag.Add(7);
+ hashbag.Add(21); hashbag.Add(37); hashbag.Add(53); hashbag.Add(69); hashbag.Add(53); hashbag.Add(85);
+ Assert.IsTrue(hashbag.Remove(5));
+ Assert.IsTrue(IC.seteq(hashbag, 4, 4, 6, 7, 21, 37, 53, 53, 69, 85));
+ Assert.IsFalse(hashbag.Remove(165));
+ Assert.IsTrue(hashbag.Check());
+ Assert.IsTrue(IC.seteq(hashbag, 4, 4, 6, 7, 21, 37, 53, 53, 69, 85));
+ Assert.IsTrue(hashbag.Remove(53));
+ Assert.IsTrue(IC.seteq(hashbag, 4, 4, 6, 7, 21, 37, 53, 69, 85));
+ Assert.IsTrue(hashbag.Remove(37));
+ Assert.IsTrue(IC.seteq(hashbag, 4, 4, 6, 7, 21, 53, 69, 85));
+ Assert.IsTrue(hashbag.Remove(85));
+ Assert.IsTrue(IC.seteq(hashbag, 4, 4, 6, 7, 21, 53, 69));
+ }
+
+
+ [TearDown]
+ public void Dispose() { hashbag = null; }
+ }
+
+ [TestFixture]
+ public class FindPredicate
+ {
+ private HashBag<int> list;
+ Fun<int, bool> pred;
+
+ [SetUp]
+ public void Init()
+ {
+ list = new HashBag<int>(TenEqualityComparer.Default);
+ pred = delegate(int i) { return i % 5 == 0; };
+ }
+
+ [TearDown]
+ public void Dispose() { list = null; }
+
+ [Test]
+ public void Find()
+ {
+ int i;
+ Assert.IsFalse(list.Find(pred, out i));
+ list.AddAll<int>(new int[] { 4, 22, 67, 37 });
+ Assert.IsFalse(list.Find(pred, out i));
+ list.AddAll<int>(new int[] { 45, 122, 675, 137 });
+ Assert.IsTrue(list.Find(pred, out i));
+ Assert.AreEqual(45, i);
+ }
+
+ }
+
+ [TestFixture]
+ public class UniqueItems
+ {
+ private HashBag<int> list;
+
+ [SetUp]
+ public void Init() { list = new HashBag<int>(); }
+
+ [TearDown]
+ public void Dispose() { list = null; }
+
+ [Test]
+ public void Test()
+ {
+ Assert.IsTrue(IC.seteq(list.UniqueItems()));
+ Assert.IsTrue(IC.seteq(list.ItemMultiplicities()));
+ list.AddAll<int>(new int[] { 7, 9, 7 });
+ Assert.IsTrue(IC.seteq(list.UniqueItems(), 7, 9));
+ Assert.IsTrue(IC.seteq(list.ItemMultiplicities(), 7, 2, 9, 1));
+ }
+ }
+
+ [TestFixture]
+ public class ArrayTest
+ {
+ private HashBag<int> hashbag;
+
+ int[] a;
+
+
+ [SetUp]
+ public void Init()
+ {
+ hashbag = new HashBag<int>();
+ a = new int[10];
+ for (int i = 0; i < 10; i++)
+ a[i] = 1000 + i;
+ }
+
+
+ [TearDown]
+ public void Dispose() { hashbag = null; }
+
+
+ private string aeq(int[] a, params int[] b)
+ {
+ if (a.Length != b.Length)
+ return "Lengths differ: " + a.Length + " != " + b.Length;
+
+ for (int i = 0; i < a.Length; i++)
+ if (a[i] != b[i])
+ return String.Format("{0}'th elements differ: {1} != {2}", i, a[i], b[i]);
+
+ return "Alles klar";
+ }
+
+
+ [Test]
+ public void ToArray()
+ {
+ Assert.AreEqual("Alles klar", aeq(hashbag.ToArray()));
+ hashbag.Add(7);
+ hashbag.Add(3);
+ hashbag.Add(10);
+ hashbag.Add(3);
+
+ int[] r = hashbag.ToArray();
+
+ Array.Sort(r);
+ Assert.AreEqual("Alles klar", aeq(r, 3, 3, 7, 10));
+ }
+
+
+ [Test]
+ public void CopyTo()
+ {
+ //Note: for small ints the itemequalityComparer is the identity!
+ hashbag.CopyTo(a, 1);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009));
+ hashbag.Add(6);
+ hashbag.CopyTo(a, 2);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 6, 1003, 1004, 1005, 1006, 1007, 1008, 1009));
+ hashbag.Add(4);
+ hashbag.Add(6);
+ hashbag.Add(9);
+ hashbag.CopyTo(a, 4);
+
+ //TODO: make independent of interequalityComparer
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 6, 1003, 6, 6, 9, 4, 1008, 1009));
+ hashbag.Clear();
+ hashbag.Add(7);
+ hashbag.CopyTo(a, 9);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 6, 1003, 6, 6, 9, 4, 1008, 7));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void CopyToBad()
+ {
+ hashbag.CopyTo(a, 11);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void CopyToBad2()
+ {
+ hashbag.CopyTo(a, -1);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void CopyToTooFar()
+ {
+ hashbag.Add(3);
+ hashbag.Add(8);
+ hashbag.CopyTo(a, 9);
+ }
+ }
+
+
+
+ [TestFixture]
+ public class HashingEquals
+ {
+ private ICollection<int> h1, h2;
+
+
+ [SetUp]
+ public void Init()
+ {
+ h1 = new HashBag<int>();
+ h2 = new LinkedList<int>();
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ h1 = h2 = null;
+ }
+
+
+ [Test]
+ public void Hashing()
+ {
+ Assert.AreEqual(h1.GetUnsequencedHashCode(), h2.GetUnsequencedHashCode());
+ h1.Add(7);
+ h2.Add(9);
+ Assert.IsTrue(h1.GetUnsequencedHashCode() != h2.GetUnsequencedHashCode());
+ h2.Add(7);
+ h1.Add(9);
+ Assert.IsTrue(h1.GetUnsequencedHashCode() == h2.GetUnsequencedHashCode());
+ }
+
+
+ [Test]
+ public void Equals()
+ {
+ Assert.IsTrue(h1.UnsequencedEquals(h2));
+// Code 1550734257, Pair (3 x 1602896434, 2 x 1186320090) number 169185 matched oth
+//er pair (3 x -1615223932, 2 x 1019546595)
+ h1.Add(1602896434);
+ h1.Add(1186320090);
+ h1.Add(1602896434);
+ h1.Add(1186320090);
+ h1.Add(1602896434);
+ h2.Add(-1615223932);
+ h2.Add(1019546595);
+ h2.Add(-1615223932);
+ h2.Add(1019546595);
+ h2.Add(-1615223932);
+ Assert.IsTrue(h1.GetUnsequencedHashCode() == h2.GetUnsequencedHashCode());
+ Assert.IsTrue(!h1.UnsequencedEquals(h2));
+ h1.Clear();
+ h2.Clear();
+ h1.Add(1);
+ h1.Add(2);
+ h2.Add(2);
+ h2.Add(1);
+ Assert.IsTrue(h1.GetUnsequencedHashCode() == h2.GetUnsequencedHashCode());
+ Assert.IsTrue(h1.UnsequencedEquals(h2));
+ }
+ }
+}
diff --git a/mcs/class/Mono.C5/1.0/Test/hashing/HashDictionaryTests.cs b/mcs/class/Mono.C5/1.0/Test/hashing/HashDictionaryTests.cs
new file mode 100644
index 00000000000..dfdaa98572b
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/Test/hashing/HashDictionaryTests.cs
@@ -0,0 +1,324 @@
+/*
+ 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 C5;
+using NUnit.Framework;
+using SCG = System.Collections.Generic;
+namespace C5UnitTests.hashtable.dictionary
+{
+ using DictionaryIntToInt = HashDictionary<int,int>;
+
+ [TestFixture]
+ public class GenericTesters
+ {
+ [Test]
+ public void TestEvents()
+ {
+ Fun<DictionaryIntToInt> factory = delegate() { return new DictionaryIntToInt(TenEqualityComparer.Default); };
+ new C5UnitTests.Templates.Events.DictionaryTester<DictionaryIntToInt>().Test(factory);
+ }
+ }
+
+ static class Factory
+ {
+ public static IDictionary<K, V> New<K, V>() { return new HashDictionary<K, V>(); }
+ }
+
+ [TestFixture]
+ public class Formatting
+ {
+ IDictionary<int, int> coll;
+ IFormatProvider rad16;
+ [SetUp]
+ public void Init() { coll = Factory.New<int, int>(); rad16 = new RadixFormatProvider(16); }
+ [TearDown]
+ public void Dispose() { coll = null; rad16 = null; }
+ [Test]
+ public void Format()
+ {
+ Assert.AreEqual("{ }", coll.ToString());
+ coll.Add(23, 67); coll.Add(45, 89);
+ Assert.AreEqual("{ 45 => 89, 23 => 67 }", coll.ToString());
+ Assert.AreEqual("{ 2D => 59, 17 => 43 }", coll.ToString(null, rad16));
+ Assert.AreEqual("{ 45 => 89, ... }", coll.ToString("L14", null));
+ Assert.AreEqual("{ 2D => 59, ... }", coll.ToString("L14", rad16));
+ }
+ }
+
+ [TestFixture]
+ public class HashDict
+ {
+ private HashDictionary<string, string> dict;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dict = new HashDictionary<string, string>();
+ //dict = TreeDictionary<string,string>.MakeNaturalO<string,string>();
+ }
+
+ [Test]
+ [ExpectedException(typeof(NullReferenceException))]
+ public void NullEqualityComparerinConstructor1()
+ {
+ new HashDictionary<int, int>(null);
+ }
+
+ [Test]
+ [ExpectedException(typeof(NullReferenceException))]
+ public void NullEqualityComparerinConstructor2()
+ {
+ new HashDictionary<int, int>(5, 0.5, null);
+ }
+
+ [Test]
+ public void Choose()
+ {
+ dict.Add("ER", "FOO");
+ Assert.AreEqual(new KeyValuePair<string, string>("ER", "FOO"), dict.Choose());
+ }
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void BadChoose()
+ {
+ dict.Choose();
+ }
+
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dict = null;
+ }
+
+
+ [Test]
+ public void Initial()
+ {
+ bool res;
+
+ Assert.IsFalse(dict.IsReadOnly);
+ Assert.AreEqual(0, dict.Count, "new dict should be empty");
+ dict.Add("A", "B");
+ Assert.AreEqual(1, dict.Count, "bad count");
+ Assert.AreEqual("B", dict["A"], "Wrong value for dict[A]");
+ dict.Add("C", "D");
+ Assert.AreEqual(2, dict.Count, "bad count");
+ Assert.AreEqual("B", dict["A"], "Wrong value");
+ Assert.AreEqual("D", dict["C"], "Wrong value");
+ res = dict.Remove("A");
+ Assert.IsTrue(res, "bad return value from Remove(A)");
+ Assert.AreEqual(1, dict.Count, "bad count");
+ Assert.AreEqual("D", dict["C"], "Wrong value of dict[C]");
+ res = dict.Remove("Z");
+ Assert.IsFalse(res, "bad return value from Remove(Z)");
+ Assert.AreEqual(1, dict.Count, "bad count");
+ Assert.AreEqual("D", dict["C"], "Wrong value of dict[C] (2)");
+ }
+
+
+ [Test]
+ public void Contains()
+ {
+ dict.Add("C", "D");
+ Assert.IsTrue(dict.Contains("C"));
+ Assert.IsFalse(dict.Contains("D"));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(DuplicateNotAllowedException), "Key being added: 'A'")]
+ public void IllegalAdd()
+ {
+ dict.Add("A", "B");
+ dict.Add("A", "B");
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void GettingNonExisting()
+ {
+ Console.WriteLine(dict["R"]);
+ }
+
+
+ [Test]
+ public void Setter()
+ {
+ dict["R"] = "UYGUY";
+ Assert.AreEqual("UYGUY", dict["R"]);
+ dict["R"] = "UIII";
+ Assert.AreEqual("UIII", dict["R"]);
+ dict["S"] = "VVV";
+ Assert.AreEqual("UIII", dict["R"]);
+ Assert.AreEqual("VVV", dict["S"]);
+ //dict.dump();
+ }
+
+ [Test]
+ public void CombinedOps()
+ {
+ dict["R"] = "UIII";
+ dict["S"] = "VVV";
+ dict["T"] = "XYZ";
+
+ string s;
+
+ Assert.IsTrue(dict.Remove("S", out s));
+ Assert.AreEqual("VVV", s);
+ Assert.IsFalse(dict.Contains("S"));
+ Assert.IsFalse(dict.Remove("A", out s));
+
+ //
+ Assert.IsTrue(dict.Find("T", out s));
+ Assert.AreEqual("XYZ", s);
+ Assert.IsFalse(dict.Find("A", out s));
+
+ //
+ Assert.IsTrue(dict.Update("R", "UHU"));
+ Assert.AreEqual("UHU", dict["R"]);
+ Assert.IsFalse(dict.Update("A", "W"));
+ Assert.IsFalse(dict.Contains("A"));
+
+ //
+ s = "KKK";
+ Assert.IsFalse(dict.FindOrAdd("B", ref s));
+ Assert.AreEqual("KKK", dict["B"]);
+ Assert.IsTrue(dict.FindOrAdd("T", ref s));
+ Assert.AreEqual("XYZ", s);
+
+ //
+ s = "LLL";
+ Assert.IsTrue(dict.UpdateOrAdd("R", s));
+ Assert.AreEqual("LLL", dict["R"]);
+ s = "MMM";
+ Assert.IsFalse(dict.UpdateOrAdd("C", s));
+ Assert.AreEqual("MMM", dict["C"]);
+ }
+
+ [Test]
+ public void DeepBucket()
+ {
+ HashDictionary<int, int> dict2 = new HashDictionary<int, int>();
+
+ for (int i = 0; i < 5; i++)
+ dict2[16 * i] = 5 * i;
+
+ for (int i = 0; i < 5; i++)
+ Assert.AreEqual(5 * i, dict2[16 * i]);
+
+ for (int i = 0; i < 5; i++)
+ dict2[16 * i] = 7 * i + 1;
+
+ for (int i = 0; i < 5; i++)
+ Assert.AreEqual(7 * i + 1, dict2[16 * i]);
+ Assert.IsTrue(dict.Check());
+ }
+ }
+
+
+
+ [TestFixture]
+ public class Enumerators
+ {
+ private HashDictionary<string, string> dict;
+
+ private SCG.IEnumerator<KeyValuePair<string, string>> dictenum;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dict = new HashDictionary<string, string>();
+ dict["S"] = "A";
+ dict["T"] = "B";
+ dict["R"] = "C";
+ dictenum = dict.GetEnumerator();
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dictenum = null;
+ dict = null;
+ }
+
+
+ [Test]
+ public void Keys()
+ {
+ SCG.IEnumerator<string> keys = dict.Keys.GetEnumerator();
+
+ Assert.IsTrue(keys.MoveNext());
+ Assert.AreEqual("R", keys.Current);
+ Assert.IsTrue(keys.MoveNext());
+ Assert.AreEqual("T", keys.Current);
+ Assert.IsTrue(keys.MoveNext());
+ Assert.AreEqual("S", keys.Current);
+ Assert.IsFalse(keys.MoveNext());
+ }
+
+
+ [Test]
+ public void Values()
+ {
+ SCG.IEnumerator<string> values = dict.Values.GetEnumerator();
+
+ Assert.IsTrue(values.MoveNext());
+ Assert.AreEqual("C", values.Current);
+ Assert.IsTrue(values.MoveNext());
+ Assert.AreEqual("B", values.Current);
+ Assert.IsTrue(values.MoveNext());
+ Assert.AreEqual("A", values.Current);
+ Assert.IsFalse(values.MoveNext());
+ }
+
+ [Test]
+ public void Fun()
+ {
+ Assert.AreEqual("B", dict.Fun("T"));
+ }
+
+
+ [Test]
+ public void NormalUse()
+ {
+ Assert.IsTrue(dictenum.MoveNext());
+ Assert.AreEqual(dictenum.Current, new KeyValuePair<string, string>("R", "C"));
+ Assert.IsTrue(dictenum.MoveNext());
+ Assert.AreEqual(dictenum.Current, new KeyValuePair<string, string>("T", "B"));
+ Assert.IsTrue(dictenum.MoveNext());
+ Assert.AreEqual(dictenum.Current, new KeyValuePair<string, string>("S", "A"));
+ Assert.IsFalse(dictenum.MoveNext());
+ }
+ }
+}
+
+
+
+
+
diff --git a/mcs/class/Mono.C5/1.0/Test/hashing/HashTableTests.cs b/mcs/class/Mono.C5/1.0/Test/hashing/HashTableTests.cs
new file mode 100644
index 00000000000..34197091356
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/Test/hashing/HashTableTests.cs
@@ -0,0 +1,1095 @@
+/*
+ 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 C5;
+using NUnit.Framework;
+using SCG = System.Collections.Generic;
+namespace C5UnitTests.hashtable.set
+{
+ using CollectionOfInt = HashSet<int>;
+
+ [TestFixture]
+ public class GenericTesters
+ {
+ [Test]
+ public void TestEvents()
+ {
+ Fun<CollectionOfInt> factory = delegate() { return new CollectionOfInt(TenEqualityComparer.Default); };
+ new C5UnitTests.Templates.Events.CollectionTester<CollectionOfInt>().Test(factory);
+ }
+
+ [Test]
+ public void Extensible()
+ {
+ C5UnitTests.Templates.Extensible.Clone.Tester<CollectionOfInt>();
+ C5UnitTests.Templates.Extensible.Serialization.Tester<CollectionOfInt>();
+ }
+ }
+
+ static class Factory
+ {
+ public static ICollection<T> New<T>() { return new HashSet<T>(); }
+ }
+
+
+ namespace Enumerable
+ {
+ [TestFixture]
+ public class Multiops
+ {
+ private HashSet<int> list;
+
+ private Fun<int, bool> always, never, even;
+
+
+ [SetUp]
+ public void Init()
+ {
+ list = new HashSet<int>();
+ always = delegate{return true;};
+ never = delegate{return false;};
+ even = delegate(int i){return i%2==0;};
+ }
+
+
+ [Test]
+ public void All()
+ {
+ Assert.IsTrue(list.All(always));
+ Assert.IsTrue(list.All(never));
+ Assert.IsTrue(list.All(even));
+ list.Add(0);
+ Assert.IsTrue(list.All(always));
+ Assert.IsFalse(list.All(never));
+ Assert.IsTrue(list.All(even));
+ list.Add(5);
+ Assert.IsTrue(list.All(always));
+ Assert.IsFalse(list.All(never));
+ Assert.IsFalse(list.All(even));
+ }
+
+
+ [Test]
+ public void Exists()
+ {
+ Assert.IsFalse(list.Exists(always));
+ Assert.IsFalse(list.Exists(never));
+ Assert.IsFalse(list.Exists(even));
+ list.Add(5);
+ Assert.IsTrue(list.Exists(always));
+ Assert.IsFalse(list.Exists(never));
+ Assert.IsFalse(list.Exists(even));
+ list.Add(8);
+ Assert.IsTrue(list.Exists(always));
+ Assert.IsFalse(list.Exists(never));
+ Assert.IsTrue(list.Exists(even));
+ }
+
+
+ [Test]
+ public void Apply()
+ {
+ int sum = 0;
+ Act<int> a = delegate(int i){sum=i+10*sum;};
+
+ list.Apply(a);
+ Assert.AreEqual(0, sum);
+ sum = 0;
+ list.Add(5);list.Add(8);list.Add(7);list.Add(5);
+ list.Apply(a);
+ Assert.AreEqual(758, sum);
+ }
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+ }
+
+
+
+ [TestFixture]
+ public class GetEnumerator
+ {
+ private HashSet<int> hashset;
+
+
+ [SetUp]
+ public void Init() { hashset = new HashSet<int>(); }
+
+
+ [Test]
+ public void Empty()
+ {
+ SCG.IEnumerator<int> e = hashset.GetEnumerator();
+
+ Assert.IsFalse(e.MoveNext());
+ }
+
+
+ [Test]
+ public void Normal()
+ {
+ hashset.Add(5);
+ hashset.Add(8);
+ hashset.Add(5);
+ hashset.Add(5);
+ hashset.Add(10);
+ hashset.Add(1);
+ hashset.Add(16);
+ hashset.Add(18);
+ hashset.Add(17);
+ hashset.Add(33);
+ Assert.IsTrue(IC.seteq(hashset, 1, 5, 8, 10, 16, 17, 18, 33));
+ }
+
+ [Test]
+ public void DoDispose()
+ {
+ hashset.Add(5);
+ hashset.Add(8);
+ hashset.Add(5);
+
+ SCG.IEnumerator<int> e = hashset.GetEnumerator();
+
+ e.MoveNext();
+ e.MoveNext();
+ e.Dispose();
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void MoveNextAfterUpdate()
+ {
+ hashset.Add(5);
+ hashset.Add(8);
+ hashset.Add(5);
+
+ SCG.IEnumerator<int> e = hashset.GetEnumerator();
+
+ e.MoveNext();
+ hashset.Add(99);
+ e.MoveNext();
+ }
+
+
+ [TearDown]
+ public void Dispose() { hashset = null; }
+ }
+ }
+
+ namespace CollectionOrSink
+ {
+ [TestFixture]
+ public class Formatting
+ {
+ ICollection<int> coll;
+ IFormatProvider rad16;
+ [SetUp]
+ public void Init() { coll = Factory.New<int>(); rad16 = new RadixFormatProvider(16); }
+ [TearDown]
+ public void Dispose() { coll = null; rad16 = null; }
+ [Test]
+ public void Format()
+ {
+ Assert.AreEqual("{ }", coll.ToString());
+ coll.AddAll<int>(new int[] { -4, 28, 129, 65530 });
+ Assert.AreEqual("{ 65530, -4, 28, 129 }", coll.ToString());
+ Assert.AreEqual("{ FFFA, -4, 1C, 81 }", coll.ToString(null, rad16));
+ Assert.AreEqual("{ 65530, -4, ... }", coll.ToString("L14", null));
+ Assert.AreEqual("{ FFFA, -4, ... }", coll.ToString("L14", rad16));
+ }
+ }
+
+ [TestFixture]
+ public class CollectionOrSink
+ {
+ private HashSet<int> hashset;
+
+
+ [SetUp]
+ public void Init() { hashset = new HashSet<int>(); }
+
+ [Test]
+ public void Choose()
+ {
+ hashset.Add(7);
+ Assert.AreEqual(7, hashset.Choose());
+ }
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void BadChoose()
+ {
+ hashset.Choose();
+ }
+
+ [Test]
+ public void CountEtAl()
+ {
+ Assert.AreEqual(0, hashset.Count);
+ Assert.IsTrue(hashset.IsEmpty);
+ Assert.IsFalse(hashset.AllowsDuplicates);
+ Assert.IsTrue(hashset.Add(0));
+ Assert.AreEqual(1, hashset.Count);
+ Assert.IsFalse(hashset.IsEmpty);
+ Assert.IsTrue(hashset.Add(5));
+ Assert.AreEqual(2, hashset.Count);
+ Assert.IsFalse(hashset.Add(5));
+ Assert.AreEqual(2, hashset.Count);
+ Assert.IsFalse(hashset.IsEmpty);
+ Assert.IsTrue(hashset.Add(8));
+ Assert.AreEqual(3, hashset.Count);
+ }
+
+
+ [Test]
+ public void AddAll()
+ {
+ hashset.Add(3);hashset.Add(4);hashset.Add(5);
+
+ HashSet<int> hashset2 = new HashSet<int>();
+
+ hashset2.AddAll(hashset);
+ Assert.IsTrue(IC.seteq(hashset2, 3, 4, 5));
+ hashset.Add(9);
+ hashset.AddAll(hashset2);
+ Assert.IsTrue(IC.seteq(hashset2, 3, 4, 5));
+ Assert.IsTrue(IC.seteq(hashset, 3, 4, 5, 9));
+ }
+
+
+ [TearDown]
+ public void Dispose() { hashset = null; }
+ }
+
+ [TestFixture]
+ public class FindPredicate
+ {
+ private HashSet<int> list;
+ Fun<int, bool> pred;
+
+ [SetUp]
+ public void Init()
+ {
+ list = new HashSet<int>(TenEqualityComparer.Default);
+ pred = delegate(int i) { return i % 5 == 0; };
+ }
+
+ [TearDown]
+ public void Dispose() { list = null; }
+
+ [Test]
+ public void Find()
+ {
+ int i;
+ Assert.IsFalse(list.Find(pred, out i));
+ list.AddAll<int>(new int[] { 4, 22, 67, 37 });
+ Assert.IsFalse(list.Find(pred, out i));
+ list.AddAll<int>(new int[] { 45, 122, 675, 137 });
+ Assert.IsTrue(list.Find(pred, out i));
+ Assert.AreEqual(45, i);
+ }
+ }
+
+ [TestFixture]
+ public class UniqueItems
+ {
+ private HashSet<int> list;
+
+ [SetUp]
+ public void Init() { list = new HashSet<int>(); }
+
+ [TearDown]
+ public void Dispose() { list = null; }
+
+ [Test]
+ public void Test()
+ {
+ Assert.IsTrue(IC.seteq(list.UniqueItems()));
+ Assert.IsTrue(IC.seteq(list.ItemMultiplicities()));
+ list.AddAll<int>(new int[] { 7, 9, 7 });
+ Assert.IsTrue(IC.seteq(list.UniqueItems(), 7, 9));
+ Assert.IsTrue(IC.seteq(list.ItemMultiplicities(), 7, 1, 9, 1));
+ }
+ }
+
+ [TestFixture]
+ public class ArrayTest
+ {
+ private HashSet<int> hashset;
+
+ int[] a;
+
+
+ [SetUp]
+ public void Init()
+ {
+ hashset = new HashSet<int>();
+ a = new int[10];
+ for (int i = 0; i < 10; i++)
+ a[i] = 1000 + i;
+ }
+
+
+ [TearDown]
+ public void Dispose() { hashset = null; }
+
+
+ private string aeq(int[] a, params int[] b)
+ {
+ if (a.Length != b.Length)
+ return "Lengths differ: " + a.Length + " != " + b.Length;
+
+ for (int i = 0; i < a.Length; i++)
+ if (a[i] != b[i])
+ return String.Format("{0}'th elements differ: {1} != {2}", i, a[i], b[i]);
+
+ return "Alles klar";
+ }
+
+
+ [Test]
+ public void ToArray()
+ {
+ Assert.AreEqual("Alles klar", aeq(hashset.ToArray()));
+ hashset.Add(7);
+ hashset.Add(3);
+ hashset.Add(10);
+
+ int[] r = hashset.ToArray();
+
+ Array.Sort(r);
+ Assert.AreEqual("Alles klar", aeq(r, 3, 7, 10));
+ }
+
+
+ [Test]
+ public void CopyTo()
+ {
+ //Note: for small ints the itemequalityComparer is the identity!
+ hashset.CopyTo(a, 1);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009));
+ hashset.Add(6);
+ hashset.CopyTo(a, 2);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 6, 1003, 1004, 1005, 1006, 1007, 1008, 1009));
+ hashset.Add(4);
+ hashset.Add(9);
+ hashset.CopyTo(a, 4);
+
+ //TODO: make test independent on onterequalityComparer
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 6, 1003, 6, 9, 4, 1007, 1008, 1009));
+ hashset.Clear();
+ hashset.Add(7);
+ hashset.CopyTo(a, 9);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 6, 1003, 6, 9, 4, 1007, 1008, 7));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void CopyToBad()
+ {
+ hashset.CopyTo(a, 11);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void CopyToBad2()
+ {
+ hashset.CopyTo(a, -1);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void CopyToTooFar()
+ {
+ hashset.Add(3);
+ hashset.Add(8);
+ hashset.CopyTo(a, 9);
+ }
+ }
+
+
+
+ [TestFixture]
+ public class Sync
+ {
+ private HashSet<int> list;
+
+
+ [SetUp]
+ public void Init()
+ {
+ list = new HashSet<int>();
+ }
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+
+
+ [Test]
+ public void Get()
+ {
+ Assert.IsNotNull(list.SyncRoot);
+ }
+ }
+ }
+
+
+
+
+ namespace EditableCollection
+ {
+ [TestFixture]
+ public class Collision
+ {
+ HashSet<int> hashset;
+
+
+ [SetUp]
+ public void Init()
+ {
+ hashset = new HashSet<int>();
+ }
+
+
+ [Test]
+ public void SingleCollision()
+ {
+ hashset.Add(7);
+ hashset.Add(7 - 1503427877);
+
+ //foreach (int cell in hashset) Console.WriteLine("A: {0}", cell);
+ hashset.Remove(7);
+ Assert.IsTrue(hashset.Contains(7 - 1503427877));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ hashset = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class Searching
+ {
+ private HashSet<int> hashset;
+
+
+ [SetUp]
+ public void Init() { hashset = new HashSet<int>(); }
+
+
+ [Test]
+ [ExpectedException(typeof(NullReferenceException))]
+ public void NullEqualityComparerinConstructor1()
+ {
+ new HashSet<int>(null);
+ }
+
+ [Test]
+ [ExpectedException(typeof(NullReferenceException))]
+ public void NullEqualityComparerinConstructor2()
+ {
+ new HashSet<int>(5, null);
+ }
+
+ [Test]
+ [ExpectedException(typeof(NullReferenceException))]
+ public void NullEqualityComparerinConstructor3()
+ {
+ new HashSet<int>(5, 0.5, null);
+ }
+
+ [Test]
+ public void Contains()
+ {
+ Assert.IsFalse(hashset.Contains(5));
+ hashset.Add(5);
+ Assert.IsTrue(hashset.Contains(5));
+ Assert.IsFalse(hashset.Contains(7));
+ hashset.Add(8);
+ hashset.Add(10);
+ Assert.IsTrue(hashset.Contains(5));
+ Assert.IsFalse(hashset.Contains(7));
+ Assert.IsTrue(hashset.Contains(8));
+ Assert.IsTrue(hashset.Contains(10));
+ hashset.Remove(8);
+ Assert.IsTrue(hashset.Contains(5));
+ Assert.IsFalse(hashset.Contains(7));
+ Assert.IsFalse(hashset.Contains(8));
+ Assert.IsTrue(hashset.Contains(10));
+ hashset.Add(0);hashset.Add(16);hashset.Add(32);hashset.Add(48);hashset.Add(64);
+ Assert.IsTrue(hashset.Contains(0));
+ Assert.IsTrue(hashset.Contains(16));
+ Assert.IsTrue(hashset.Contains(32));
+ Assert.IsTrue(hashset.Contains(48));
+ Assert.IsTrue(hashset.Contains(64));
+ Assert.IsTrue(hashset.Check());
+
+ int i = 0, j = i;
+
+ Assert.IsTrue(hashset.Find(ref i));
+ Assert.AreEqual(j, i);
+ j = i = 16;
+ Assert.IsTrue(hashset.Find(ref i));
+ Assert.AreEqual(j, i);
+ j = i = 32;
+ Assert.IsTrue(hashset.Find(ref i));
+ Assert.AreEqual(j, i);
+ j = i = 48;
+ Assert.IsTrue(hashset.Find(ref i));
+ Assert.AreEqual(j, i);
+ j = i = 64;
+ Assert.IsTrue(hashset.Find(ref i));
+ Assert.AreEqual(j, i);
+ j = i = 80;
+ Assert.IsFalse(hashset.Find(ref i));
+ Assert.AreEqual(j, i);
+ }
+
+
+ [Test]
+ public void Many()
+ {
+ int j = 7373;
+ int[] a = new int[j];
+
+ for (int i = 0; i < j; i++)
+ {
+ hashset.Add(3 * i + 1);
+ a[i] = 3 * i + 1;
+ }
+
+ Assert.IsTrue(IC.seteq(hashset, a));
+ }
+
+
+ [Test]
+ public void ContainsCount()
+ {
+ Assert.AreEqual(0, hashset.ContainsCount(5));
+ hashset.Add(5);
+ Assert.AreEqual(1, hashset.ContainsCount(5));
+ Assert.AreEqual(0, hashset.ContainsCount(7));
+ hashset.Add(8);
+ Assert.AreEqual(1, hashset.ContainsCount(5));
+ Assert.AreEqual(0, hashset.ContainsCount(7));
+ Assert.AreEqual(1, hashset.ContainsCount(8));
+ hashset.Add(5);
+ Assert.AreEqual(1, hashset.ContainsCount(5));
+ Assert.AreEqual(0, hashset.ContainsCount(7));
+ Assert.AreEqual(1, hashset.ContainsCount(8));
+ }
+
+
+ [Test]
+ public void RemoveAllCopies()
+ {
+ hashset.Add(5);hashset.Add(7);hashset.Add(5);
+ Assert.AreEqual(1, hashset.ContainsCount(5));
+ Assert.AreEqual(1, hashset.ContainsCount(7));
+ hashset.RemoveAllCopies(5);
+ Assert.AreEqual(0, hashset.ContainsCount(5));
+ Assert.AreEqual(1, hashset.ContainsCount(7));
+ hashset.Add(5);hashset.Add(8);hashset.Add(5);
+ hashset.RemoveAllCopies(8);
+ Assert.IsTrue(IC.eq(hashset, 7, 5));
+ }
+
+
+ [Test]
+ public void ContainsAll()
+ {
+ HashSet<int> list2 = new HashSet<int>();
+
+ Assert.IsTrue(hashset.ContainsAll(list2));
+ list2.Add(4);
+ Assert.IsFalse(hashset.ContainsAll(list2));
+ hashset.Add(4);
+ Assert.IsTrue(hashset.ContainsAll(list2));
+ hashset.Add(5);
+ Assert.IsTrue(hashset.ContainsAll(list2));
+ list2.Add(20);
+ Assert.IsFalse(hashset.ContainsAll(list2));
+ hashset.Add(20);
+ Assert.IsTrue(hashset.ContainsAll(list2));
+ }
+
+
+ [Test]
+ public void RetainAll()
+ {
+ HashSet<int> list2 = new HashSet<int>();
+
+ hashset.Add(4);hashset.Add(5);hashset.Add(6);
+ list2.Add(5);list2.Add(4);list2.Add(7);
+ hashset.RetainAll(list2);
+ Assert.IsTrue(IC.seteq(hashset, 4, 5));
+ hashset.Add(6);
+ list2.Clear();
+ list2.Add(7);list2.Add(8);list2.Add(9);
+ hashset.RetainAll(list2);
+ Assert.IsTrue(IC.seteq(hashset));
+ }
+
+
+ [Test]
+ public void RemoveAll()
+ {
+ HashSet<int> list2 = new HashSet<int>();
+
+ hashset.Add(4);hashset.Add(5);hashset.Add(6);
+ list2.Add(5);list2.Add(7);list2.Add(4);
+ hashset.RemoveAll(list2);
+ Assert.IsTrue(IC.eq(hashset, 6));
+ hashset.Add(5);hashset.Add(4);
+ list2.Clear();
+ list2.Add(6);list2.Add(5);
+ hashset.RemoveAll(list2);
+ Assert.IsTrue(IC.eq(hashset, 4));
+ list2.Clear();
+ list2.Add(7);list2.Add(8);list2.Add(9);
+ hashset.RemoveAll(list2);
+ Assert.IsTrue(IC.eq(hashset, 4));
+ }
+
+
+ [Test]
+ public void Remove()
+ {
+ hashset.Add(4);hashset.Add(4);hashset.Add(5);hashset.Add(4);hashset.Add(6);
+ Assert.IsFalse(hashset.Remove(2));
+ Assert.IsTrue(hashset.Remove(4));
+ Assert.IsTrue(IC.seteq(hashset, 5, 6));
+ hashset.Add(7);
+ hashset.Add(21);hashset.Add(37);hashset.Add(53);hashset.Add(69);hashset.Add(85);
+ Assert.IsTrue(hashset.Remove(5));
+ Assert.IsTrue(IC.seteq(hashset, 6, 7, 21, 37, 53, 69, 85));
+ Assert.IsFalse(hashset.Remove(165));
+ Assert.IsTrue(IC.seteq(hashset, 6, 7, 21, 37, 53, 69, 85));
+ Assert.IsTrue(hashset.Remove(53));
+ Assert.IsTrue(IC.seteq(hashset, 6, 7, 21, 37, 69, 85));
+ Assert.IsTrue(hashset.Remove(37));
+ Assert.IsTrue(IC.seteq(hashset, 6, 7, 21, 69, 85));
+ Assert.IsTrue(hashset.Remove(85));
+ Assert.IsTrue(IC.seteq(hashset, 6, 7, 21, 69));
+ }
+
+
+ [Test]
+ public void Clear()
+ {
+ hashset.Add(7);hashset.Add(7);
+ hashset.Clear();
+ Assert.IsTrue(hashset.IsEmpty);
+ }
+
+
+ [TearDown]
+ public void Dispose() { hashset = null; }
+ }
+
+ [TestFixture]
+ public class Combined
+ {
+ private ICollection<KeyValuePair<int,int>> lst;
+
+
+ [SetUp]
+ public void Init()
+ {
+ lst = new HashSet<KeyValuePair<int, int>>(new KeyValuePairEqualityComparer<int, int>());
+ for (int i = 0; i < 10; i++)
+ lst.Add(new KeyValuePair<int,int>(i, i + 30));
+ }
+
+
+ [TearDown]
+ public void Dispose() { lst = null; }
+
+
+ [Test]
+ public void Find()
+ {
+ KeyValuePair<int,int> p = new KeyValuePair<int,int>(3, 78);
+
+ Assert.IsTrue(lst.Find(ref p));
+ Assert.AreEqual(3, p.Key);
+ Assert.AreEqual(33, p.Value);
+ p = new KeyValuePair<int,int>(13, 78);
+ Assert.IsFalse(lst.Find(ref p));
+ }
+
+
+ [Test]
+ public void FindOrAdd()
+ {
+ KeyValuePair<int,int> p = new KeyValuePair<int,int>(3, 78);
+ KeyValuePair<int,int> q = new KeyValuePair<int,int>();
+
+ Assert.IsTrue(lst.FindOrAdd(ref p));
+ Assert.AreEqual(3, p.Key);
+ Assert.AreEqual(33, p.Value);
+ p = new KeyValuePair<int,int>(13, 79);
+ Assert.IsFalse(lst.FindOrAdd(ref p));
+ q.Key = 13;
+ Assert.IsTrue(lst.Find(ref q));
+ Assert.AreEqual(13, q.Key);
+ Assert.AreEqual(79, q.Value);
+ }
+
+
+ [Test]
+ public void Update()
+ {
+ KeyValuePair<int,int> p = new KeyValuePair<int,int>(3, 78);
+ KeyValuePair<int,int> q = new KeyValuePair<int,int>();
+
+ Assert.IsTrue(lst.Update(p));
+ q.Key = 3;
+ Assert.IsTrue(lst.Find(ref q));
+ Assert.AreEqual(3, q.Key);
+ Assert.AreEqual(78, q.Value);
+ p = new KeyValuePair<int,int>(13, 78);
+ Assert.IsFalse(lst.Update(p));
+ }
+
+
+ [Test]
+ public void UpdateOrAdd()
+ {
+ KeyValuePair<int,int> p = new KeyValuePair<int,int>(3, 78);
+ KeyValuePair<int,int> q = new KeyValuePair<int,int>();
+
+ Assert.IsTrue(lst.UpdateOrAdd(p));
+ q.Key = 3;
+ Assert.IsTrue(lst.Find(ref q));
+ Assert.AreEqual(3, q.Key);
+ Assert.AreEqual(78, q.Value);
+ p = new KeyValuePair<int,int>(13, 79);
+ Assert.IsFalse(lst.UpdateOrAdd(p));
+ q.Key = 13;
+ Assert.IsTrue(lst.Find(ref q));
+ Assert.AreEqual(13, q.Key);
+ Assert.AreEqual(79, q.Value);
+ }
+
+
+ [Test]
+ public void RemoveWithReturn()
+ {
+ KeyValuePair<int,int> p = new KeyValuePair<int,int>(3, 78);
+ //KeyValuePair<int,int> q = new KeyValuePair<int,int>();
+
+ Assert.IsTrue(lst.Remove(p, out p));
+ Assert.AreEqual(3, p.Key);
+ Assert.AreEqual(33, p.Value);
+ p = new KeyValuePair<int,int>(13, 78);
+ Assert.IsFalse(lst.Remove(p, out p));
+ }
+ }
+
+
+ }
+
+
+
+
+ namespace HashingAndEquals
+ {
+ [TestFixture]
+ public class IEditableCollection
+ {
+ private ICollection<int> dit, dat, dut;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new HashSet<int>();
+ dat = new HashSet<int>();
+ dut = new HashSet<int>();
+ }
+
+
+ [Test]
+ public void EmptyEmpty()
+ {
+ Assert.IsTrue(dit.UnsequencedEquals(dat));
+ }
+
+
+ [Test]
+ public void EmptyNonEmpty()
+ {
+ dit.Add(3);
+ Assert.IsFalse(dit.UnsequencedEquals(dat));
+ Assert.IsFalse(dat.UnsequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void HashVal()
+ {
+ Assert.AreEqual(CHC.unsequencedhashcode(), dit.GetUnsequencedHashCode());
+ dit.Add(3);
+ Assert.AreEqual(CHC.unsequencedhashcode(3), dit.GetUnsequencedHashCode());
+ dit.Add(7);
+ Assert.AreEqual(CHC.unsequencedhashcode(3, 7), dit.GetUnsequencedHashCode());
+ Assert.AreEqual(CHC.unsequencedhashcode(), dut.GetUnsequencedHashCode());
+ dut.Add(3);
+ Assert.AreEqual(CHC.unsequencedhashcode(3), dut.GetUnsequencedHashCode());
+ dut.Add(7);
+ Assert.AreEqual(CHC.unsequencedhashcode(7, 3), dut.GetUnsequencedHashCode());
+ }
+
+
+ [Test]
+ public void EqualHashButDifferent()
+ {
+ dit.Add(-1657792980);dit.Add(-1570288808);
+ dat.Add(1862883298);dat.Add(-272461342);
+ Assert.AreEqual(dit.GetUnsequencedHashCode(), dat.GetUnsequencedHashCode());
+ Assert.IsFalse(dit.UnsequencedEquals(dat));
+ }
+
+
+ [Test]
+ public void Normal()
+ {
+ dit.Add(3);
+ dit.Add(7);
+ dat.Add(3);
+ Assert.IsFalse(dit.UnsequencedEquals(dat));
+ Assert.IsFalse(dat.UnsequencedEquals(dit));
+ dat.Add(7);
+ Assert.IsTrue(dit.UnsequencedEquals(dat));
+ Assert.IsTrue(dat.UnsequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void WrongOrder()
+ {
+ dit.Add(3);
+ dut.Add(3);
+ Assert.IsTrue(dit.UnsequencedEquals(dut));
+ Assert.IsTrue(dut.UnsequencedEquals(dit));
+ dit.Add(7);
+ dut.Add(7);
+ Assert.IsTrue(dit.UnsequencedEquals(dut));
+ Assert.IsTrue(dut.UnsequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void Reflexive()
+ {
+ Assert.IsTrue(dit.UnsequencedEquals(dit));
+ dit.Add(3);
+ Assert.IsTrue(dit.UnsequencedEquals(dit));
+ dit.Add(7);
+ Assert.IsTrue(dit.UnsequencedEquals(dit));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = null;
+ dat = null;
+ dut = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class MultiLevelUnorderedOfUnOrdered
+ {
+ private ICollection<int> dit, dat, dut;
+
+ private ICollection<ICollection<int>> Dit, Dat, Dut;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new HashSet<int>();
+ dat = new HashSet<int>();
+ dut = new HashSet<int>();
+ dit.Add(2);dit.Add(1);
+ dat.Add(1);dat.Add(2);
+ dut.Add(3);
+ Dit = new HashSet<ICollection<int>>();
+ Dat = new HashSet<ICollection<int>>();
+ Dut = new HashSet<ICollection<int>>();
+ }
+
+
+ [Test]
+ public void Check()
+ {
+ Assert.IsTrue(dit.UnsequencedEquals(dat));
+ Assert.IsFalse(dit.UnsequencedEquals(dut));
+ }
+
+
+ [Test]
+ public void Multi()
+ {
+ Dit.Add(dit);Dit.Add(dut);Dit.Add(dit);
+ Dat.Add(dut);Dat.Add(dit);Dat.Add(dat);
+ Assert.IsTrue(Dit.UnsequencedEquals(Dat));
+ Assert.IsFalse(Dit.UnsequencedEquals(Dut));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = dat = dut = null;
+ Dit = Dat = Dut = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class MultiLevelOrderedOfUnOrdered
+ {
+ private ICollection<int> dit, dat, dut;
+
+ private ISequenced<ICollection<int>> Dit, Dat, Dut;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new HashSet<int>();
+ dat = new HashSet<int>();
+ dut = new HashSet<int>();
+ dit.Add(2);dit.Add(1);
+ dat.Add(1);dat.Add(2);
+ dut.Add(3);
+ Dit = new LinkedList<ICollection<int>>();
+ Dat = new LinkedList<ICollection<int>>();
+ Dut = new LinkedList<ICollection<int>>();
+ }
+
+
+ [Test]
+ public void Check()
+ {
+ Assert.IsTrue(dit.UnsequencedEquals(dat));
+ Assert.IsFalse(dit.UnsequencedEquals(dut));
+ }
+
+
+ [Test]
+ public void Multi()
+ {
+ Dit.Add(dit);Dit.Add(dut);Dit.Add(dit);
+ Dat.Add(dut);Dat.Add(dit);Dat.Add(dat);
+ Dut.Add(dit);Dut.Add(dut);Dut.Add(dat);
+ Assert.IsFalse(Dit.SequencedEquals(Dat));
+ Assert.IsTrue(Dit.SequencedEquals(Dut));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = dat = dut = null;
+ Dit = Dat = Dut = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class MultiLevelUnOrderedOfOrdered
+ {
+ private ISequenced<int> dit, dat, dut, dot;
+
+ private ICollection<ISequenced<int>> Dit, Dat, Dut, Dot;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new LinkedList<int>();
+ dat = new LinkedList<int>();
+ dut = new LinkedList<int>();
+ dot = new LinkedList<int>();
+ dit.Add(2);dit.Add(1);
+ dat.Add(1);dat.Add(2);
+ dut.Add(3);
+ dot.Add(2);dot.Add(1);
+ Dit = new HashSet<ISequenced<int>>();
+ Dat = new HashSet<ISequenced<int>>();
+ Dut = new HashSet<ISequenced<int>>();
+ Dot = new HashSet<ISequenced<int>>();
+ }
+
+
+ [Test]
+ public void Check()
+ {
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ Assert.IsTrue(dit.SequencedEquals(dot));
+ Assert.IsFalse(dit.SequencedEquals(dut));
+ }
+
+
+ [Test]
+ public void Multi()
+ {
+ Dit.Add(dit);Dit.Add(dut);//Dit.Add(dit);
+ Dat.Add(dut);Dat.Add(dit);Dat.Add(dat);
+ Dut.Add(dot);Dut.Add(dut);//Dut.Add(dit);
+ Dot.Add(dit);Dot.Add(dit);Dot.Add(dut);
+ Assert.IsTrue(Dit.UnsequencedEquals(Dit));
+ Assert.IsTrue(Dit.UnsequencedEquals(Dut));
+ Assert.IsFalse(Dit.UnsequencedEquals(Dat));
+ Assert.IsTrue(Dit.UnsequencedEquals(Dot));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = dat = dut = dot = null;
+ Dit = Dat = Dut = Dot = null;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/1.0/Test/heaps/HeapTests.cs b/mcs/class/Mono.C5/1.0/Test/heaps/HeapTests.cs
new file mode 100644
index 00000000000..e0e3dfdf8ed
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/Test/heaps/HeapTests.cs
@@ -0,0 +1,551 @@
+/*
+ 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 C5;
+using NUnit.Framework;
+using SCG = System.Collections.Generic;
+
+namespace C5UnitTests.heaps
+{
+ using CollectionOfInt = IntervalHeap<int>;
+
+ [TestFixture]
+ public class GenericTesters
+ {
+ [Test]
+ public void TestEvents()
+ {
+ Fun<CollectionOfInt> factory = delegate() { return new CollectionOfInt(TenEqualityComparer.Default); };
+ new C5UnitTests.Templates.Events.PriorityQueueTester<CollectionOfInt>().Test(factory);
+ }
+
+ [Test]
+ public void Extensible()
+ {
+ C5UnitTests.Templates.Extensible.Clone.Tester<CollectionOfInt>();
+ C5UnitTests.Templates.Extensible.Serialization.Tester<CollectionOfInt>();
+ }
+ }
+
+ [TestFixture]
+ public class Events
+ {
+ IPriorityQueue<int> queue;
+ ArrayList<KeyValuePair<Acts, int>> events;
+
+
+ [SetUp]
+ public void Init()
+ {
+ queue = new IntervalHeap<int>();
+ events = new ArrayList<KeyValuePair<Acts, int>>();
+ }
+
+
+ [TearDown]
+ public void Dispose() { queue = null; events = null; }
+
+ [Test]
+ public void Listenable()
+ {
+ Assert.AreEqual(EventTypeEnum.Basic, queue.ListenableEvents);
+ }
+
+ enum Acts
+ {
+ Add, Remove, Changed
+ }
+
+ [Test]
+ public void Direct()
+ {
+ CollectionChangedHandler<int> cch;
+ ItemsAddedHandler<int> iah;
+ ItemsRemovedHandler<int> irh;
+ Assert.AreEqual(EventTypeEnum.None, queue.ActiveEvents);
+ queue.CollectionChanged += (cch = new CollectionChangedHandler<int>(queue_CollectionChanged));
+ Assert.AreEqual(EventTypeEnum.Changed, queue.ActiveEvents);
+ queue.ItemsAdded += (iah = new ItemsAddedHandler<int>(queue_ItemAdded));
+ Assert.AreEqual(EventTypeEnum.Changed | EventTypeEnum.Added, queue.ActiveEvents);
+ queue.ItemsRemoved += (irh = new ItemsRemovedHandler<int>(queue_ItemRemoved));
+ Assert.AreEqual(EventTypeEnum.Changed | EventTypeEnum.Added | EventTypeEnum.Removed, queue.ActiveEvents);
+ queue.Add(34);
+ queue.Add(56);
+ queue.AddAll<int>(new int[] {});
+ queue.Add(34);
+ queue.Add(12);
+ queue.DeleteMax();
+ queue.DeleteMin();
+ queue.AddAll<int>(new int[] { 4, 5, 6, 2 });
+ Assert.AreEqual(17, events.Count);
+ int[] vals = { 34, 0, 56, 0, 34, 0, 12, 0, 56, 0, 12, 0, 4, 5, 6, 2, 0 };
+ Acts[] acts = { Acts.Add, Acts.Changed, Acts.Add, Acts.Changed, Acts.Add, Acts.Changed, Acts.Add, Acts.Changed,
+ Acts.Remove, Acts.Changed, Acts.Remove, Acts.Changed, Acts.Add, Acts.Add, Acts.Add, Acts.Add, Acts.Changed };
+ for (int i = 0; i < vals.Length; i++)
+ {
+ //Console.WriteLine("{0}", events[cell]);
+ Assert.AreEqual(acts[i], events[i].Key, "Action " + i);
+ Assert.AreEqual(vals[i], events[i].Value, "Value " + i);
+ }
+ queue.CollectionChanged -= cch;
+ Assert.AreEqual(EventTypeEnum.Added | EventTypeEnum.Removed, queue.ActiveEvents);
+ queue.ItemsAdded -= iah;
+ Assert.AreEqual(EventTypeEnum.Removed, queue.ActiveEvents);
+ queue.ItemsRemoved -= irh;
+ Assert.AreEqual(EventTypeEnum.None, queue.ActiveEvents);
+ }
+
+ [Test]
+ public void Guarded()
+ {
+ ICollectionValue<int> guarded = new GuardedCollectionValue<int>(queue);
+ guarded.CollectionChanged += new CollectionChangedHandler<int>(queue_CollectionChanged);
+ guarded.ItemsAdded += new ItemsAddedHandler<int>(queue_ItemAdded);
+ guarded.ItemsRemoved += new ItemsRemovedHandler<int>(queue_ItemRemoved);
+ queue.Add(34);
+ queue.Add(56);
+ queue.Add(34);
+ queue.Add(12);
+ queue.DeleteMax();
+ queue.DeleteMin();
+ queue.AddAll<int>(new int[] { 4, 5, 6, 2 });
+ Assert.AreEqual(17, events.Count);
+ int[] vals = { 34, 0, 56, 0, 34, 0, 12, 0, 56, 0, 12, 0, 4, 5, 6, 2, 0 };
+ Acts[] acts = { Acts.Add, Acts.Changed, Acts.Add, Acts.Changed, Acts.Add, Acts.Changed, Acts.Add, Acts.Changed,
+ Acts.Remove, Acts.Changed, Acts.Remove, Acts.Changed, Acts.Add, Acts.Add, Acts.Add, Acts.Add, Acts.Changed };
+ for (int i = 0; i < vals.Length; i++)
+ {
+ //Console.WriteLine("{0}", events[cell]);
+ Assert.AreEqual(vals[i], events[i].Value);
+ Assert.AreEqual(acts[i], events[i].Key);
+ }
+ }
+
+
+ void queue_CollectionChanged(object sender)
+ {
+ events.Add(new KeyValuePair<Acts, int>(Acts.Changed, 0));
+ }
+ void queue_ItemAdded(object sender, ItemCountEventArgs<int> e)
+ {
+ events.Add(new KeyValuePair<Acts, int>(Acts.Add, e.Item));
+ }
+ void queue_ItemRemoved(object sender, ItemCountEventArgs<int> e)
+ {
+ events.Add(new KeyValuePair<Acts, int>(Acts.Remove, e.Item));
+ }
+ }
+
+ [TestFixture]
+ public class Formatting
+ {
+ IntervalHeap<int> coll;
+ IFormatProvider rad16;
+ [SetUp]
+ public void Init() { coll = new IntervalHeap<int>(); rad16 = new RadixFormatProvider(16); }
+ [TearDown]
+ public void Dispose() { coll = null; rad16 = null; }
+ [Test]
+ public void Format()
+ {
+ Assert.AreEqual("{ }", coll.ToString());
+ coll.AddAll<int>(new int[] { -4, 28, 129, 65530 });
+ Assert.AreEqual("{ -4, 65530, 28, 129 }", coll.ToString());
+ Assert.AreEqual("{ -4, FFFA, 1C, 81 }", coll.ToString(null, rad16));
+ Assert.AreEqual("{ -4, 65530, ... }", coll.ToString("L14", null));
+ Assert.AreEqual("{ -4, FFFA, ... }", coll.ToString("L14", rad16));
+ }
+ }
+
+
+ [TestFixture]
+ public class IntervalHeapTests
+ {
+ IPriorityQueue<int> queue;
+
+
+ [SetUp]
+ public void Init() { queue = new IntervalHeap<int>(); }
+
+
+ [TearDown]
+ public void Dispose() { queue = null; }
+
+ [Test]
+ [ExpectedException(typeof(NullReferenceException))]
+ public void NullEqualityComparerinConstructor1()
+ {
+ new IntervalHeap<int>(null);
+ }
+
+ [Test]
+ [ExpectedException(typeof(NullReferenceException))]
+ public void NullEqualityComparerinConstructor2()
+ {
+ new IntervalHeap<int>(5, null);
+ }
+
+ [Test]
+ public void Handles()
+ {
+ IPriorityQueueHandle<int>[] handles = new IPriorityQueueHandle<int>[10];
+
+ queue.Add(ref handles[0], 7);
+ Assert.IsTrue(queue.Check());
+ queue.Add(ref handles[1], 72);
+ Assert.IsTrue(queue.Check());
+ queue.Add(ref handles[2], 27);
+ Assert.IsTrue(queue.Check());
+ queue.Add(ref handles[3], 17);
+ Assert.IsTrue(queue.Check());
+ queue.Add(ref handles[4], 70);
+ Assert.IsTrue(queue.Check());
+ queue.Add(ref handles[5], 1);
+ Assert.IsTrue(queue.Check());
+ queue.Add(ref handles[6], 2);
+ Assert.IsTrue(queue.Check());
+ queue.Add(ref handles[7], 7);
+ Assert.IsTrue(queue.Check());
+ queue.Add(ref handles[8], 8);
+ Assert.IsTrue(queue.Check());
+ queue.Add(ref handles[9], 9);
+ Assert.IsTrue(queue.Check());
+ queue.Delete(handles[2]);
+ Assert.IsTrue(queue.Check());
+ queue.Delete(handles[0]);
+ Assert.IsTrue(queue.Check());
+ queue.Delete(handles[8]);
+ Assert.IsTrue(queue.Check());
+ queue.Delete(handles[4]);
+ Assert.IsTrue(queue.Check());
+ queue.Delete(handles[6]);
+ Assert.IsTrue(queue.Check());
+ Assert.AreEqual(5, queue.Count);
+ }
+
+ [Test]
+ public void Replace()
+ {
+ IPriorityQueueHandle<int> handle = null;
+ queue.Add(6);
+ queue.Add(10);
+ queue.Add(ref handle, 7);
+ queue.Add(21);
+ Assert.AreEqual(7, queue.Replace(handle, 12));
+ Assert.AreEqual(21, queue.FindMax());
+ Assert.AreEqual(12, queue.Replace(handle, 34));
+ Assert.AreEqual(34, queue.FindMax());
+ Assert.IsTrue(queue.Check());
+ //replace max
+ Assert.AreEqual(34, queue.Replace(handle, 60));
+ Assert.AreEqual(60, queue.FindMax());
+ Assert.AreEqual(60, queue.Replace(handle, queue[handle] + 80));
+ Assert.AreEqual(140, queue.FindMax());
+ Assert.IsTrue(queue.Check());
+ }
+
+ [Test]
+ public void Replace2()
+ {
+ IPriorityQueueHandle<int> handle = null;
+ queue.Add(6);
+ queue.Add(10);
+ queue.Add(ref handle, 7);
+ //Replace last item in queue with something large
+ Assert.AreEqual(7, queue.Replace(handle, 12));
+ Assert.IsTrue(queue.Check());
+ }
+
+ [Test]
+ public void ReuseHandle()
+ {
+ IPriorityQueueHandle<int> handle = null;
+ queue.Add(ref handle, 7);
+ queue.Delete(handle);
+ queue.Add(ref handle, 8);
+ }
+
+ [Test]
+ [ExpectedException(typeof(InvalidPriorityQueueHandleException))]
+ public void ErrorAddValidHandle()
+ {
+ IPriorityQueueHandle<int> handle = null;
+ queue.Add(ref handle, 7);
+ queue.Add(ref handle, 8);
+ }
+
+ [Test]
+ [ExpectedException(typeof(InvalidPriorityQueueHandleException))]
+ public void ErrorDeleteInvalidHandle()
+ {
+ IPriorityQueueHandle<int> handle = null;
+ queue.Add(ref handle, 7);
+ queue.Delete(handle);
+ queue.Delete(handle);
+ }
+
+ [Test]
+ [ExpectedException(typeof(InvalidPriorityQueueHandleException))]
+ public void ErrorReplaceInvalidHandle()
+ {
+ IPriorityQueueHandle<int> handle = null;
+ queue.Add(ref handle, 7);
+ queue.Delete(handle);
+ queue.Replace(handle, 13);
+ }
+
+ [Test]
+ public void Simple()
+ {
+ Assert.IsTrue(queue.AllowsDuplicates);
+ Assert.AreEqual(0, queue.Count);
+ queue.Add(8); queue.Add(18); queue.Add(8); queue.Add(3);
+ Assert.AreEqual(4, queue.Count);
+ Assert.AreEqual(18, queue.DeleteMax());
+ Assert.AreEqual(3, queue.Count);
+ Assert.AreEqual(3, queue.DeleteMin());
+ Assert.AreEqual(2, queue.Count);
+ Assert.AreEqual(8, queue.FindMax());
+ Assert.AreEqual(8, queue.DeleteMax());
+ Assert.AreEqual(8, queue.FindMax());
+ queue.Add(15);
+ Assert.AreEqual(15, queue.FindMax());
+ Assert.AreEqual(8, queue.FindMin());
+ Assert.IsTrue(queue.Comparer.Compare(2, 3) < 0);
+ Assert.IsTrue(queue.Comparer.Compare(4, 3) > 0);
+ Assert.IsTrue(queue.Comparer.Compare(3, 3) == 0);
+
+ }
+
+
+ [Test]
+ public void Enumerate()
+ {
+ int[] a = new int[4];
+ int siz = 0;
+ foreach (int i in queue)
+ siz++;
+ Assert.AreEqual(0, siz);
+
+ queue.Add(8); queue.Add(18); queue.Add(8); queue.Add(3);
+
+ foreach (int i in queue)
+ a[siz++] = i;
+ Assert.AreEqual(4, siz);
+ Array.Sort(a, 0, siz);
+ Assert.AreEqual(3, a[0]);
+ Assert.AreEqual(8, a[1]);
+ Assert.AreEqual(8, a[2]);
+ Assert.AreEqual(18, a[3]);
+
+ siz = 0;
+ Assert.AreEqual(18, queue.DeleteMax());
+ foreach (int i in queue)
+ a[siz++] = i;
+ Assert.AreEqual(3, siz);
+ Array.Sort(a, 0, siz);
+ Assert.AreEqual(3, a[0]);
+ Assert.AreEqual(8, a[1]);
+ Assert.AreEqual(8, a[2]);
+
+ siz = 0;
+ Assert.AreEqual(8, queue.DeleteMax());
+ foreach (int i in queue)
+ a[siz++] = i;
+ Assert.AreEqual(2, siz);
+ Array.Sort(a, 0, siz);
+ Assert.AreEqual(3, a[0]);
+ Assert.AreEqual(8, a[1]);
+
+ siz = 0;
+ Assert.AreEqual(8, queue.DeleteMax());
+ foreach (int i in queue)
+ a[siz++] = i;
+ Assert.AreEqual(1, siz);
+ Assert.AreEqual(3, a[0]);
+ }
+
+ [Test]
+ public void Random()
+ {
+ int length = 1000;
+ int[] a = new int[length];
+ Random ran = new Random(6754);
+
+ for (int i = 0; i < length; i++)
+ queue.Add(a[i] = ran.Next());
+
+ Assert.IsTrue(queue.Check());
+ Array.Sort(a);
+ for (int i = 0; i < length / 2; i++)
+ {
+ Assert.AreEqual(a[length - i - 1], queue.DeleteMax());
+ Assert.IsTrue(queue.Check());
+ Assert.AreEqual(a[i], queue.DeleteMin());
+ Assert.IsTrue(queue.Check());
+ }
+
+ Assert.IsTrue(queue.IsEmpty);
+ }
+
+ [Test]
+ public void RandomWithHandles()
+ {
+ int length = 1000;
+ int[] a = new int[length];
+ Random ran = new Random(6754);
+
+ for (int i = 0; i < length; i++)
+ {
+ IPriorityQueueHandle<int> h = null;
+ queue.Add(ref h, a[i] = ran.Next());
+ Assert.IsTrue(queue.Check());
+ }
+
+ Assert.IsTrue(queue.Check());
+ Array.Sort(a);
+ for (int i = 0; i < length / 2; i++)
+ {
+ Assert.AreEqual(a[length - i - 1], queue.DeleteMax());
+ Assert.IsTrue(queue.Check());
+ Assert.AreEqual(a[i], queue.DeleteMin());
+ Assert.IsTrue(queue.Check());
+ }
+
+ Assert.IsTrue(queue.IsEmpty);
+ }
+
+ [Test]
+ public void RandomWithDeleteHandles()
+ {
+ Random ran = new Random(6754);
+ int length = 1000;
+ int[] a = new int[length];
+ ArrayList<int> shuffle = new ArrayList<int>(length);
+ IPriorityQueueHandle<int>[] h = new IPriorityQueueHandle<int>[length];
+
+ for (int i = 0; i < length; i++)
+ {
+ shuffle.Add(i);
+ queue.Add(ref h[i], a[i] = ran.Next());
+ Assert.IsTrue(queue.Check());
+ }
+
+ Assert.IsTrue(queue.Check());
+ shuffle.Shuffle(ran);
+ for (int i = 0; i < length; i++)
+ {
+ int j = shuffle[i];
+ Assert.AreEqual(a[j], queue.Delete(h[j]));
+ Assert.IsTrue(queue.Check());
+ }
+
+ Assert.IsTrue(queue.IsEmpty);
+ }
+
+ [Test]
+ public void RandomIndexing()
+ {
+ Random ran = new Random(6754);
+ int length = 1000;
+ int[] a = new int[length];
+ int[] b = new int[length];
+ ArrayList<int> shuffle = new ArrayList<int>(length);
+ IPriorityQueueHandle<int>[] h = new IPriorityQueueHandle<int>[length];
+
+ for (int i = 0; i < length; i++)
+ {
+ shuffle.Add(i);
+ queue.Add(ref h[i], a[i] = ran.Next());
+ b[i] = ran.Next();
+ Assert.IsTrue(queue.Check());
+ }
+
+ Assert.IsTrue(queue.Check());
+ shuffle.Shuffle(ran);
+ for (int i = 0; i < length; i++)
+ {
+ int j = shuffle[i];
+ Assert.AreEqual(a[j], queue[h[j]]);
+ queue[h[j]] = b[j];
+ Assert.AreEqual(b[j], queue[h[j]]);
+ Assert.IsTrue(queue.Check());
+ }
+ }
+
+
+
+ [Test]
+ public void RandomDuplicates()
+ {
+ int length = 1000;
+ int s;
+ int[] a = new int[length];
+ Random ran = new Random(6754);
+
+ for (int i = 0; i < length; i++)
+ queue.Add(a[i] = ran.Next(3, 13));
+ Assert.IsTrue(queue.Check());
+
+ Array.Sort(a);
+
+ for (int i = 0; i < length / 2; i++)
+ {
+ Assert.AreEqual(a[i], queue.DeleteMin());
+ Assert.IsTrue(queue.Check());
+ Assert.AreEqual(a[length - i - 1], s = queue.DeleteMax());
+ Assert.IsTrue(queue.Check());
+ }
+
+ Assert.IsTrue(queue.IsEmpty);
+ }
+
+
+ [Test]
+ public void AddAll()
+ {
+ int length = 1000;
+ int[] a = new int[length];
+ Random ran = new Random(6754);
+
+ LinkedList<int> lst = new LinkedList<int>();
+ for (int i = 0; i < length; i++)
+ lst.Add(a[i] = ran.Next());
+
+ queue.AddAll(lst);
+ Assert.IsTrue(queue.Check());
+ Array.Sort(a);
+ for (int i = 0; i < length / 2; i++)
+ {
+ Assert.AreEqual(a[length - i - 1], queue.DeleteMax());
+ Assert.IsTrue(queue.Check());
+ Assert.AreEqual(a[i], queue.DeleteMin());
+ Assert.IsTrue(queue.Check());
+ }
+
+ Assert.IsTrue(queue.IsEmpty);
+ }
+
+ }
+
+
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/1.0/Test/linkedlists/HashedLinkedListTest.cs b/mcs/class/Mono.C5/1.0/Test/linkedlists/HashedLinkedListTest.cs
new file mode 100644
index 00000000000..077f51c66bc
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/Test/linkedlists/HashedLinkedListTest.cs
@@ -0,0 +1,2841 @@
+/*
+ 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 C5;
+using NUnit.Framework;
+using SCG = System.Collections.Generic;
+
+
+namespace C5UnitTests.linkedlists.hashed
+{
+ using CollectionOfInt = HashedLinkedList<int>;
+
+ [TestFixture]
+ public class GenericTesters
+ {
+ [Test]
+ public void TestEvents()
+ {
+ Fun<CollectionOfInt> factory = delegate() { return new CollectionOfInt(TenEqualityComparer.Default); };
+ new C5UnitTests.Templates.Events.ListTester<CollectionOfInt>().Test(factory);
+ }
+
+ [Test]
+ public void Extensible()
+ {
+ C5UnitTests.Templates.Extensible.Clone.Tester<CollectionOfInt>();
+ C5UnitTests.Templates.Extensible.Clone.ViewTester<CollectionOfInt>();
+ C5UnitTests.Templates.Extensible.Serialization.Tester<CollectionOfInt>();
+ C5UnitTests.Templates.Extensible.Serialization.ViewTester<CollectionOfInt>();
+ }
+ }
+
+ static class Factory
+ {
+ public static ICollection<T> New<T>() { return new HashedLinkedList<T>(); }
+ }
+
+
+ namespace Enumerable
+ {
+ [TestFixture]
+ public class Multiops
+ {
+ private HashedLinkedList<int> list;
+
+ private Fun<int, bool> always, never, even;
+
+
+ [SetUp]
+ public void Init()
+ {
+ list = new HashedLinkedList<int>();
+ always = delegate { return true; };
+ never = delegate { return false; };
+ even = delegate(int i) { return i % 2 == 0; };
+ }
+
+
+ [Test]
+ public void All()
+ {
+ Assert.IsTrue(list.All(always));
+ Assert.IsTrue(list.All(never));
+ Assert.IsTrue(list.All(even));
+ list.Add(8);
+ Assert.IsTrue(list.All(always));
+ Assert.IsFalse(list.All(never));
+ Assert.IsTrue(list.All(even));
+ list.Add(5);
+ Assert.IsTrue(list.All(always));
+ Assert.IsFalse(list.All(never));
+ Assert.IsFalse(list.All(even));
+ }
+
+
+ [Test]
+ public void Exists()
+ {
+ Assert.IsFalse(list.Exists(always));
+ Assert.IsFalse(list.Exists(never));
+ Assert.IsFalse(list.Exists(even));
+ list.Add(5);
+ Assert.IsTrue(list.Exists(always));
+ Assert.IsFalse(list.Exists(never));
+ Assert.IsFalse(list.Exists(even));
+ list.Add(8);
+ Assert.IsTrue(list.Exists(always));
+ Assert.IsFalse(list.Exists(never));
+ Assert.IsTrue(list.Exists(even));
+ }
+
+
+ [Test]
+ public void Apply()
+ {
+ int sum = 0;
+ Act<int> a = delegate(int i) { sum = i + 10 * sum; };
+
+ list.Apply(a);
+ Assert.AreEqual(0, sum);
+ sum = 0;
+ list.Add(5); list.Add(8); list.Add(7); list.Add(5);
+ list.Apply(a);
+ Assert.AreEqual(587, sum);
+ }
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+ }
+
+
+
+ [TestFixture]
+ public class GetEnumerator
+ {
+ private HashedLinkedList<int> list;
+
+
+ [SetUp]
+ public void Init() { list = new HashedLinkedList<int>(); }
+
+
+ [Test]
+ public void Empty()
+ {
+ SCG.IEnumerator<int> e = list.GetEnumerator();
+
+ Assert.IsFalse(e.MoveNext());
+ }
+
+
+ [Test]
+ public void Normal()
+ {
+ list.Add(5);
+ list.Add(8);
+ list.Add(5);
+ list.Add(5);
+ list.Add(10);
+ list.Add(1);
+
+ SCG.IEnumerator<int> e = list.GetEnumerator();
+
+ Assert.IsTrue(e.MoveNext());
+ Assert.AreEqual(5, e.Current);
+ Assert.IsTrue(e.MoveNext());
+ Assert.AreEqual(8, e.Current);
+ Assert.IsTrue(e.MoveNext());
+ Assert.AreEqual(10, e.Current);
+ Assert.IsTrue(e.MoveNext());
+ Assert.AreEqual(1, e.Current);
+ Assert.IsFalse(e.MoveNext());
+ }
+
+
+ [Test]
+ public void DoDispose()
+ {
+ list.Add(5);
+ list.Add(8);
+ list.Add(5);
+
+ SCG.IEnumerator<int> e = list.GetEnumerator();
+
+ e.MoveNext();
+ e.MoveNext();
+ e.Dispose();
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void MoveNextAfterUpdate()
+ {
+ list.Add(5);
+ list.Add(8);
+ list.Add(5);
+
+ SCG.IEnumerator<int> e = list.GetEnumerator();
+
+ e.MoveNext();
+ list.Add(99);
+ e.MoveNext();
+ }
+
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+ }
+ }
+
+ namespace CollectionOrSink
+ {
+ [TestFixture]
+ public class Formatting
+ {
+ ICollection<int> coll;
+ IFormatProvider rad16;
+ [SetUp]
+ public void Init() { coll = Factory.New<int>(); rad16 = new RadixFormatProvider(16); }
+ [TearDown]
+ public void Dispose() { coll = null; rad16 = null; }
+ [Test]
+ public void Format()
+ {
+ Assert.AreEqual("[ ]", coll.ToString());
+ coll.AddAll<int>(new int[] { -4, 28, 129, 65530 });
+ Assert.AreEqual("[ -4, 28, 129, 65530 ]", coll.ToString());
+ Assert.AreEqual("[ -4, 1C, 81, FFFA ]", coll.ToString(null, rad16));
+ Assert.AreEqual("[ -4, 28, 129... ]", coll.ToString("L14", null));
+ Assert.AreEqual("[ -4, 1C, 81... ]", coll.ToString("L14", rad16));
+ }
+ }
+
+ [TestFixture]
+ public class CollectionOrSink
+ {
+ private HashedLinkedList<int> list;
+
+
+ [SetUp]
+ public void Init() { list = new HashedLinkedList<int>(); }
+
+ [Test]
+ [ExpectedException(typeof(NullReferenceException))]
+ public void NullEqualityComparerinConstructor1()
+ {
+ new HashedLinkedList<int>(null);
+ }
+
+ [Test]
+ public void Choose()
+ {
+ list.Add(7);
+ Assert.AreEqual(7, list.Choose());
+ }
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void BadChoose()
+ {
+ list.Choose();
+ }
+
+
+ [Test]
+ public void CountEtAl()
+ {
+ Assert.AreEqual(0, list.Count);
+ Assert.IsTrue(list.IsEmpty);
+ Assert.IsFalse(list.AllowsDuplicates);
+ Assert.IsTrue(list.Add(5));
+ Assert.AreEqual(1, list.Count);
+ Assert.IsFalse(list.IsEmpty);
+ Assert.IsFalse(list.Add(5));
+ Assert.AreEqual(1, list.Count);
+ Assert.IsFalse(list.IsEmpty);
+ Assert.IsTrue(list.Add(8));
+ Assert.AreEqual(2, list.Count);
+ }
+
+
+ [Test]
+ public void AddAll()
+ {
+ list.Add(3); list.Add(4); list.Add(5);
+
+ HashedLinkedList<int> list2 = new HashedLinkedList<int>();
+
+ list2.AddAll(list);
+ Assert.IsTrue(IC.eq(list2, 3, 4, 5));
+ list.AddAll(list2);
+ Assert.IsTrue(IC.eq(list2, 3, 4, 5));
+ Assert.IsTrue(IC.eq(list, 3, 4, 5));
+ }
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+ }
+
+ [TestFixture]
+ public class FindPredicate
+ {
+ private HashedLinkedList<int> list;
+ Fun<int, bool> pred;
+
+ [SetUp]
+ public void Init()
+ {
+ list = new HashedLinkedList<int>(TenEqualityComparer.Default);
+ pred = delegate(int i) { return i % 5 == 0; };
+ }
+
+ [TearDown]
+ public void Dispose() { list = null; }
+
+ [Test]
+ public void Find()
+ {
+ int i;
+ Assert.IsFalse(list.Find(pred, out i));
+ list.AddAll<int>(new int[] { 4, 22, 67, 37 });
+ Assert.IsFalse(list.Find(pred, out i));
+ list.AddAll<int>(new int[] { 45, 122, 675, 137 });
+ Assert.IsTrue(list.Find(pred, out i));
+ Assert.AreEqual(45, i);
+ }
+
+ [Test]
+ public void FindLast()
+ {
+ int i;
+ Assert.IsFalse(list.FindLast(pred, out i));
+ list.AddAll<int>(new int[] { 4, 22, 67, 37 });
+ Assert.IsFalse(list.FindLast(pred, out i));
+ list.AddAll<int>(new int[] { 45, 122, 675, 137 });
+ Assert.IsTrue(list.FindLast(pred, out i));
+ Assert.AreEqual(675, i);
+ }
+
+ [Test]
+ public void FindIndex()
+ {
+ Assert.IsFalse(0 <= list.FindIndex(pred));
+ list.AddAll<int>(new int[] { 4, 22, 67, 37 });
+ Assert.IsFalse(0 <= list.FindIndex(pred));
+ list.AddAll<int>(new int[] { 45, 122, 675, 137 });
+ Assert.AreEqual(4, list.FindIndex(pred));
+ }
+
+ [Test]
+ public void FindLastIndex()
+ {
+ Assert.IsFalse(0 <= list.FindLastIndex(pred));
+ list.AddAll<int>(new int[] { 4, 22, 67, 37 });
+ Assert.IsFalse(0 <= list.FindLastIndex(pred));
+ list.AddAll<int>(new int[] { 45, 122, 675, 137 });
+ Assert.AreEqual(6, list.FindLastIndex(pred));
+ }
+ }
+
+ [TestFixture]
+ public class UniqueItems
+ {
+ private HashedLinkedList<int> list;
+
+ [SetUp]
+ public void Init() { list = new HashedLinkedList<int>(); }
+
+ [TearDown]
+ public void Dispose() { list = null; }
+
+ [Test]
+ public void Test()
+ {
+ Assert.IsTrue(IC.seteq(list.UniqueItems()));
+ Assert.IsTrue(IC.seteq(list.ItemMultiplicities()));
+ list.AddAll<int>(new int[] { 7, 9, 7 });
+ Assert.IsTrue(IC.seteq(list.UniqueItems(), 7, 9));
+ Assert.IsTrue(IC.seteq(list.ItemMultiplicities(), 7, 1, 9, 1));
+ }
+ }
+
+ [TestFixture]
+ public class ArrayTest
+ {
+ private HashedLinkedList<int> list;
+
+ int[] a;
+
+
+ [SetUp]
+ public void Init()
+ {
+ list = new HashedLinkedList<int>();
+ a = new int[10];
+ for (int i = 0; i < 10; i++)
+ a[i] = 1000 + i;
+ }
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+
+
+ private string aeq(int[] a, params int[] b)
+ {
+ if (a.Length != b.Length)
+ return "Lengths differ: " + a.Length + " != " + b.Length;
+
+ for (int i = 0; i < a.Length; i++)
+ if (a[i] != b[i])
+ return String.Format("{0}'th elements differ: {1} != {2}", i, a[i], b[i]);
+
+ return "Alles klar";
+ }
+
+
+ [Test]
+ public void ToArray()
+ {
+ Assert.AreEqual("Alles klar", aeq(list.ToArray()));
+ list.Add(7);
+ list.Add(8);
+ Assert.AreEqual("Alles klar", aeq(list.ToArray(), 7, 8));
+ }
+
+
+ [Test]
+ public void CopyTo()
+ {
+ list.CopyTo(a, 1);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009));
+ list.Add(6);
+ list.CopyTo(a, 2);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 6, 1003, 1004, 1005, 1006, 1007, 1008, 1009));
+ list.Add(4);
+ list.Add(5);
+ list.Add(9);
+ list.CopyTo(a, 4);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 6, 1003, 6, 4, 5, 9, 1008, 1009));
+ list.Clear();
+ list.Add(7);
+ list.CopyTo(a, 9);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 6, 1003, 6, 4, 5, 9, 1008, 7));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void CopyToBad()
+ {
+ list.CopyTo(a, 11);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void CopyToBad2()
+ {
+ list.CopyTo(a, -1);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void CopyToTooFar()
+ {
+ list.Add(3);
+ list.Add(4);
+ list.CopyTo(a, 9);
+ }
+ }
+
+
+
+ [TestFixture]
+ public class Sync
+ {
+ private HashedLinkedList<int> list;
+
+
+ [SetUp]
+ public void Init()
+ {
+ list = new HashedLinkedList<int>();
+ }
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+
+
+ [Test]
+ public void Get()
+ {
+ Assert.IsNotNull(list.SyncRoot);
+ }
+ }
+ }
+
+
+
+
+ namespace EditableCollection
+ {
+ [TestFixture]
+ public class Searching
+ {
+ private HashedLinkedList<int> list;
+
+
+ [SetUp]
+ public void Init() { list = new HashedLinkedList<int>(); }
+
+
+ [Test]
+ public void Contains()
+ {
+ Assert.IsFalse(list.Contains(5));
+ list.Add(5);
+ Assert.IsTrue(list.Contains(5));
+ Assert.IsFalse(list.Contains(7));
+ list.Add(8);
+ list.Add(10);
+ Assert.IsTrue(list.Contains(5));
+ Assert.IsFalse(list.Contains(7));
+ Assert.IsTrue(list.Contains(8));
+ Assert.IsTrue(list.Contains(10));
+ list.Remove(8);
+ Assert.IsTrue(list.Contains(5));
+ Assert.IsFalse(list.Contains(7));
+ Assert.IsFalse(list.Contains(8));
+ Assert.IsTrue(list.Contains(10));
+ }
+
+ [Test]
+ public void BadAdd()
+ {
+ Assert.IsTrue(list.Add(5));
+ Assert.IsTrue(list.Add(8));
+ Assert.IsFalse(list.Add(5));
+ }
+
+
+ [Test]
+ public void ContainsCount()
+ {
+ Assert.AreEqual(0, list.ContainsCount(5));
+ list.Add(5);
+ Assert.AreEqual(1, list.ContainsCount(5));
+ Assert.AreEqual(0, list.ContainsCount(7));
+ list.Add(8);
+ Assert.AreEqual(1, list.ContainsCount(5));
+ Assert.AreEqual(0, list.ContainsCount(7));
+ Assert.AreEqual(1, list.ContainsCount(8));
+ }
+
+
+ [Test]
+ public void RemoveAllCopies()
+ {
+ list.Add(5); list.Add(7);
+ Assert.AreEqual(1, list.ContainsCount(5));
+ Assert.AreEqual(1, list.ContainsCount(7));
+ list.RemoveAllCopies(5);
+ Assert.IsTrue(list.Check());
+ Assert.AreEqual(0, list.ContainsCount(5));
+ Assert.AreEqual(1, list.ContainsCount(7));
+ list.Add(5); list.Add(8);
+ list.RemoveAllCopies(8);
+ Assert.IsTrue(IC.eq(list, 7, 5));
+ }
+
+
+ [Test]
+ public void FindAll()
+ {
+ Fun<int, bool> f = delegate(int i) { return i % 2 == 0; };
+
+ Assert.IsTrue(list.FindAll(f).IsEmpty);
+ list.Add(5); list.Add(8); list.Add(10);
+ Assert.IsTrue(((HashedLinkedList<int>)list.FindAll(f)).Check());
+ Assert.IsTrue(IC.eq(list.FindAll(f), 8, 10));
+ }
+
+
+ [Test]
+ public void ContainsAll()
+ {
+ HashedLinkedList<int> list2 = new HashedLinkedList<int>();
+
+ Assert.IsTrue(list.ContainsAll(list2));
+ list2.Add(4);
+ Assert.IsFalse(list.ContainsAll(list2));
+ list.Add(4);
+ Assert.IsTrue(list.ContainsAll(list2));
+ list.Add(5);
+ Assert.IsTrue(list.ContainsAll(list2));
+ }
+
+
+ [Test]
+ public void RetainAll()
+ {
+ HashedLinkedList<int> list2 = new HashedLinkedList<int>();
+
+ list.Add(4); list.Add(5); list.Add(6);
+ list2.Add(5); list2.Add(4); list2.Add(7);
+ list.RetainAll(list2);
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4, 5));
+ list.Add(5); list.Add(4); list.Add(6);
+ list2.Clear();
+ list2.Add(5); list2.Add(5); list2.Add(6);
+ list.RetainAll(list2);
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 5, 6));
+ list2.Clear();
+ list2.Add(7); list2.Add(8); list2.Add(9);
+ list.RetainAll(list2);
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list));
+ }
+
+
+ [Test]
+ public void RemoveAll()
+ {
+ HashedLinkedList<int> list2 = new HashedLinkedList<int>();
+
+ list.Add(4); list.Add(5); list.Add(6);
+ list2.Add(5); list2.Add(4); list2.Add(7);
+ list.RemoveAll(list2);
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 6));
+ list.Add(5); list.Add(4); list.Add(6);
+ list2.Clear();
+ list2.Add(6); list2.Add(5);
+ list.RemoveAll(list2);
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4));
+ list2.Clear();
+ list2.Add(7); list2.Add(8); list2.Add(9);
+ list.RemoveAll(list2);
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4));
+ }
+
+
+ [Test]
+ public void Remove()
+ {
+ list.Add(4); list.Add(5); list.Add(6);
+ Assert.IsFalse(list.Remove(2));
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(list.Remove(4));
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 5, 6));
+ Assert.AreEqual(6, list.RemoveLast());
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 5));
+ list.Add(7);
+ Assert.AreEqual(5, list.RemoveFirst());
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 7));
+ }
+
+
+ [Test]
+ public void Clear()
+ {
+ list.Add(7); list.Add(6);
+ list.Clear();
+ Assert.IsTrue(list.IsEmpty);
+ }
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+ }
+ }
+
+
+
+
+ namespace IIndexed
+ {
+ [TestFixture]
+ public class Searching
+ {
+ private IIndexed<int> dit;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new HashedLinkedList<int>();
+ }
+
+
+ [Test]
+ public void IndexOf()
+ {
+ Assert.AreEqual(~0, dit.IndexOf(6));
+ dit.Add(7);
+ Assert.AreEqual(~1, dit.IndexOf(6));
+ Assert.AreEqual(~1, dit.LastIndexOf(6));
+ Assert.AreEqual(0, dit.IndexOf(7));
+ dit.Add(5); dit.Add(7); dit.Add(8); dit.Add(7);
+ Assert.AreEqual(~3, dit.IndexOf(6));
+ Assert.AreEqual(0, dit.IndexOf(7));
+ Assert.AreEqual(0, dit.LastIndexOf(7));
+ Assert.AreEqual(2, dit.IndexOf(8));
+ Assert.AreEqual(1, dit.LastIndexOf(5));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class Removing
+ {
+ private IIndexed<int> dit;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new HashedLinkedList<int>();
+ }
+
+
+ [Test]
+ public void RemoveAt()
+ {
+ dit.Add(5); dit.Add(7); dit.Add(9); dit.Add(1); dit.Add(2);
+ Assert.AreEqual(7, dit.RemoveAt(1));
+ Assert.IsTrue(((HashedLinkedList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 5, 9, 1, 2));
+ Assert.AreEqual(5, dit.RemoveAt(0));
+ Assert.IsTrue(((HashedLinkedList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 9, 1, 2));
+ Assert.AreEqual(2, dit.RemoveAt(2));
+ Assert.IsTrue(((HashedLinkedList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 9, 1));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void RemoveAtBad0()
+ {
+ dit.RemoveAt(0);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void RemoveAtBadM1()
+ {
+ dit.RemoveAt(-1);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void RemoveAtBad1()
+ {
+ dit.Add(8);
+ dit.RemoveAt(1);
+ }
+
+
+ [Test]
+ public void RemoveInterval()
+ {
+ dit.RemoveInterval(0, 0);
+ dit.Add(10); dit.Add(20); dit.Add(30); dit.Add(40); dit.Add(50); dit.Add(60);
+ dit.RemoveInterval(3, 0);
+ Assert.IsTrue(((HashedLinkedList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 10, 20, 30, 40, 50, 60));
+ dit.RemoveInterval(3, 1);
+ Assert.IsTrue(((HashedLinkedList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 10, 20, 30, 50, 60));
+ dit.RemoveInterval(1, 3);
+ Assert.IsTrue(((HashedLinkedList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 10, 60));
+ dit.RemoveInterval(0, 2);
+ Assert.IsTrue(((HashedLinkedList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit));
+ dit.Add(10); dit.Add(20); dit.Add(30); dit.Add(40); dit.Add(50); dit.Add(60);
+ dit.RemoveInterval(0, 2);
+ Assert.IsTrue(((HashedLinkedList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 30, 40, 50, 60));
+ dit.RemoveInterval(2, 2);
+ Assert.IsTrue(((HashedLinkedList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 30, 40));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = null;
+ }
+ }
+ }
+
+
+
+
+ namespace IList_
+ {
+ [TestFixture]
+ public class Searching
+ {
+ private IList<int> lst;
+
+
+ [SetUp]
+ public void Init() { lst = new HashedLinkedList<int>(); }
+
+
+ [TearDown]
+ public void Dispose() { lst = null; }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void FirstBad()
+ {
+ int f = lst.First;
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void LastBad()
+ {
+ int f = lst.Last;
+ }
+
+
+ [Test]
+ public void FirstLast()
+ {
+ lst.Add(19);
+ Assert.AreEqual(19, lst.First);
+ Assert.AreEqual(19, lst.Last);
+ lst.Add(34); lst.InsertFirst(12);
+ Assert.AreEqual(12, lst.First);
+ Assert.AreEqual(34, lst.Last);
+ }
+
+
+ [Test]
+ public void This()
+ {
+ lst.Add(34);
+ Assert.AreEqual(34, lst[0]);
+ lst[0] = 56;
+ Assert.AreEqual(56, lst.First);
+ lst.Add(7); lst.Add(77); lst.Add(777); lst.Add(7777);
+ lst[0] = 45; lst[2] = 78; lst[4] = 101;
+ Assert.IsTrue(IC.eq(lst, 45, 7, 78, 777, 101));
+ }
+
+ [Test]
+ public void ThisWithUpdates()
+ {
+ HashedLinkedList<KeyValuePair<int, int>> pairlist = new HashedLinkedList<KeyValuePair<int, int>>(new KeyValuePairEqualityComparer<int, int>());
+ pairlist.Add(new KeyValuePair<int, int>(10, 50));
+ pairlist.Add(new KeyValuePair<int, int>(11, 51));
+ pairlist.Add(new KeyValuePair<int, int>(12, 52));
+ pairlist.Add(new KeyValuePair<int, int>(13, 53));
+ pairlist[2] = new KeyValuePair<int, int>(12, 102);
+ Assert.IsTrue(pairlist.Check());
+ Assert.AreEqual(new KeyValuePair<int, int>(12, 102), pairlist[2]);
+ pairlist[2] = new KeyValuePair<int, int>(22, 202);
+ Assert.IsTrue(pairlist.Check());
+ Assert.AreEqual(new KeyValuePair<int, int>(22, 202), pairlist[2]);
+ pairlist[1] = new KeyValuePair<int, int>(12, 303);
+ Assert.IsTrue(pairlist.Check());
+ Assert.AreEqual(new KeyValuePair<int, int>(12, 303), pairlist[1]);
+ Assert.AreEqual(new KeyValuePair<int, int>(22, 202), pairlist[2]);
+ }
+
+ [Test]
+ [ExpectedException(typeof(ArgumentException))]
+ public void ThisWithUpdatesBad()
+ {
+ HashedLinkedList<KeyValuePair<int, int>> pairlist = new HashedLinkedList<KeyValuePair<int, int>>(new KeyValuePairEqualityComparer<int, int>());
+ pairlist.Add(new KeyValuePair<int, int>(10, 50));
+ pairlist.Add(new KeyValuePair<int, int>(11, 51));
+ pairlist.Add(new KeyValuePair<int, int>(12, 52));
+ pairlist.Add(new KeyValuePair<int, int>(13, 53));
+ pairlist[2] = new KeyValuePair<int, int>(11, 102);
+ }
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void ThisBadEmptyGet()
+ {
+ int f = lst[0];
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void ThisBadLowGet()
+ {
+ lst.Add(7);
+
+ int f = lst[-1];
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void ThisBadHiGet()
+ {
+ lst.Add(6);
+
+ int f = lst[1];
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void ThisBadEmptySet()
+ {
+ lst[0] = 4;
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void ThisBadLowSet()
+ {
+ lst.Add(7);
+ lst[-1] = 9;
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void ThisBadHiSet()
+ {
+ lst.Add(6);
+ lst[1] = 11;
+ }
+ }
+
+
+ [TestFixture]
+ public class Combined
+ {
+ private IList<KeyValuePair<int, int>> lst;
+
+
+ [SetUp]
+ public void Init()
+ {
+ lst = new HashedLinkedList<KeyValuePair<int, int>>(new KeyValuePairEqualityComparer<int, int>());
+ for (int i = 0; i < 10; i++)
+ lst.Add(new KeyValuePair<int, int>(i, i + 30));
+ }
+
+
+ [TearDown]
+ public void Dispose() { lst = null; }
+
+
+ [Test]
+ public void Find()
+ {
+ KeyValuePair<int, int> p = new KeyValuePair<int, int>(3, 78);
+
+ Assert.IsTrue(lst.Find(ref p));
+ Assert.AreEqual(3, p.Key);
+ Assert.AreEqual(33, p.Value);
+ p = new KeyValuePair<int, int>(13, 78);
+ Assert.IsFalse(lst.Find(ref p));
+ }
+
+
+ [Test]
+ public void FindOrAdd()
+ {
+ KeyValuePair<int, int> p = new KeyValuePair<int, int>(3, 78);
+
+ Assert.IsTrue(lst.FindOrAdd(ref p));
+ Assert.AreEqual(3, p.Key);
+ Assert.AreEqual(33, p.Value);
+ p = new KeyValuePair<int, int>(13, 79);
+ Assert.IsFalse(lst.FindOrAdd(ref p));
+ Assert.AreEqual(13, lst[10].Key);
+ Assert.AreEqual(79, lst[10].Value);
+ }
+
+
+ [Test]
+ public void Update()
+ {
+ KeyValuePair<int, int> p = new KeyValuePair<int, int>(3, 78);
+
+ Assert.IsTrue(lst.Update(p));
+ Assert.AreEqual(3, lst[3].Key);
+ Assert.AreEqual(78, lst[3].Value);
+ p = new KeyValuePair<int, int>(13, 78);
+ Assert.IsFalse(lst.Update(p));
+ }
+
+
+ [Test]
+ public void UpdateOrAdd()
+ {
+ KeyValuePair<int, int> p = new KeyValuePair<int, int>(3, 78);
+
+ Assert.IsTrue(lst.UpdateOrAdd(p));
+ Assert.AreEqual(3, lst[3].Key);
+ Assert.AreEqual(78, lst[3].Value);
+ p = new KeyValuePair<int, int>(13, 79);
+ Assert.IsFalse(lst.UpdateOrAdd(p));
+ Assert.AreEqual(13, lst[10].Key);
+ Assert.AreEqual(79, lst[10].Value);
+ }
+
+
+ [Test]
+ public void RemoveWithReturn()
+ {
+ KeyValuePair<int, int> p = new KeyValuePair<int, int>(3, 78);
+
+ Assert.IsTrue(lst.Remove(p, out p));
+ Assert.AreEqual(3, p.Key);
+ Assert.AreEqual(33, p.Value);
+ Assert.AreEqual(4, lst[3].Key);
+ Assert.AreEqual(34, lst[3].Value);
+ p = new KeyValuePair<int, int>(13, 78);
+ Assert.IsFalse(lst.Remove(p, out p));
+ }
+ }
+
+
+ [TestFixture]
+ public class Inserting
+ {
+ private IList<int> lst;
+
+
+ [SetUp]
+ public void Init() { lst = new HashedLinkedList<int>(); }
+
+
+ [TearDown]
+ public void Dispose() { lst = null; }
+
+
+ [Test]
+ public void Insert()
+ {
+ lst.Insert(0, 5);
+ Assert.IsTrue(IC.eq(lst, 5));
+ lst.Insert(0, 7);
+ Assert.IsTrue(IC.eq(lst, 7, 5));
+ lst.Insert(1, 4);
+ Assert.IsTrue(IC.eq(lst, 7, 4, 5));
+ lst.Insert(3, 2);
+ Assert.IsTrue(IC.eq(lst, 7, 4, 5, 2));
+ }
+
+ [Test]
+ [ExpectedException(typeof(DuplicateNotAllowedException))]
+ public void InsertDuplicate()
+ {
+ lst.Insert(0, 5);
+ Assert.IsTrue(IC.eq(lst, 5));
+ lst.Insert(0, 7);
+ Assert.IsTrue(IC.eq(lst, 7, 5));
+ lst.Insert(1, 5);
+ }
+
+ [Test]
+ public void InsertAllDuplicate1()
+ {
+ lst.Insert(0, 3);
+ Assert.IsTrue(IC.eq(lst, 3));
+ lst.Insert(0, 7);
+ Assert.IsTrue(IC.eq(lst, 7, 3));
+ try
+ {
+ lst.InsertAll<int>(1, new int[] { 1, 2, 3, 4 });
+ }
+ catch (DuplicateNotAllowedException)
+ {
+ }
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 1, 2, 3));
+ }
+
+ [Test]
+ public void InsertAllDuplicate2()
+ {
+ lst.Insert(0, 3);
+ Assert.IsTrue(IC.eq(lst, 3));
+ lst.Insert(0, 7);
+ Assert.IsTrue(IC.eq(lst, 7, 3));
+ try
+ {
+ lst.InsertAll<int>(1, new int[] { 5, 6, 5, 8 });
+ }
+ catch (DuplicateNotAllowedException)
+ {
+ }
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 5, 6, 3));
+ }
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void BadInsertLow()
+ {
+ lst.Add(7);
+ lst.Insert(-1, 9);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void BadInsertHi()
+ {
+ lst.Add(6);
+ lst.Insert(2, 11);
+ }
+
+
+ [Test]
+ public void FIFO()
+ {
+ for (int i = 0; i < 7; i++)
+ lst.Add(2 * i);
+
+ Assert.IsTrue(lst.FIFO);
+ Assert.AreEqual(0, lst.Remove());
+ Assert.AreEqual(2, lst.Remove());
+ lst.FIFO = false;
+ Assert.AreEqual(12, lst.Remove());
+ Assert.AreEqual(10, lst.Remove());
+ lst.FIFO = true;
+ Assert.AreEqual(4, lst.Remove());
+ Assert.AreEqual(6, lst.Remove());
+ }
+
+
+ [Test]
+ public void InsertFirstLast()
+ {
+ lst.InsertFirst(4);
+ lst.InsertLast(5);
+ lst.InsertFirst(14);
+ lst.InsertLast(15);
+ lst.InsertFirst(24);
+ lst.InsertLast(25);
+ lst.InsertFirst(34);
+ lst.InsertLast(55);
+ Assert.IsTrue(IC.eq(lst, 34, 24, 14, 4, 5, 15, 25, 55));
+ }
+
+
+ [Test]
+ public void InsertFirst()
+ {
+ lst.Add(2);
+ lst.Add(3);
+ lst.Add(4);
+ lst.Add(5);
+ lst.ViewOf(2).InsertFirst(7);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 2, 3, 4, 5));
+ lst.ViewOf(3).InsertFirst(8);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 2, 8, 3, 4, 5));
+ lst.ViewOf(5).InsertFirst(9);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 2, 8, 3, 4, 9, 5));
+ }
+
+
+ [Test]
+ public void BadViewOf()
+ {
+ lst.Add(2);
+ lst.Add(3);
+ lst.Add(2);
+ lst.Add(5);
+ Assert.IsNull(lst.ViewOf(4));
+ }
+
+
+ [Test]
+ public void InsertAfter()
+ {
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ lst.Add(4);
+ lst.Add(5);
+ lst.LastViewOf(2).InsertLast(7);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 1, 2, 7, 3, 4, 5));
+ lst.LastViewOf(1).InsertLast(8);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 1, 8, 2, 7, 3, 4, 5));
+ lst.LastViewOf(5).InsertLast(9);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 1, 8, 2, 7, 3, 4, 5, 9));
+ }
+
+
+ [Test]
+ public void BadInsertAfter()
+ {
+ lst.Add(2);
+ lst.Add(3);
+ lst.Add(6);
+ lst.Add(5);
+ Assert.IsNull(lst.ViewOf(4));
+ }
+
+
+ [Test]
+ public void InsertAll()
+ {
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ lst.Add(4);
+
+ IList<int> lst2 = new HashedLinkedList<int>();
+
+ lst2.Add(7); lst2.Add(8); lst2.Add(9);
+ lst.InsertAll(0, lst2);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 8, 9, 1, 2, 3, 4));
+ lst.RemoveAll(lst2);
+ lst.InsertAll(4, lst2);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 1, 2, 3, 4, 7, 8, 9));
+ lst.RemoveAll(lst2);
+ lst.InsertAll(2, lst2);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 1, 2, 7, 8, 9, 3, 4));
+ }
+
+ [Test]
+ [ExpectedException(typeof(DuplicateNotAllowedException))]
+ public void InsertAllBad()
+ {
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ lst.Add(4);
+
+ IList<int> lst2 = new HashedLinkedList<int>();
+
+ lst2.Add(5); lst2.Add(2); lst2.Add(9);
+ lst.InsertAll(0, lst2);
+ }
+
+
+ [Test]
+ public void Map()
+ {
+ Fun<int, string> m = delegate(int i) { return "<<" + i + ">>"; };
+ IList<string> r = lst.Map(m);
+
+ Assert.IsTrue(((HashedLinkedList<string>)r).Check());
+ Assert.IsTrue(r.IsEmpty);
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ lst.Add(4);
+ r = lst.Map(m);
+ Assert.IsTrue(((HashedLinkedList<string>)r).Check());
+ Assert.AreEqual(4, r.Count);
+ for (int i = 0; i < 4; i++)
+ Assert.AreEqual("<<" + (i + 1) + ">>", r[i]);
+ }
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void BadMapper()
+ {
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ Fun<int, bool> m = delegate(int i) { if (i == 2) lst.Add(7); return true; };
+ lst.Map(m);
+ }
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void ModifyingFindAll()
+ {
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ Fun<int, bool> m = delegate(int i) { if (i == 2) lst.Add(7); return true; };
+ lst.FindAll(m);
+ }
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void BadMapperView()
+ {
+ lst = lst.View(0, 0);
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ Fun<int, bool> m = delegate(int i) { if (i == 2) lst.Add(7); return true; };
+ lst.Map(m);
+ }
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void ModifyingFindAllView()
+ {
+ lst = lst.View(0, 0);
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ Fun<int, bool> m = delegate(int i) { if (i == 2) lst.Add(7); return true; };
+ lst.FindAll(m);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void BadRemove() { lst.Remove(); }
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void BadRemoveFirst() { lst.RemoveFirst(); }
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void BadRemoveLast() { lst.RemoveLast(); }
+
+
+ [Test]
+ public void RemoveFirstLast()
+ {
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ lst.Add(4);
+ Assert.AreEqual(1, lst.RemoveFirst());
+ Assert.AreEqual(4, lst.RemoveLast());
+ Assert.AreEqual(2, lst.RemoveFirst());
+ Assert.AreEqual(3, lst.RemoveLast());
+ Assert.IsTrue(lst.IsEmpty);
+ }
+
+
+ [Test]
+ public void Reverse()
+ {
+ for (int i = 0; i < 10; i++)
+ lst.Add(i);
+
+ lst.Reverse();
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0));
+ lst.View(0, 3).Reverse();
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 8, 9, 6, 5, 4, 3, 2, 1, 0));
+ lst.View(7, 0).Reverse();
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 8, 9, 6, 5, 4, 3, 2, 1, 0));
+ lst.View(7, 3).Reverse();
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 8, 9, 6, 5, 4, 3, 0, 1, 2));
+ lst.View(5, 1).Reverse();
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 8, 9, 6, 5, 4, 3, 0, 1, 2));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void BadReverse()
+ {
+ for (int i = 0; i < 10; i++)
+ lst.Add(i);
+
+ lst.View(8, 3).Reverse();
+ }
+ }
+
+
+
+ [TestFixture]
+ public class SortingTest
+ {
+ private IList<int> lst;
+
+
+ [SetUp]
+ public void Init() { lst = new HashedLinkedList<int>(); }
+
+
+ [TearDown]
+ public void Dispose() { lst = null; }
+
+
+ [Test]
+ public void Sort()
+ {
+ lst.Add(5); lst.Add(6); lst.Add(55); lst.Add(7); lst.Add(3);
+ Assert.IsFalse(lst.IsSorted(new IC()));
+ lst.Sort(new IC());
+ Assert.IsTrue(lst.Check(), "Check ");
+ Assert.IsTrue(lst.IsSorted());
+ Assert.IsTrue(lst.IsSorted(new IC()));
+ Assert.IsTrue(IC.eq(lst, 3, 5, 6, 7, 55));
+ }
+ }
+
+ [TestFixture]
+ public class ShuffleTests
+ {
+ private IList<int> lst;
+
+
+ [SetUp]
+ public void Init() { lst = new HashedLinkedList<int>(); }
+
+
+ [TearDown]
+ public void Dispose() { lst = null; }
+
+
+ [Test]
+ public void Shuffle()
+ {
+ lst.Add(5); lst.Add(6); lst.Add(5); lst.Add(7); lst.Add(3);
+ for (int i = 0; i < 100; i++)
+ {
+ lst.Shuffle(new C5Random(i + 1));
+ Assert.IsTrue(lst.Check(), "Check " + i);
+ int[] lst2 = lst.ToArray();
+ Sorting.IntroSort<int>(lst2);
+ Assert.IsTrue(IC.eq(lst2, 3, 5, 6, 7), "Contents " + i);
+ }
+ }
+ }
+ }
+
+ namespace Range
+ {
+ [TestFixture]
+ public class Range
+ {
+ private IList<int> lst;
+
+
+ [SetUp]
+ public void Init() { lst = new HashedLinkedList<int>(); }
+
+
+ [TearDown]
+ public void Dispose() { lst = null; }
+
+
+ [Test]
+ public void GetRange()
+ {
+ //Assert.IsTrue(IC.eq(lst[0, 0)));
+ for (int i = 0; i < 10; i++) lst.Add(i);
+
+ Assert.IsTrue(IC.eq(lst[0, 3], 0, 1, 2));
+ Assert.IsTrue(IC.eq(lst[3, 3], 3, 4, 5));
+ Assert.IsTrue(IC.eq(lst[6, 3], 6, 7, 8));
+ Assert.IsTrue(IC.eq(lst[6, 4], 6, 7, 8, 9));
+ }
+
+
+ [Test]
+ public void Backwards()
+ {
+ for (int i = 0; i < 10; i++) lst.Add(i);
+
+ Assert.IsTrue(IC.eq(lst.Backwards(), 9, 8, 7, 6, 5, 4, 3, 2, 1, 0));
+ Assert.IsTrue(IC.eq(lst[0, 3].Backwards(), 2, 1, 0));
+ Assert.IsTrue(IC.eq(lst[3, 3].Backwards(), 5, 4, 3));
+ Assert.IsTrue(IC.eq(lst[6, 4].Backwards(), 9, 8, 7, 6));
+ }
+
+
+ [Test]
+ public void DirectionAndCount()
+ {
+ for (int i = 0; i < 10; i++) lst.Add(i);
+
+ Assert.AreEqual(EnumerationDirection.Forwards, lst.Direction);
+ Assert.AreEqual(EnumerationDirection.Forwards, lst[3, 7].Direction);
+ Assert.AreEqual(EnumerationDirection.Backwards, lst[3, 7].Backwards().Direction);
+ Assert.AreEqual(EnumerationDirection.Backwards, lst.Backwards().Direction);
+ Assert.AreEqual(4, lst[3, 4].Count);
+ Assert.AreEqual(4, lst[3, 4].Backwards().Count);
+ Assert.AreEqual(10, lst.Backwards().Count);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void MoveNextAfterUpdate()
+ {
+ for (int i = 0; i < 10; i++) lst.Add(i);
+
+ foreach (int i in lst)
+ {
+ lst.Add(45 + i);
+ }
+ }
+ }
+ }
+
+
+
+
+ namespace View
+ {
+ [TestFixture]
+ public class Simple
+ {
+ HashedLinkedList<int> list;
+ HashedLinkedList<int> view;
+
+
+ [SetUp]
+ public void Init()
+ {
+ list = new HashedLinkedList<int>();
+ list.Add(0); list.Add(1); list.Add(2); list.Add(3);
+ view = (HashedLinkedList<int>)list.View(1, 2);
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ list = null;
+ view = null;
+ }
+
+
+ void check()
+ {
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(view.Check());
+ }
+
+ [Test]
+ public void InsertPointer()
+ {
+ IList<int> view2 = list.View(2, 0);
+ list.Insert(view2, 7);
+ check();
+ list.Insert(list, 8);
+ check();
+ view.Insert(view2, 9);
+ check();
+ view.Insert(list.View(3, 2), 10);
+ check();
+ view.Insert(list.ViewOf(0), 11);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 11, 1, 9, 7, 2, 10, 3, 8));
+ Assert.IsTrue(IC.eq(view, 11, 1, 9, 7, 2, 10));
+ }
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void InsertPointerBad1()
+ {
+ view.Insert(list.View(0, 0), 7);
+ }
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void InsertPointerBad2()
+ {
+ view.Insert(list, 7);
+ }
+
+ [Test]
+ [ExpectedException(typeof(IncompatibleViewException))]
+ public void InsertPointerBad3()
+ {
+ list.Insert(new ArrayList<int>(), 7);
+ }
+
+ [Test]
+ [ExpectedException(typeof(IncompatibleViewException))]
+ public void InsertPointerBad4()
+ {
+ list.Insert(new ArrayList<int>().View(0, 0), 7);
+ }
+
+ [Test]
+ public void Span()
+ {
+ IList<int> span = list.View(1, 0).Span(list.View(2, 0));
+ Assert.IsTrue(span.Check());
+ Assert.AreEqual(1, span.Offset);
+ Assert.AreEqual(1, span.Count);
+ span = list.View(0, 2).Span(list.View(2, 2));
+ Assert.IsTrue(span.Check());
+ Assert.AreEqual(0, span.Offset);
+ Assert.AreEqual(4, span.Count);
+ span = list.View(3, 1).Span(list.View(1, 1));
+ Assert.IsNull(span);
+ }
+
+ [Test]
+ public void ViewOf()
+ {
+ for (int i = 0; i < 4; i++)
+ list.Add(i);
+ IList<int> v = view.ViewOf(2);
+ Assert.IsTrue(v.Check());
+ Assert.IsTrue(IC.eq(v, 2));
+ Assert.AreEqual(2, v.Offset);
+ v = list.ViewOf(2);
+ Assert.IsTrue(v.Check());
+ Assert.IsTrue(IC.eq(v, 2));
+ Assert.AreEqual(2, v.Offset);
+ v = list.LastViewOf(2);
+ Assert.IsTrue(v.Check());
+ Assert.IsTrue(IC.eq(v, 2));
+ Assert.AreEqual(2, v.Offset);
+ }
+
+ [Test]
+ public void BadViewOf()
+ {
+ Assert.IsNull(view.ViewOf(5));
+ Assert.IsNull(view.LastViewOf(5));
+ Assert.IsNull(view.ViewOf(3));
+ Assert.IsNull(view.LastViewOf(3));
+ Assert.IsNull(view.ViewOf(0));
+ Assert.IsNull(view.LastViewOf(0));
+ }
+
+
+ [Test]
+ public void ArrayStuff()
+ {
+ Assert.IsTrue(IC.eq(view.ToArray(), 1, 2));
+ int[] extarray = new int[5];
+ view.CopyTo(extarray, 2);
+ Assert.IsTrue(IC.eq(extarray, 0, 0, 1, 2, 0));
+ }
+
+ [Test]
+ public void Add()
+ {
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 1, 2, 3));
+ Assert.IsTrue(IC.eq(view, 1, 2));
+ view.InsertFirst(10);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 10, 1, 2, 3));
+ Assert.IsTrue(IC.eq(view, 10, 1, 2));
+ view.Clear();
+ Assert.IsFalse(view.IsReadOnly);
+ Assert.IsFalse(view.AllowsDuplicates);
+ Assert.IsTrue(view.IsEmpty);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 3));
+ Assert.IsTrue(IC.eq(view));
+ view.Add(8);
+ Assert.IsFalse(view.IsEmpty);
+ Assert.IsFalse(view.AllowsDuplicates);
+ Assert.IsFalse(view.IsReadOnly);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 8, 3));
+ Assert.IsTrue(IC.eq(view, 8));
+ view.Add(12);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 8, 12, 3));
+ Assert.IsTrue(IC.eq(view, 8, 12));
+ view./*ViewOf(12).*/InsertLast(15);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 8, 12, 15, 3));
+ Assert.IsTrue(IC.eq(view, 8, 12, 15));
+ view.ViewOf(12).InsertFirst(18);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 8, 18, 12, 15, 3));
+ Assert.IsTrue(IC.eq(view, 8, 18, 12, 15));
+
+ HashedLinkedList<int> lst2 = new HashedLinkedList<int>();
+
+ lst2.Add(90); lst2.Add(92);
+ view.AddAll(lst2);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 8, 18, 12, 15, 90, 92, 3));
+ Assert.IsTrue(IC.eq(view, 8, 18, 12, 15, 90, 92));
+ view.InsertLast(66);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 8, 18, 12, 15, 90, 92, 66, 3));
+ Assert.IsTrue(IC.eq(view, 8, 18, 12, 15, 90, 92, 66));
+ }
+
+
+ [Test]
+ public void Bxxx()
+ {
+ Assert.IsTrue(IC.eq(view.Backwards(), 2, 1));
+ Assert.AreSame(list, view.Underlying);
+ Assert.IsNull(list.Underlying);
+ Assert.AreEqual(EnumerationDirection.Forwards, view.Direction);
+ Assert.AreEqual(EnumerationDirection.Backwards, view.Backwards().Direction);
+ Assert.AreEqual(0, list.Offset);
+ Assert.AreEqual(1, view.Offset);
+ }
+
+
+ [Test]
+ public void Contains()
+ {
+ Assert.IsTrue(view.Contains(1));
+ Assert.IsFalse(view.Contains(0));
+
+ HashedLinkedList<int> lst2 = new HashedLinkedList<int>();
+
+ lst2.Add(2);
+ Assert.IsTrue(view.ContainsAll(lst2));
+ lst2.Add(3);
+ Assert.IsFalse(view.ContainsAll(lst2));
+ Assert.AreEqual(Speed.Constant, view.ContainsSpeed);
+ Assert.AreEqual(2, view.Count);
+ view.Add(1);
+ Assert.AreEqual(1, view.ContainsCount(2));
+ Assert.AreEqual(1, view.ContainsCount(1));
+ Assert.AreEqual(2, view.Count);
+ }
+
+
+ [Test]
+ public void CreateView()
+ {
+ HashedLinkedList<int> view2 = (HashedLinkedList<int>)view.View(1, 0);
+
+ Assert.AreSame(list, view2.Underlying);
+ }
+
+
+ [Test]
+ public void FIFO()
+ {
+ Assert.IsTrue(view.FIFO);
+ view.Add(23); view.Add(24); view.Add(25);
+ check();
+ Assert.IsTrue(IC.eq(view, 1, 2, 23, 24, 25));
+ Assert.AreEqual(1, view.Remove());
+ check();
+ Assert.IsTrue(IC.eq(view, 2, 23, 24, 25));
+ view.FIFO = false;
+ Assert.IsFalse(view.FIFO);
+ Assert.AreEqual(25, view.Remove());
+ check();
+ Assert.IsTrue(IC.eq(view, 2, 23, 24));
+ }
+
+
+ [Test]
+ public void MapEtc()
+ {
+ HashedLinkedList<double> dbl = (HashedLinkedList<double>)view.Map(new Fun<int, double>(delegate(int i) { return i / 10.0; }));
+
+ Assert.IsTrue(dbl.Check());
+ Assert.AreEqual(0.1, dbl[0]);
+ Assert.AreEqual(0.2, dbl[1]);
+ for (int i = 0; i < 10; i++) view.Add(i);
+
+ HashedLinkedList<int> list2 = (HashedLinkedList<int>)view.FindAll(new Fun<int, bool>(delegate(int i) { return i % 4 == 1; }));
+
+ Assert.IsTrue(list2.Check());
+ Assert.IsTrue(IC.eq(list2, 1, 5, 9));
+ }
+
+
+ [Test]
+ public void FL()
+ {
+ Assert.AreEqual(1, view.First);
+ Assert.AreEqual(2, view.Last);
+ }
+
+
+ [Test]
+ public void Indexing()
+ {
+ list.Clear();
+ for (int i = 0; i < 20; i++) list.Add(i);
+
+ view = (HashedLinkedList<int>)list.View(5, 7);
+ for (int i = 0; i < 7; i++) Assert.AreEqual(i + 5, view[i]);
+
+ for (int i = 0; i < 7; i++) Assert.AreEqual(i, view.IndexOf(i + 5));
+
+ for (int i = 0; i < 7; i++) Assert.AreEqual(i, view.LastIndexOf(i + 5));
+ }
+
+
+ [Test]
+ public void Insert()
+ {
+ view.Insert(0, 34);
+ view.Insert(1, 35);
+ view.Insert(4, 36);
+ Assert.IsTrue(view.Check());
+ Assert.IsTrue(IC.eq(view, 34, 35, 1, 2, 36));
+
+ IList<int> list2 = new HashedLinkedList<int>();
+
+ list2.Add(40); list2.Add(41);
+ view.InsertAll(3, list2);
+ Assert.IsTrue(view.Check());
+ Assert.IsTrue(IC.eq(view, 34, 35, 1, 40, 41, 2, 36));
+ }
+
+
+ [Test]
+ public void Sort()
+ {
+ view.Add(45); view.Add(47); view.Add(46); view.Add(48);
+ Assert.IsFalse(view.IsSorted(new IC()));
+ view.Sort(new IC());
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 1, 2, 45, 46, 47, 48, 3));
+ Assert.IsTrue(IC.eq(view, 1, 2, 45, 46, 47, 48));
+ }
+
+
+ [Test]
+ public void Remove()
+ {
+ view.Add(1); view.Add(5); view.Add(3); view.Add(1); view.Add(3); view.Add(0);
+ Assert.IsTrue(IC.eq(view, 1, 2, 5));
+ Assert.IsTrue(view.Remove(1));
+ check();
+ Assert.IsTrue(IC.eq(view, 2, 5));
+ Assert.IsFalse(view.Remove(1));
+ check();
+ Assert.IsTrue(IC.eq(view, 2, 5));
+ Assert.IsFalse(view.Remove(0));
+ check();
+ Assert.IsTrue(IC.eq(view, 2, 5));
+ view.RemoveAllCopies(3);
+ check();
+ Assert.IsTrue(IC.eq(view, 2, 5));
+ Assert.IsTrue(IC.eq(list, 0, 2, 5, 3));
+ view.Add(1); view.Add(5); view.Add(3); view.Add(1); view.Add(3); view.Add(0);
+ Assert.IsTrue(IC.eq(view, 2, 5, 1));
+
+ HashedLinkedList<int> l2 = new HashedLinkedList<int>();
+
+ l2.Add(1); l2.Add(2); l2.Add(2); l2.Add(3); l2.Add(1);
+ view.RemoveAll(l2);
+ check();
+ Assert.IsTrue(IC.eq(view, 5));
+ view.RetainAll(l2);
+ check();
+ Assert.IsTrue(IC.eq(view));
+ view.Add(2); view.Add(4); view.Add(5);
+ Assert.AreEqual(2, view.RemoveAt(0));
+ Assert.AreEqual(5, view.RemoveAt(1));
+ Assert.AreEqual(4, view.RemoveAt(0));
+ check();
+ Assert.IsTrue(IC.eq(view));
+ view.Add(8); view.Add(6); view.Add(78);
+ Assert.AreEqual(8, view.RemoveFirst());
+ Assert.AreEqual(78, view.RemoveLast());
+ view.Add(2); view.Add(5); view.Add(3); view.Add(1);
+ view.RemoveInterval(1, 2);
+ check();
+ Assert.IsTrue(IC.eq(view, 6, 1));
+ }
+
+
+ [Test]
+ public void Reverse()
+ {
+ view.Clear();
+ for (int i = 0; i < 10; i++) view.Add(10 + i);
+
+ view.View(3, 4).Reverse();
+ check();
+ Assert.IsTrue(IC.eq(view, 10, 11, 12, 16, 15, 14, 13, 17, 18, 19));
+ view.Reverse();
+ Assert.IsTrue(IC.eq(view, 19, 18, 17, 13, 14, 15, 16, 12, 11, 10));
+ Assert.IsTrue(IC.eq(list, 0, 19, 18, 17, 13, 14, 15, 16, 12, 11, 10, 3));
+ }
+
+
+ [Test]
+ public void Slide()
+ {
+ view.Slide(1);
+ check();
+ Assert.IsTrue(IC.eq(view, 2, 3));
+ view.Slide(-2);
+ check();
+ Assert.IsTrue(IC.eq(view, 0, 1));
+ view.Slide(0, 3);
+ check();
+ Assert.IsTrue(IC.eq(view, 0, 1, 2));
+ view.Slide(2, 1);
+ check();
+ Assert.IsTrue(IC.eq(view, 2));
+ view.Slide(-1, 0);
+ check();
+ Assert.IsTrue(IC.eq(view));
+ view.Add(28);
+ Assert.IsTrue(IC.eq(list, 0, 28, 1, 2, 3));
+ }
+ [Test]
+ public void Iterate()
+ {
+ list.Clear();
+ check();
+ view = null;
+ foreach (int i in new int[] { 2, 4, 8, 13, 6, 1, 10, 11 }) list.Add(i);
+
+ view = (HashedLinkedList<int>)list.View(list.Count - 2, 2);
+ int j = 666;
+ while (true)
+ {
+ check();
+ //Console.WriteLine("View: {0}: {1} --> {2}", view.Count, view.First, view.Last);
+ if ((view.Last - view.First) % 2 == 1)
+ view.Insert(1, j++);
+ check();
+ if (view.Offset == 0)
+ break;
+ else
+ view.Slide(-1, 2);
+ }
+ //foreach (int cell in list) Console.Write(" " + cell);
+ //Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 2, 4, 8, 668, 13, 6, 1, 667, 10, 666, 11));
+ }
+
+
+ [Test]
+ public void SyncRoot()
+ {
+ Assert.AreSame(view.SyncRoot, list.SyncRoot);
+ }
+ }
+ [TestFixture]
+ public class MulipleViews
+ {
+ IList<int> list;
+ IList<int>[][] views;
+ [SetUp]
+ public void Init()
+ {
+ list = new HashedLinkedList<int>();
+ for (int i = 0; i < 6; i++)
+ list.Add(i);
+ views = new IList<int>[7][];
+ for (int i = 0; i < 7; i++)
+ {
+ views[i] = new IList<int>[7 - i];
+ for (int j = 0; j < 7 - i; j++)
+ views[i][j] = list.View(i, j);
+ }
+ }
+ [TearDown]
+ public void Dispose()
+ {
+ list = null;
+ views = null;
+ }
+ [Test]
+ public void Insert()
+ {
+ Assert.IsTrue(list.Check(), "list check before insert");
+ list.Insert(3, 777);
+ Assert.IsTrue(list.Check(), "list check after insert");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i < 3 || (i == 3 && j == 0) ? i : i + 1, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(i < 3 && i + j > 3 ? j + 1 : j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+ [Test]
+ public void RemoveAt()
+ {
+ Assert.IsTrue(list.Check(), "list check before remove");
+ list.RemoveAt(3);
+ Assert.IsTrue(list.Check(), "list check after remove");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i <= 3 ? i : i - 1, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(i <= 3 && i + j > 3 ? j - 1 : j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+
+ [Test]
+ public void RemoveInterval()
+ {
+ Assert.IsTrue(list.Check(), "list check before remove");
+ list.RemoveInterval(3, 2);
+ Assert.IsTrue(list.Check(), "list check after remove");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i <= 3 ? i : i <= 5 ? 3 : i - 2, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(j == 0 ? 0 : i <= 3 && i + j > 4 ? j - 2 : i > 4 || i + j <= 3 ? j : j - 1, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+
+ [Test]
+ public void InsertAtEnd()
+ {
+ Assert.IsTrue(list.Check(), "list check before insert");
+ list.InsertLast(777);
+ Assert.IsTrue(list.Check(), "list check after insert");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+ [Test]
+ public void RemoveAtEnd()
+ {
+ Assert.IsTrue(list.Check(), "list check before remove");
+ list.RemoveAt(5);
+ Assert.IsTrue(list.Check(), "list check after remove");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i <= 5 ? i : i - 1, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(i <= 5 && i + j > 5 ? j - 1 : j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+ [Test]
+ public void InsertAtStart()
+ {
+ Assert.IsTrue(list.Check(), "list check before insert");
+ list.Insert(0, 777);
+ Assert.IsTrue(list.Check(), "list check after insert");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i == 0 && j == 0 ? 0 : i + 1, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+ [Test]
+ public void RemoveAtStart()
+ {
+ Assert.IsTrue(list.Check(), "list check before remove");
+ list.RemoveAt(0);
+ Assert.IsTrue(list.Check(), "list check after remove");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i == 0 ? i : i - 1, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(i == 0 && j > 0 ? j - 1 : j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+ [Test]
+ public void Clear()
+ {
+ Assert.IsTrue(list.Check(), "list check before clear");
+ //for (int i = 0; i < 7; i++)
+ //for (int j = 0; j < 7 - i; j++)
+ //Console.WriteLine("// view[{0}][{1}] : {2}", i, j, ((HashedLinkedList<int>) views[i][j]).GetHashCode());
+ views[2][3].Clear();
+ Assert.IsTrue(list.Check(), "list check after clear");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i < 2 ? i : i < 6 ? 2 : i - 3, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(s(i, j), views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+
+ private int s(int i, int j)
+ {
+ if (j == 0) return 0;
+ int k = i + j - 1; //end
+ if (i > 4 || k <= 1) return j;
+ if (i >= 2) return k > 4 ? k - 4 : 0;
+ if (i <= 2) return k >= 4 ? j - 3 : 2 - i;
+ return -1;
+ }
+ [Test]
+ public void InsertAll()
+ {
+ IList<int> list2 = new HashedLinkedList<int>();
+ for (int i = 0; i < 5; i++) { list2.Add(100 + i); }
+ Assert.IsTrue(list.Check(), "list check before insertAll");
+ list.InsertAll(3, list2);
+ Assert.IsTrue(list.Check(), "list check after insertAll");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i < 3 || (i == 3 && j == 0) ? i : i + 5, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(i < 3 && i + j > 3 ? j + 5 : j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+
+ [Test]
+ public void AddAll()
+ {
+ IList<int> list2 = new HashedLinkedList<int>();
+ for (int i = 0; i < 5; i++) { list2.Add(100 + i); }
+ Assert.IsTrue(list.Check(), "list check before AddAll");
+ list.View(1, 2).AddAll(list2);
+ Assert.IsTrue(list.Check(), "list check after AddAll");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i < 3 || (i == 3 && j == 0) ? i : i + 5, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(i < 3 && i + j > 3 ? j + 5 : j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+
+ [Test]
+ public void Remove()
+ {
+ for (int i = 0; i < 7; i++)
+ {
+ for (int j = 0; j < 7 - i; j++)
+ {
+ list = new HashedLinkedList<int>();
+ for (int k = 0; k < 6; k++) list.Add(k);
+ HashedLinkedList<int> v = (HashedLinkedList<int>)list.View(i, j);
+ list.Remove(3);
+ Assert.IsTrue(list.Check(), "list check after Remove, i=" + i + ", j=" + j);
+ }
+ }
+ }
+ [Test]
+ public void RemoveAll1()
+ {
+ IList<int> list2 = new HashedLinkedList<int>();
+ list2.Add(1); list2.Add(3); list2.Add(4);
+
+ for (int i = 0; i < 7; i++)
+ {
+ for (int j = 0; j < 7 - i; j++)
+ {
+ list = new HashedLinkedList<int>();
+ for (int k = 0; k < 6; k++) list.Add(k);
+ HashedLinkedList<int> v = (HashedLinkedList<int>)list.View(i, j);
+ list.RemoveAll(list2);
+ Assert.IsTrue(list.Check(), "list check after RemoveAll, i=" + i + ", j=" + j);
+ }
+ }
+ }
+ [Test]
+ public void RemoveAll2()
+ {
+ IList<int> list2 = new HashedLinkedList<int>();
+ list2.Add(1); list2.Add(3); list2.Add(4);
+ Assert.IsTrue(list.Check(), "list check before RemoveAll");
+ list.RemoveAll(list2);
+
+ Assert.AreEqual(0, views[0][0].Offset, "view [0][0] offset");
+ Assert.AreEqual(0, views[0][1].Offset, "view [0][1] offset");
+ Assert.AreEqual(0, views[0][2].Offset, "view [0][2] offset");
+ Assert.AreEqual(0, views[0][3].Offset, "view [0][3] offset");
+ Assert.AreEqual(0, views[0][4].Offset, "view [0][4] offset");
+ Assert.AreEqual(0, views[0][5].Offset, "view [0][5] offset");
+ Assert.AreEqual(0, views[0][6].Offset, "view [0][6] offset");
+ Assert.AreEqual(1, views[1][0].Offset, "view [1][0] offset");
+ Assert.AreEqual(1, views[1][1].Offset, "view [1][1] offset");
+ Assert.AreEqual(1, views[1][2].Offset, "view [1][2] offset");
+ Assert.AreEqual(1, views[1][3].Offset, "view [1][3] offset");
+ Assert.AreEqual(1, views[1][4].Offset, "view [1][4] offset");
+ Assert.AreEqual(1, views[1][5].Offset, "view [1][5] offset");
+ Assert.AreEqual(1, views[2][0].Offset, "view [2][0] offset");
+ Assert.AreEqual(1, views[2][1].Offset, "view [2][1] offset");
+ Assert.AreEqual(1, views[2][2].Offset, "view [2][2] offset");
+ Assert.AreEqual(1, views[2][3].Offset, "view [2][3] offset");
+ Assert.AreEqual(1, views[2][4].Offset, "view [2][4] offset");
+ Assert.AreEqual(2, views[3][0].Offset, "view [3][0] offset");
+ Assert.AreEqual(2, views[3][1].Offset, "view [3][1] offset");
+ Assert.AreEqual(2, views[3][2].Offset, "view [3][2] offset");
+ Assert.AreEqual(2, views[3][3].Offset, "view [3][3] offset");
+ Assert.AreEqual(2, views[4][0].Offset, "view [4][0] offset");
+ Assert.AreEqual(2, views[4][1].Offset, "view [4][1] offset");
+ Assert.AreEqual(2, views[4][2].Offset, "view [4][2] offset");
+ Assert.AreEqual(2, views[5][0].Offset, "view [5][0] offset");
+ Assert.AreEqual(2, views[5][1].Offset, "view [5][1] offset");
+ Assert.AreEqual(3, views[6][0].Offset, "view [6][0] offset");
+
+ Assert.AreEqual(0, views[0][0].Count, "view [0][0] count");
+ Assert.AreEqual(1, views[0][1].Count, "view [0][1] count");
+ Assert.AreEqual(1, views[0][2].Count, "view [0][2] count");
+ Assert.AreEqual(2, views[0][3].Count, "view [0][3] count");
+ Assert.AreEqual(2, views[0][4].Count, "view [0][4] count");
+ Assert.AreEqual(2, views[0][5].Count, "view [0][5] count");
+ Assert.AreEqual(3, views[0][6].Count, "view [0][6] count");
+ Assert.AreEqual(0, views[1][0].Count, "view [1][0] count");
+ Assert.AreEqual(0, views[1][1].Count, "view [1][1] count");
+ Assert.AreEqual(1, views[1][2].Count, "view [1][2] count");
+ Assert.AreEqual(1, views[1][3].Count, "view [1][3] count");
+ Assert.AreEqual(1, views[1][4].Count, "view [1][4] count");
+ Assert.AreEqual(2, views[1][5].Count, "view [1][5] count");
+ Assert.AreEqual(0, views[2][0].Count, "view [2][0] count");
+ Assert.AreEqual(1, views[2][1].Count, "view [2][1] count");
+ Assert.AreEqual(1, views[2][2].Count, "view [2][2] count");
+ Assert.AreEqual(1, views[2][3].Count, "view [2][3] count");
+ Assert.AreEqual(2, views[2][4].Count, "view [2][4] count");
+ Assert.AreEqual(0, views[3][0].Count, "view [3][0] count");
+ Assert.AreEqual(0, views[3][1].Count, "view [3][1] count");
+ Assert.AreEqual(0, views[3][2].Count, "view [3][2] count");
+ Assert.AreEqual(1, views[3][3].Count, "view [3][3] count");
+ Assert.AreEqual(0, views[4][0].Count, "view [4][0] count");
+ Assert.AreEqual(0, views[4][1].Count, "view [4][1] count");
+ Assert.AreEqual(1, views[4][2].Count, "view [4][2] count");
+ Assert.AreEqual(0, views[5][0].Count, "view [5][0] count");
+ Assert.AreEqual(1, views[5][1].Count, "view [5][1] count");
+ Assert.AreEqual(0, views[6][0].Count, "view [6][0] count");
+
+ Assert.IsTrue(list.Check(), "list check after RemoveAll");
+ }
+
+ [Test]
+ public void RetainAll()
+ {
+ IList<int> list2 = new HashedLinkedList<int>();
+ list2.Add(2); list2.Add(4); list2.Add(5);
+ Assert.IsTrue(list.Check(), "list check before RetainAll");
+ list.RetainAll(list2);
+ Assert.AreEqual(0, views[0][0].Offset, "view [0][0] offset");
+ Assert.AreEqual(0, views[0][1].Offset, "view [0][1] offset");
+ Assert.AreEqual(0, views[0][2].Offset, "view [0][2] offset");
+ Assert.AreEqual(0, views[0][3].Offset, "view [0][3] offset");
+ Assert.AreEqual(0, views[0][4].Offset, "view [0][4] offset");
+ Assert.AreEqual(0, views[0][5].Offset, "view [0][5] offset");
+ Assert.AreEqual(0, views[0][6].Offset, "view [0][6] offset");
+ Assert.AreEqual(0, views[1][0].Offset, "view [1][0] offset");
+ Assert.AreEqual(0, views[1][1].Offset, "view [1][1] offset");
+ Assert.AreEqual(0, views[1][2].Offset, "view [1][2] offset");
+ Assert.AreEqual(0, views[1][3].Offset, "view [1][3] offset");
+ Assert.AreEqual(0, views[1][4].Offset, "view [1][4] offset");
+ Assert.AreEqual(0, views[1][5].Offset, "view [1][5] offset");
+ Assert.AreEqual(0, views[2][0].Offset, "view [2][0] offset");
+ Assert.AreEqual(0, views[2][1].Offset, "view [2][1] offset");
+ Assert.AreEqual(0, views[2][2].Offset, "view [2][2] offset");
+ Assert.AreEqual(0, views[2][3].Offset, "view [2][3] offset");
+ Assert.AreEqual(0, views[2][4].Offset, "view [2][4] offset");
+ Assert.AreEqual(1, views[3][0].Offset, "view [3][0] offset");
+ Assert.AreEqual(1, views[3][1].Offset, "view [3][1] offset");
+ Assert.AreEqual(1, views[3][2].Offset, "view [3][2] offset");
+ Assert.AreEqual(1, views[3][3].Offset, "view [3][3] offset");
+ Assert.AreEqual(1, views[4][0].Offset, "view [4][0] offset");
+ Assert.AreEqual(1, views[4][1].Offset, "view [4][1] offset");
+ Assert.AreEqual(1, views[4][2].Offset, "view [4][2] offset");
+ Assert.AreEqual(2, views[5][0].Offset, "view [5][0] offset");
+ Assert.AreEqual(2, views[5][1].Offset, "view [5][1] offset");
+ Assert.AreEqual(3, views[6][0].Offset, "view [6][0] offset");
+
+ Assert.AreEqual(0, views[0][0].Count, "view [0][0] count");
+ Assert.AreEqual(0, views[0][1].Count, "view [0][1] count");
+ Assert.AreEqual(0, views[0][2].Count, "view [0][2] count");
+ Assert.AreEqual(1, views[0][3].Count, "view [0][3] count");
+ Assert.AreEqual(1, views[0][4].Count, "view [0][4] count");
+ Assert.AreEqual(2, views[0][5].Count, "view [0][5] count");
+ Assert.AreEqual(3, views[0][6].Count, "view [0][6] count");
+ Assert.AreEqual(0, views[1][0].Count, "view [1][0] count");
+ Assert.AreEqual(0, views[1][1].Count, "view [1][1] count");
+ Assert.AreEqual(1, views[1][2].Count, "view [1][2] count");
+ Assert.AreEqual(1, views[1][3].Count, "view [1][3] count");
+ Assert.AreEqual(2, views[1][4].Count, "view [1][4] count");
+ Assert.AreEqual(3, views[1][5].Count, "view [1][5] count");
+ Assert.AreEqual(0, views[2][0].Count, "view [2][0] count");
+ Assert.AreEqual(1, views[2][1].Count, "view [2][1] count");
+ Assert.AreEqual(1, views[2][2].Count, "view [2][2] count");
+ Assert.AreEqual(2, views[2][3].Count, "view [2][3] count");
+ Assert.AreEqual(3, views[2][4].Count, "view [2][4] count");
+ Assert.AreEqual(0, views[3][0].Count, "view [3][0] count");
+ Assert.AreEqual(0, views[3][1].Count, "view [3][1] count");
+ Assert.AreEqual(1, views[3][2].Count, "view [3][2] count");
+ Assert.AreEqual(2, views[3][3].Count, "view [3][3] count");
+ Assert.AreEqual(0, views[4][0].Count, "view [4][0] count");
+ Assert.AreEqual(1, views[4][1].Count, "view [4][1] count");
+ Assert.AreEqual(2, views[4][2].Count, "view [4][2] count");
+ Assert.AreEqual(0, views[5][0].Count, "view [5][0] count");
+ Assert.AreEqual(1, views[5][1].Count, "view [5][1] count");
+ Assert.AreEqual(0, views[6][0].Count, "view [6][0] count");
+
+
+ Assert.IsTrue(list.Check(), "list check after RetainAll");
+ }
+
+ [Test]
+ public void RemoveAllCopies()
+ {
+ IList<int> list2 = new HashedLinkedList<int>();
+ list2.Add(0); list2.Add(2); list2.Add(82); list2.Add(92); list2.Add(5); list2.Add(2); list2.Add(1);
+ for (int i = 0; i < 7; i++)
+ {
+ for (int j = 0; j < 7 - i; j++)
+ {
+ list = new HashedLinkedList<int>();
+ list.AddAll(list2);
+ HashedLinkedList<int> v = (HashedLinkedList<int>)list.View(i, j);
+ list.RemoveAllCopies(2);
+ Assert.IsTrue(list.Check(), "list check after RemoveAllCopies, i=" + i + ", j=" + j);
+ }
+ }
+ }
+
+ private void checkDisposed(bool reverse, int start, int count)
+ {
+ int k = 0;
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ if (i + j <= start || i >= start + count || (i <= start && i + j >= start + count) || (reverse && start <= i && start + count >= i + j))
+ {
+ try
+ {
+ k = views[i][j].Count;
+ }
+ catch (ViewDisposedException)
+ {
+ Assert.Fail("view[" + i + "][" + j + "] threw");
+ }
+ Assert.AreEqual(j, views[i][j].Count, "view[" + i + "][" + j + "] size");
+ if (reverse && ((j > 0 && start <= i && start + count >= i + j) || (j == 0 && start < i && start + count > i)))
+ Assert.AreEqual(start + (start + count - i - j), views[i][j].Offset, "view[" + i + "][" + j + "] offset (mirrored)");
+ else
+ Assert.AreEqual(i, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ }
+ else
+ {
+ try
+ {
+ k = views[i][j].Count;
+ Assert.Fail("view[" + i + "][" + j + "] no throw");
+ }
+ catch (ViewDisposedException) { }
+ }
+ }
+ }
+
+ [Test]
+ public void Reverse()
+ {
+ int start = 2, count = 3;
+ IList<int> list2 = list.View(start, count);
+ Assert.IsTrue(list.Check(), "list check before Reverse");
+ list2.Reverse();
+ Assert.IsTrue(list.Check(), "list check after Reverse");
+ checkDisposed(true, start, count);
+ }
+
+ [Test]
+ public void Sort()
+ {
+ int start = 2, count = 3;
+ IList<int> list2 = list.View(start, count);
+ Assert.IsTrue(list.Check(), "list check before Sort");
+ list2.Sort();
+ Assert.IsTrue(list.Check(), "list check after Sort");
+ checkDisposed(false, start, count);
+ }
+ [Test]
+ public void Shuffle()
+ {
+ int start = 2, count = 3;
+ IList<int> list2 = list.View(start, count);
+ Assert.IsTrue(list.Check(), "list check before Shuffle");
+ list2.Shuffle();
+ Assert.IsTrue(list.Check(), "list check after Shuffle");
+ checkDisposed(false, start, count);
+ }
+
+
+ }
+
+ }
+
+ namespace HashingAndEquals
+ {
+ [TestFixture]
+ public class ISequenced
+ {
+ private ISequenced<int> dit, dat, dut;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new HashedLinkedList<int>();
+ dat = new HashedLinkedList<int>();
+ dut = new HashedLinkedList<int>();
+ }
+
+
+ [Test]
+ public void EmptyEmpty()
+ {
+ Assert.IsTrue(dit.SequencedEquals(dat));
+ }
+
+
+ [Test]
+ public void EmptyNonEmpty()
+ {
+ dit.Add(3);
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ Assert.IsFalse(dat.SequencedEquals(dit));
+ }
+
+ [Test]
+ public void HashVal()
+ {
+ Assert.AreEqual(CHC.sequencedhashcode(), dit.GetSequencedHashCode());
+ dit.Add(3);
+ Assert.AreEqual(CHC.sequencedhashcode(3), dit.GetSequencedHashCode());
+ dit.Add(7);
+ Assert.AreEqual(CHC.sequencedhashcode(3, 7), dit.GetSequencedHashCode());
+ Assert.AreEqual(CHC.sequencedhashcode(), dut.GetSequencedHashCode());
+ dut.Add(7);
+ Assert.AreEqual(CHC.sequencedhashcode(7), dut.GetSequencedHashCode());
+ dut.Add(3);
+ Assert.AreEqual(CHC.sequencedhashcode(7, 3), dut.GetSequencedHashCode());
+ }
+
+
+ [Test]
+ public void EqualHashButDifferent()
+ {
+ dit.Add(0); dit.Add(31);
+ dat.Add(1); dat.Add(0);
+ Assert.AreEqual(dit.GetSequencedHashCode(), dat.GetSequencedHashCode());
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ }
+
+
+ [Test]
+ public void Normal()
+ {
+ dit.Add(3);
+ dit.Add(7);
+ dat.Add(3);
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ Assert.IsFalse(dat.SequencedEquals(dit));
+ dat.Add(7);
+ Assert.IsTrue(dit.SequencedEquals(dat));
+ Assert.IsTrue(dat.SequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void WrongOrder()
+ {
+ dit.Add(3);
+ dut.Add(3);
+ Assert.IsTrue(dit.SequencedEquals(dut));
+ Assert.IsTrue(dut.SequencedEquals(dit));
+ dit.Add(7);
+ ((HashedLinkedList<int>)dut).InsertFirst(7);
+ Assert.IsFalse(dit.SequencedEquals(dut));
+ Assert.IsFalse(dut.SequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void Reflexive()
+ {
+ Assert.IsTrue(dit.SequencedEquals(dit));
+ dit.Add(3);
+ Assert.IsTrue(dit.SequencedEquals(dit));
+ dit.Add(7);
+ Assert.IsTrue(dit.SequencedEquals(dit));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = null;
+ dat = null;
+ dut = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class IEditableCollection
+ {
+ private ICollection<int> dit, dat, dut;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new HashedLinkedList<int>();
+ dat = new HashedLinkedList<int>();
+ dut = new HashedLinkedList<int>();
+ }
+
+
+ [Test]
+ public void EmptyEmpty()
+ {
+ Assert.IsTrue(dit.UnsequencedEquals(dat));
+ }
+
+
+ [Test]
+ public void EmptyNonEmpty()
+ {
+ dit.Add(3);
+ Assert.IsFalse(dit.UnsequencedEquals(dat));
+ Assert.IsFalse(dat.UnsequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void HashVal()
+ {
+ Assert.AreEqual(CHC.unsequencedhashcode(), dit.GetUnsequencedHashCode());
+ dit.Add(3);
+ Assert.AreEqual(CHC.unsequencedhashcode(3), dit.GetUnsequencedHashCode());
+ dit.Add(7);
+ Assert.AreEqual(CHC.unsequencedhashcode(3, 7), dit.GetUnsequencedHashCode());
+ Assert.AreEqual(CHC.unsequencedhashcode(), dut.GetUnsequencedHashCode());
+ dut.Add(3);
+ Assert.AreEqual(CHC.unsequencedhashcode(3), dut.GetUnsequencedHashCode());
+ dut.Add(7);
+ Assert.AreEqual(CHC.unsequencedhashcode(7, 3), dut.GetUnsequencedHashCode());
+ }
+
+
+ [Test]
+ public void EqualHashButDifferent()
+ {
+ dit.Add(-1657792980); dit.Add(-1570288808);
+ dat.Add(1862883298); dat.Add(-272461342);
+ Assert.AreEqual(dit.GetUnsequencedHashCode(), dat.GetUnsequencedHashCode());
+ Assert.IsFalse(dit.UnsequencedEquals(dat));
+ }
+
+
+ [Test]
+ public void Normal()
+ {
+ dit.Add(3);
+ dit.Add(7);
+ dat.Add(3);
+ Assert.IsFalse(dit.UnsequencedEquals(dat));
+ Assert.IsFalse(dat.UnsequencedEquals(dit));
+ dat.Add(7);
+ Assert.IsTrue(dit.UnsequencedEquals(dat));
+ Assert.IsTrue(dat.UnsequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void WrongOrder()
+ {
+ dit.Add(3);
+ dut.Add(3);
+ Assert.IsTrue(dit.UnsequencedEquals(dut));
+ Assert.IsTrue(dut.UnsequencedEquals(dit));
+ dit.Add(7);
+ dut.Add(7);
+ Assert.IsTrue(dit.UnsequencedEquals(dut));
+ Assert.IsTrue(dut.UnsequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void Reflexive()
+ {
+ Assert.IsTrue(dit.UnsequencedEquals(dit));
+ dit.Add(3);
+ Assert.IsTrue(dit.UnsequencedEquals(dit));
+ dit.Add(7);
+ Assert.IsTrue(dit.UnsequencedEquals(dit));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = null;
+ dat = null;
+ dut = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class MultiLevelUnorderedOfUnOrdered
+ {
+ private ICollection<int> dit, dat, dut;
+
+ private ICollection<ICollection<int>> Dit, Dat, Dut;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new HashedLinkedList<int>();
+ dat = new HashedLinkedList<int>();
+ dut = new HashedLinkedList<int>();
+ dit.Add(2); dit.Add(1);
+ dat.Add(1); dat.Add(2);
+ dut.Add(3);
+ Dit = new HashedLinkedList<ICollection<int>>();
+ Dat = new HashedLinkedList<ICollection<int>>();
+ Dut = new HashedLinkedList<ICollection<int>>();
+ }
+
+
+ [Test]
+ public void Check()
+ {
+ Assert.IsTrue(dit.UnsequencedEquals(dat));
+ Assert.IsFalse(dit.UnsequencedEquals(dut));
+ }
+
+
+ [Test]
+ public void Multi()
+ {
+ Dit.Add(dit); Dit.Add(dut); Dit.Add(dit);
+ Dat.Add(dut); Dat.Add(dit); Dat.Add(dat);
+ Assert.IsTrue(Dit.UnsequencedEquals(Dat));
+ Assert.IsFalse(Dit.UnsequencedEquals(Dut));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = dat = dut = null;
+ Dit = Dat = Dut = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class MultiLevelOrderedOfUnOrdered
+ {
+ private ICollection<int> dit, dat, dut;
+
+ private ISequenced<ICollection<int>> Dit, Dat, Dut;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new HashedLinkedList<int>();
+ dat = new HashedLinkedList<int>();
+ dut = new HashedLinkedList<int>();
+ dit.Add(2); dit.Add(1);
+ dat.Add(1); dat.Add(2);
+ dut.Add(3);
+ Dit = new HashedLinkedList<ICollection<int>>();
+ Dat = new HashedLinkedList<ICollection<int>>();
+ Dut = new HashedLinkedList<ICollection<int>>();
+ }
+
+
+ [Test]
+ public void Check()
+ {
+ Assert.IsTrue(dit.UnsequencedEquals(dat));
+ Assert.IsFalse(dit.UnsequencedEquals(dut));
+ }
+
+
+ [Test]
+ public void Multi()
+ {
+ Dit.Add(dit); Dit.Add(dut); Dit.Add(dit);
+ Dat.Add(dut); Dat.Add(dit); Dat.Add(dat);
+ Dut.Add(dit); Dut.Add(dut); Dut.Add(dat);
+ Assert.IsFalse(Dit.SequencedEquals(Dat));
+ Assert.IsTrue(Dit.SequencedEquals(Dut));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = dat = dut = null;
+ Dit = Dat = Dut = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class MultiLevelUnOrderedOfOrdered
+ {
+ private ISequenced<int> dit, dat, dut, dot;
+
+ private ICollection<ISequenced<int>> Dit, Dat, Dut, Dot;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new HashedLinkedList<int>();
+ dat = new HashedLinkedList<int>();
+ dut = new HashedLinkedList<int>();
+ dot = new HashedLinkedList<int>();
+ dit.Add(2); dit.Add(1);
+ dat.Add(1); dat.Add(2);
+ dut.Add(3);
+ dot.Add(2); dot.Add(1);
+ Dit = new HashedLinkedList<ISequenced<int>>();
+ Dat = new HashedLinkedList<ISequenced<int>>();
+ Dut = new HashedLinkedList<ISequenced<int>>();
+ Dot = new HashedLinkedList<ISequenced<int>>();
+ }
+
+
+ [Test]
+ public void Check()
+ {
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ Assert.IsTrue(dit.SequencedEquals(dot));
+ Assert.IsFalse(dit.SequencedEquals(dut));
+ }
+
+
+ [Test]
+ public void Multi()
+ {
+ Dit.Add(dit); Dit.Add(dut); Dit.Add(dit);
+ Dat.Add(dut); Dat.Add(dit); Dat.Add(dat);
+ Dut.Add(dot); Dut.Add(dut); Dut.Add(dit);
+ Dot.Add(dit); Dot.Add(dit); Dot.Add(dut);
+ Assert.IsTrue(Dit.UnsequencedEquals(Dut));
+ Assert.IsFalse(Dit.UnsequencedEquals(Dat));
+ Assert.IsTrue(Dit.UnsequencedEquals(Dot));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = dat = dut = dot = null;
+ Dit = Dat = Dut = Dot = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class MultiLevelOrderedOfOrdered
+ {
+ private ISequenced<int> dit, dat, dut, dot;
+
+ private ISequenced<ISequenced<int>> Dit, Dat, Dut, Dot;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new HashedLinkedList<int>();
+ dat = new HashedLinkedList<int>();
+ dut = new HashedLinkedList<int>();
+ dot = new HashedLinkedList<int>();
+ dit.Add(2); dit.Add(1); //{2,1}
+ dat.Add(1); dat.Add(2); //{1,2}
+ dut.Add(3); //{3}
+ dot.Add(2); dot.Add(1); //{2,1}
+ Dit = new HashedLinkedList<ISequenced<int>>();
+ Dat = new HashedLinkedList<ISequenced<int>>();
+ Dut = new HashedLinkedList<ISequenced<int>>();
+ Dot = new HashedLinkedList<ISequenced<int>>();
+ }
+
+
+ [Test]
+ public void Check()
+ {
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ Assert.IsTrue(dit.SequencedEquals(dot));
+ Assert.IsFalse(dit.SequencedEquals(dut));
+ }
+
+
+ [Test]
+ public void Multi()
+ {
+ Dit.Add(dit); Dit.Add(dut); Dit.Add(dit); // {{2,1},{3}}
+ Dat.Add(dut); Dat.Add(dit); Dat.Add(dat); // {{3},{2,1},{1,2}}
+ Dut.Add(dot); Dut.Add(dut); Dut.Add(dit); // {{2,1},{3}}
+ Dot.Add(dit); Dot.Add(dit); Dot.Add(dut); // {{2,1},{3}}
+ Assert.IsTrue(Dit.SequencedEquals(Dut));
+ Assert.IsFalse(Dit.SequencedEquals(Dat));
+ Assert.IsTrue(Dit.SequencedEquals(Dot));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = dat = dut = dot = null;
+ Dit = Dat = Dut = Dot = null;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/1.0/Test/linkedlists/LinkedListTest.cs b/mcs/class/Mono.C5/1.0/Test/linkedlists/LinkedListTest.cs
new file mode 100644
index 00000000000..2ba2f89ebf4
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/Test/linkedlists/LinkedListTest.cs
@@ -0,0 +1,3411 @@
+/*
+ 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 C5;
+using NUnit.Framework;
+using SCG = System.Collections.Generic;
+
+
+namespace C5UnitTests.linkedlists.plain
+{
+ using CollectionOfInt = LinkedList<int>;
+
+ [TestFixture]
+ public class GenericTesters
+ {
+
+ [Test]
+ public void TestEvents()
+ {
+ Fun<CollectionOfInt> factory = delegate() { return new CollectionOfInt(TenEqualityComparer.Default); };
+ new C5UnitTests.Templates.Events.ListTester<CollectionOfInt>().Test(factory);
+ new C5UnitTests.Templates.Events.QueueTester<CollectionOfInt>().Test(factory);
+ new C5UnitTests.Templates.Events.StackTester<CollectionOfInt>().Test(factory);
+ }
+
+ [Test]
+ public void Extensible()
+ {
+ C5UnitTests.Templates.Extensible.Clone.Tester<CollectionOfInt>();
+ C5UnitTests.Templates.Extensible.Clone.ViewTester<CollectionOfInt>();
+ C5UnitTests.Templates.Extensible.Serialization.Tester<CollectionOfInt>();
+ C5UnitTests.Templates.Extensible.Serialization.ViewTester<CollectionOfInt>();
+ }
+ }
+
+ static class Factory
+ {
+ public static ICollection<T> New<T>() { return new LinkedList<T>(); }
+ }
+
+ namespace Enumerable
+ {
+ [TestFixture]
+ public class Multiops
+ {
+ private LinkedList<int> list;
+
+ private Fun<int, bool> always, never, even;
+
+
+ [SetUp]
+ public void Init()
+ {
+ list = new LinkedList<int>();
+ always = delegate { return true; };
+ never = delegate { return false; };
+ even = delegate(int i) { return i % 2 == 0; };
+ }
+
+
+ [Test]
+ public void All()
+ {
+ Assert.IsTrue(list.All(always));
+ Assert.IsTrue(list.All(never));
+ Assert.IsTrue(list.All(even));
+ list.Add(8);
+ Assert.IsTrue(list.All(always));
+ Assert.IsFalse(list.All(never));
+ Assert.IsTrue(list.All(even));
+ list.Add(5);
+ Assert.IsTrue(list.All(always));
+ Assert.IsFalse(list.All(never));
+ Assert.IsFalse(list.All(even));
+ }
+
+
+ [Test]
+ public void Exists()
+ {
+ Assert.IsFalse(list.Exists(always));
+ Assert.IsFalse(list.Exists(never));
+ Assert.IsFalse(list.Exists(even));
+ list.Add(5);
+ Assert.IsTrue(list.Exists(always));
+ Assert.IsFalse(list.Exists(never));
+ Assert.IsFalse(list.Exists(even));
+ list.Add(8);
+ Assert.IsTrue(list.Exists(always));
+ Assert.IsFalse(list.Exists(never));
+ Assert.IsTrue(list.Exists(even));
+ }
+
+
+ [Test]
+ public void Apply()
+ {
+ int sum = 0;
+ Act<int> a = delegate(int i) { sum = i + 10 * sum; };
+
+ list.Apply(a);
+ Assert.AreEqual(0, sum);
+ sum = 0;
+ list.Add(5); list.Add(8); list.Add(7); list.Add(5);
+ list.Apply(a);
+ Assert.AreEqual(5875, sum);
+ }
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+ }
+
+
+
+ [TestFixture]
+ public class GetEnumerator
+ {
+ private LinkedList<int> list;
+
+
+ [SetUp]
+ public void Init() { list = new LinkedList<int>(); }
+
+
+ [Test]
+ public void Empty()
+ {
+ SCG.IEnumerator<int> e = list.GetEnumerator();
+
+ Assert.IsFalse(e.MoveNext());
+ }
+
+
+ [Test]
+ public void Normal()
+ {
+ list.Add(5);
+ list.Add(8);
+ list.Add(5);
+ list.Add(5);
+ list.Add(10);
+ list.Add(1);
+
+ SCG.IEnumerator<int> e = list.GetEnumerator();
+
+ Assert.IsTrue(e.MoveNext());
+ Assert.AreEqual(5, e.Current);
+ Assert.IsTrue(e.MoveNext());
+ Assert.AreEqual(8, e.Current);
+ Assert.IsTrue(e.MoveNext());
+ Assert.AreEqual(5, e.Current);
+ Assert.IsTrue(e.MoveNext());
+ Assert.AreEqual(5, e.Current);
+ Assert.IsTrue(e.MoveNext());
+ Assert.AreEqual(10, e.Current);
+ Assert.IsTrue(e.MoveNext());
+ Assert.AreEqual(1, e.Current);
+ Assert.IsFalse(e.MoveNext());
+ }
+
+
+ [Test]
+ public void DoDispose()
+ {
+ list.Add(5);
+ list.Add(8);
+ list.Add(5);
+
+ SCG.IEnumerator<int> e = list.GetEnumerator();
+
+ e.MoveNext();
+ e.MoveNext();
+ e.Dispose();
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void MoveNextAfterUpdate()
+ {
+ list.Add(5);
+ list.Add(8);
+ list.Add(5);
+
+ SCG.IEnumerator<int> e = list.GetEnumerator();
+
+ e.MoveNext();
+ list.Add(99);
+ e.MoveNext();
+ }
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+ }
+ }
+
+ namespace CollectionOrExtensible
+ {
+ [TestFixture]
+ public class Formatting
+ {
+ ICollection<int> coll;
+ IFormatProvider rad16;
+ [SetUp]
+ public void Init() { coll = Factory.New<int>(); rad16 = new RadixFormatProvider(16); }
+ [TearDown]
+ public void Dispose() { coll = null; rad16 = null; }
+ [Test]
+ public void Format()
+ {
+ Assert.AreEqual("[ ]", coll.ToString());
+ coll.AddAll<int>(new int[] { -4, 28, 129, 65530 });
+ Assert.AreEqual("[ -4, 28, 129, 65530 ]", coll.ToString());
+ Assert.AreEqual("[ -4, 1C, 81, FFFA ]", coll.ToString(null, rad16));
+ Assert.AreEqual("[ -4, 28, 129... ]", coll.ToString("L14", null));
+ Assert.AreEqual("[ -4, 1C, 81... ]", coll.ToString("L14", rad16));
+ }
+ }
+
+ [TestFixture]
+ public class CollectionOrSink
+ {
+ private LinkedList<int> list;
+
+
+ [SetUp]
+ public void Init() { list = new LinkedList<int>(); }
+
+ [Test]
+ [ExpectedException(typeof(NullReferenceException))]
+ public void NullEqualityComparerinConstructor1()
+ {
+ new LinkedList<int>(null);
+ }
+
+ [Test]
+ public void Choose()
+ {
+ list.Add(7);
+ Assert.AreEqual(7, list.Choose());
+ }
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void BadChoose()
+ {
+ list.Choose();
+ }
+
+
+ [Test]
+ public void CountEtAl()
+ {
+ Assert.AreEqual(0, list.Count);
+ Assert.IsTrue(list.IsEmpty);
+ Assert.IsTrue(list.AllowsDuplicates);
+ list.Add(5);
+ Assert.AreEqual(1, list.Count);
+ Assert.IsFalse(list.IsEmpty);
+ list.Add(5);
+ Assert.AreEqual(2, list.Count);
+ Assert.IsFalse(list.IsEmpty);
+ list.Add(8);
+ Assert.AreEqual(3, list.Count);
+ }
+
+
+ [Test]
+ public void AddAll()
+ {
+ list.Add(3); list.Add(4); list.Add(5);
+
+ LinkedList<int> list2 = new LinkedList<int>();
+
+ list2.AddAll(list);
+ Assert.IsTrue(IC.eq(list2, 3, 4, 5));
+ list.AddAll(list2);
+ Assert.IsTrue(IC.eq(list2, 3, 4, 5));
+ Assert.IsTrue(IC.eq(list, 3, 4, 5, 3, 4, 5));
+ }
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+ }
+
+ [TestFixture]
+ public class FindPredicate
+ {
+ private LinkedList<int> list;
+ Fun<int, bool> pred;
+
+ [SetUp]
+ public void Init()
+ {
+ list = new LinkedList<int>(TenEqualityComparer.Default);
+ pred = delegate(int i) { return i % 5 == 0; };
+ }
+
+ [TearDown]
+ public void Dispose() { list = null; }
+
+ [Test]
+ public void Find()
+ {
+ int i;
+ Assert.IsFalse(list.Find(pred, out i));
+ list.AddAll<int>(new int[] { 4, 22, 67, 37 });
+ Assert.IsFalse(list.Find(pred, out i));
+ list.AddAll<int>(new int[] { 45, 122, 675, 137 });
+ Assert.IsTrue(list.Find(pred, out i));
+ Assert.AreEqual(45, i);
+ }
+
+ [Test]
+ public void FindLast()
+ {
+ int i;
+ Assert.IsFalse(list.FindLast(pred, out i));
+ list.AddAll<int>(new int[] { 4, 22, 67, 37 });
+ Assert.IsFalse(list.FindLast(pred, out i));
+ list.AddAll<int>(new int[] { 45, 122, 675, 137 });
+ Assert.IsTrue(list.FindLast(pred, out i));
+ Assert.AreEqual(675, i);
+ }
+
+ [Test]
+ public void FindIndex()
+ {
+ Assert.IsFalse(0 <= list.FindIndex(pred));
+ list.AddAll<int>(new int[] { 4, 22, 67, 37 });
+ Assert.IsFalse(0 <= list.FindIndex(pred));
+ list.AddAll<int>(new int[] { 45, 122, 675, 137 });
+ Assert.AreEqual(4, list.FindIndex(pred));
+ }
+
+ [Test]
+ public void FindLastIndex()
+ {
+ Assert.IsFalse(0 <= list.FindLastIndex(pred));
+ list.AddAll<int>(new int[] { 4, 22, 67, 37 });
+ Assert.IsFalse(0 <= list.FindLastIndex(pred));
+ list.AddAll<int>(new int[] { 45, 122, 675, 137 });
+ Assert.AreEqual(6, list.FindLastIndex(pred));
+ }
+ }
+
+ [TestFixture]
+ public class UniqueItems
+ {
+ private LinkedList<int> list;
+
+ [SetUp]
+ public void Init() { list = new LinkedList<int>(); }
+
+ [TearDown]
+ public void Dispose() { list = null; }
+
+ [Test]
+ public void Test()
+ {
+ Assert.IsTrue(IC.seteq(list.UniqueItems()));
+ Assert.IsTrue(IC.seteq(list.ItemMultiplicities()));
+ list.AddAll<int>(new int[] { 7, 9, 7 });
+ Assert.IsTrue(IC.seteq(list.UniqueItems(), 7, 9));
+ Assert.IsTrue(IC.seteq(list.ItemMultiplicities(), 7, 2, 9, 1));
+ }
+ }
+
+ [TestFixture]
+ public class ArrayTest
+ {
+ private LinkedList<int> list;
+
+ int[] a;
+
+
+ [SetUp]
+ public void Init()
+ {
+ list = new LinkedList<int>();
+ a = new int[10];
+ for (int i = 0; i < 10; i++)
+ a[i] = 1000 + i;
+ }
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+
+
+ private string aeq(int[] a, params int[] b)
+ {
+ if (a.Length != b.Length)
+ return "Lengths differ: " + a.Length + " != " + b.Length;
+
+ for (int i = 0; i < a.Length; i++)
+ if (a[i] != b[i])
+ return String.Format("{0}'th elements differ: {1} != {2}", i, a[i], b[i]);
+
+ return "Alles klar";
+ }
+
+
+ [Test]
+ public void ToArray()
+ {
+ Assert.AreEqual("Alles klar", aeq(list.ToArray()));
+ list.Add(7);
+ list.Add(7);
+ Assert.AreEqual("Alles klar", aeq(list.ToArray(), 7, 7));
+ }
+
+
+ [Test]
+ public void CopyTo()
+ {
+ list.CopyTo(a, 1);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009));
+ list.Add(6);
+ list.CopyTo(a, 2);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 6, 1003, 1004, 1005, 1006, 1007, 1008, 1009));
+ list.Add(4);
+ list.Add(4);
+ list.Add(9);
+ list.CopyTo(a, 4);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 6, 1003, 6, 4, 4, 9, 1008, 1009));
+ list.Clear();
+ list.Add(7);
+ list.CopyTo(a, 9);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 6, 1003, 6, 4, 4, 9, 1008, 7));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void CopyToBad()
+ {
+ list.CopyTo(a, 11);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void CopyToBad2()
+ {
+ list.CopyTo(a, -1);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void CopyToTooFar()
+ {
+ list.Add(3);
+ list.Add(3);
+ list.CopyTo(a, 9);
+ }
+ }
+
+
+
+ [TestFixture]
+ public class Sync
+ {
+ private LinkedList<int> list;
+
+
+ [SetUp]
+ public void Init()
+ {
+ list = new LinkedList<int>();
+ }
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+
+
+ [Test]
+ public void Get()
+ {
+ Assert.IsNotNull(list.SyncRoot);
+ }
+ }
+ }
+
+
+
+
+ namespace EditableCollection
+ {
+ [TestFixture]
+ public class Searching
+ {
+ private LinkedList<int> list;
+
+
+ [SetUp]
+ public void Init() { list = new LinkedList<int>(); }
+
+
+ [Test]
+ public void Contains()
+ {
+ Assert.IsFalse(list.Contains(5));
+ list.Add(5);
+ Assert.IsTrue(list.Contains(5));
+ Assert.IsFalse(list.Contains(7));
+ list.Add(8);
+ list.Add(10);
+ Assert.IsTrue(list.Contains(5));
+ Assert.IsFalse(list.Contains(7));
+ Assert.IsTrue(list.Contains(8));
+ Assert.IsTrue(list.Contains(10));
+ list.Remove(8);
+ Assert.IsTrue(list.Contains(5));
+ Assert.IsFalse(list.Contains(7));
+ Assert.IsFalse(list.Contains(8));
+ Assert.IsTrue(list.Contains(10));
+ }
+
+
+ [Test]
+ public void ContainsCount()
+ {
+ Assert.AreEqual(0, list.ContainsCount(5));
+ list.Add(5);
+ Assert.AreEqual(1, list.ContainsCount(5));
+ Assert.AreEqual(0, list.ContainsCount(7));
+ list.Add(8);
+ Assert.AreEqual(1, list.ContainsCount(5));
+ Assert.AreEqual(0, list.ContainsCount(7));
+ Assert.AreEqual(1, list.ContainsCount(8));
+ list.Add(5);
+ Assert.AreEqual(2, list.ContainsCount(5));
+ Assert.AreEqual(0, list.ContainsCount(7));
+ Assert.AreEqual(1, list.ContainsCount(8));
+ }
+
+
+ [Test]
+ public void RemoveAllCopies()
+ {
+ list.Add(5); list.Add(7); list.Add(5);
+ Assert.AreEqual(2, list.ContainsCount(5));
+ Assert.AreEqual(1, list.ContainsCount(7));
+ list.RemoveAllCopies(5);
+ Assert.AreEqual(0, list.ContainsCount(5));
+ Assert.AreEqual(1, list.ContainsCount(7));
+ list.Add(5); list.Add(8); list.Add(5);
+ list.RemoveAllCopies(8);
+ Assert.IsTrue(IC.eq(list, 7, 5, 5));
+ }
+
+
+ [Test]
+ public void FindAll()
+ {
+ Fun<int, bool> f = delegate(int i) { return i % 2 == 0; };
+
+ Assert.IsTrue(list.FindAll(f).IsEmpty);
+ list.Add(5); list.Add(8); list.Add(5); list.Add(10); list.Add(8);
+ Assert.IsTrue(((LinkedList<int>)list.FindAll(f)).Check());
+ Assert.IsTrue(IC.eq(list.FindAll(f), 8, 10, 8));
+ }
+
+
+ [Test]
+ public void ContainsAll()
+ {
+ LinkedList<int> list2 = new LinkedList<int>();
+
+ Assert.IsTrue(list.ContainsAll(list2));
+ list2.Add(4);
+ Assert.IsFalse(list.ContainsAll(list2));
+ list.Add(4);
+ Assert.IsTrue(list.ContainsAll(list2));
+ list.Add(5);
+ Assert.IsTrue(list.ContainsAll(list2));
+ list2.Add(4);
+ Assert.IsFalse(list.ContainsAll(list2));
+ list.Add(4);
+ Assert.IsTrue(list.ContainsAll(list2));
+ }
+
+
+ [Test]
+ public void RetainAll()
+ {
+ LinkedList<int> list2 = new LinkedList<int>();
+
+ list.Add(4); list.Add(4); list.Add(5); list.Add(4); list.Add(6);
+ list2.Add(5); list2.Add(4); list2.Add(7); list2.Add(7); list2.Add(4);
+ list.RetainAll(list2);
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4, 4, 5));
+ list.Add(5); list.Add(4); list.Add(6);
+ list2.Clear();
+ list2.Add(5); list2.Add(5); list2.Add(6);
+ list.RetainAll(list2);
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 5, 5, 6));
+ list2.Clear();
+ list2.Add(7); list2.Add(8); list2.Add(9);
+ list.RetainAll(list2);
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list));
+ }
+
+
+ [Test]
+ public void RemoveAll()
+ {
+ LinkedList<int> list2 = new LinkedList<int>();
+
+ list.Add(4); list.Add(4); list.Add(5); list.Add(4); list.Add(6);
+ list2.Add(5); list2.Add(4); list2.Add(7); list2.Add(7); list2.Add(4);
+ list.RemoveAll(list2);
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4, 6));
+ list.Add(5); list.Add(4); list.Add(6);
+ list2.Clear();
+ list2.Add(6); list2.Add(5); list2.Add(5); list2.Add(6);
+ list.RemoveAll(list2);
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4, 4));
+ list2.Clear();
+ list2.Add(7); list2.Add(8); list2.Add(9);
+ list.RemoveAll(list2);
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4, 4));
+ }
+
+
+ [Test]
+ public void Remove()
+ {
+
+ Assert.IsTrue(list.FIFO);
+ list.Add(4); list.Add(4); list.Add(5); list.Add(4); list.Add(6);
+ Assert.IsFalse(list.Remove(2));
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(list.Remove(4));
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4, 5, 4, 6));
+ Assert.AreEqual(6, list.RemoveLast());
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4, 5, 4));
+ list.Add(7);
+ Assert.AreEqual(4, list.RemoveFirst());
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 5, 4, 7));
+
+ list.FIFO = false;
+ list.Clear();
+ list.Add(4); list.Add(4); list.Add(5); list.Add(4); list.Add(6);
+ Assert.IsFalse(list.Remove(2));
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(list.Remove(4));
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4, 4, 5, 6));
+ Assert.AreEqual(6, list.RemoveLast());
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4, 4, 5));
+ list.Add(7);
+ Assert.AreEqual(4, list.RemoveFirst());
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 4, 5, 7));
+ }
+
+
+ [Test]
+ public void Clear()
+ {
+ list.Add(7); list.Add(7);
+ list.Clear();
+ Assert.IsTrue(list.IsEmpty);
+ }
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+ }
+ }
+
+
+
+
+ namespace IIndexed
+ {
+ [TestFixture]
+ public class Searching
+ {
+ private IIndexed<int> dit;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new LinkedList<int>();
+ }
+
+
+ [Test]
+ public void IndexOf()
+ {
+ Assert.AreEqual(~0, dit.IndexOf(6));
+ dit.Add(7);
+ Assert.AreEqual(~1, dit.IndexOf(6));
+ Assert.AreEqual(~1, dit.LastIndexOf(6));
+ Assert.AreEqual(0, dit.IndexOf(7));
+ dit.Add(5); dit.Add(7); dit.Add(8); dit.Add(7);
+ Assert.AreEqual(~5, dit.IndexOf(6));
+ Assert.AreEqual(0, dit.IndexOf(7));
+ Assert.AreEqual(4, dit.LastIndexOf(7));
+ Assert.AreEqual(3, dit.IndexOf(8));
+ Assert.AreEqual(1, dit.LastIndexOf(5));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class Removing
+ {
+ private IIndexed<int> dit;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new LinkedList<int>();
+ }
+
+
+ [Test]
+ public void RemoveAt()
+ {
+ dit.Add(5); dit.Add(7); dit.Add(9); dit.Add(1); dit.Add(2);
+ Assert.AreEqual(7, dit.RemoveAt(1));
+ Assert.IsTrue(((LinkedList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 5, 9, 1, 2));
+ Assert.AreEqual(5, dit.RemoveAt(0));
+ Assert.IsTrue(((LinkedList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 9, 1, 2));
+ Assert.AreEqual(2, dit.RemoveAt(2));
+ Assert.IsTrue(((LinkedList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 9, 1));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void RemoveAtBad0()
+ {
+ dit.RemoveAt(0);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void RemoveAtBadM1()
+ {
+ dit.RemoveAt(-1);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void RemoveAtBad1()
+ {
+ dit.Add(8);
+ dit.RemoveAt(1);
+ }
+
+
+ [Test]
+ public void RemoveInterval()
+ {
+ dit.RemoveInterval(0, 0);
+ dit.Add(10); dit.Add(20); dit.Add(30); dit.Add(40); dit.Add(50); dit.Add(60);
+ dit.RemoveInterval(3, 0);
+ Assert.IsTrue(((LinkedList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 10, 20, 30, 40, 50, 60));
+ dit.RemoveInterval(3, 1);
+ Assert.IsTrue(((LinkedList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 10, 20, 30, 50, 60));
+ dit.RemoveInterval(1, 3);
+ Assert.IsTrue(((LinkedList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 10, 60));
+ dit.RemoveInterval(0, 2);
+ Assert.IsTrue(((LinkedList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit));
+ dit.Add(10); dit.Add(20); dit.Add(30); dit.Add(40); dit.Add(50); dit.Add(60);
+ dit.RemoveInterval(0, 2);
+ Assert.IsTrue(((LinkedList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 30, 40, 50, 60));
+ dit.RemoveInterval(2, 2);
+ Assert.IsTrue(((LinkedList<int>)dit).Check());
+ Assert.IsTrue(IC.eq(dit, 30, 40));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = null;
+ }
+ }
+ }
+
+
+
+
+ namespace IList_
+ {
+ [TestFixture]
+ public class Searching
+ {
+ private IList<int> lst;
+
+
+ [SetUp]
+ public void Init() { lst = new LinkedList<int>(); }
+
+
+ [TearDown]
+ public void Dispose() { lst = null; }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void FirstBad()
+ {
+ int f = lst.First;
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void LastBad()
+ {
+ int f = lst.Last;
+ }
+
+
+ [Test]
+ public void FirstLast()
+ {
+ lst.Add(19);
+ Assert.AreEqual(19, lst.First);
+ Assert.AreEqual(19, lst.Last);
+ lst.Add(34); lst.InsertFirst(12);
+ Assert.AreEqual(12, lst.First);
+ Assert.AreEqual(34, lst.Last);
+ }
+
+
+ [Test]
+ public void This()
+ {
+ lst.Add(34);
+ Assert.AreEqual(34, lst[0]);
+ lst[0] = 56;
+ Assert.AreEqual(56, lst.First);
+ lst.Add(7); lst.Add(7); lst.Add(7); lst.Add(7);
+ lst[0] = 45; lst[2] = 78; lst[4] = 101;
+ Assert.IsTrue(IC.eq(lst, 45, 7, 78, 7, 101));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void ThisBadEmptyGet()
+ {
+ int f = lst[0];
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void ThisBadLowGet()
+ {
+ lst.Add(7);
+
+ int f = lst[-1];
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void ThisBadHiGet()
+ {
+ lst.Add(6);
+
+ int f = lst[1];
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void ThisBadEmptySet()
+ {
+ lst[0] = 4;
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void ThisBadLowSet()
+ {
+ lst.Add(7);
+ lst[-1] = 9;
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void ThisBadHiSet()
+ {
+ lst.Add(6);
+ lst[1] = 11;
+ }
+ }
+
+
+ [TestFixture]
+ public class Combined
+ {
+ private IList<KeyValuePair<int, int>> lst;
+
+
+ [SetUp]
+ public void Init()
+ {
+ lst = new LinkedList<KeyValuePair<int, int>>(new KeyValuePairEqualityComparer<int, int>());
+ for (int i = 0; i < 10; i++)
+ lst.Add(new KeyValuePair<int, int>(i, i + 30));
+ }
+
+
+ [TearDown]
+ public void Dispose() { lst = null; }
+
+
+ [Test]
+ public void Find()
+ {
+ KeyValuePair<int, int> p = new KeyValuePair<int, int>(3, 78);
+
+ Assert.IsTrue(lst.Find(ref p));
+ Assert.AreEqual(3, p.Key);
+ Assert.AreEqual(33, p.Value);
+ p = new KeyValuePair<int, int>(13, 78);
+ Assert.IsFalse(lst.Find(ref p));
+ }
+
+
+ [Test]
+ public void FindOrAdd()
+ {
+ KeyValuePair<int, int> p = new KeyValuePair<int, int>(3, 78);
+
+ Assert.IsTrue(lst.FindOrAdd(ref p));
+ Assert.AreEqual(3, p.Key);
+ Assert.AreEqual(33, p.Value);
+ p = new KeyValuePair<int, int>(13, 79);
+ Assert.IsFalse(lst.FindOrAdd(ref p));
+ Assert.AreEqual(13, lst[10].Key);
+ Assert.AreEqual(79, lst[10].Value);
+ }
+
+
+ [Test]
+ public void Update()
+ {
+ KeyValuePair<int, int> p = new KeyValuePair<int, int>(3, 78);
+
+ Assert.IsTrue(lst.Update(p));
+ Assert.AreEqual(3, lst[3].Key);
+ Assert.AreEqual(78, lst[3].Value);
+ p = new KeyValuePair<int, int>(13, 78);
+ Assert.IsFalse(lst.Update(p));
+ }
+
+
+ [Test]
+ public void UpdateOrAdd()
+ {
+ KeyValuePair<int, int> p = new KeyValuePair<int, int>(3, 78);
+
+ Assert.IsTrue(lst.UpdateOrAdd(p));
+ Assert.AreEqual(3, lst[3].Key);
+ Assert.AreEqual(78, lst[3].Value);
+ p = new KeyValuePair<int, int>(13, 79);
+ Assert.IsFalse(lst.UpdateOrAdd(p));
+ Assert.AreEqual(13, lst[10].Key);
+ Assert.AreEqual(79, lst[10].Value);
+ }
+
+
+ [Test]
+ public void RemoveWithReturn()
+ {
+ KeyValuePair<int, int> p = new KeyValuePair<int, int>(3, 78);
+
+ Assert.IsTrue(lst.Remove(p, out p));
+ Assert.AreEqual(3, p.Key);
+ Assert.AreEqual(33, p.Value);
+ Assert.AreEqual(4, lst[3].Key);
+ Assert.AreEqual(34, lst[3].Value);
+ p = new KeyValuePair<int, int>(13, 78);
+ Assert.IsFalse(lst.Remove(p, out p));
+ }
+ }
+
+
+ [TestFixture]
+ public class Inserting
+ {
+ private IList<int> lst;
+
+
+ [SetUp]
+ public void Init() { lst = new LinkedList<int>(); }
+
+
+ [TearDown]
+ public void Dispose() { lst = null; }
+
+
+ [Test]
+ public void Insert()
+ {
+ lst.Insert(0, 5);
+ Assert.IsTrue(IC.eq(lst, 5));
+ lst.Insert(0, 7);
+ Assert.IsTrue(IC.eq(lst, 7, 5));
+ lst.Insert(1, 4);
+ Assert.IsTrue(IC.eq(lst, 7, 4, 5));
+ lst.Insert(3, 2);
+ Assert.IsTrue(IC.eq(lst, 7, 4, 5, 2));
+ }
+
+ [Test]
+ public void InsertDuplicate()
+ {
+ lst.Insert(0, 5);
+ Assert.IsTrue(IC.eq(lst, 5));
+ lst.Insert(0, 7);
+ Assert.IsTrue(IC.eq(lst, 7, 5));
+ lst.Insert(1, 5);
+ Assert.IsTrue(IC.eq(lst, 7, 5, 5));
+ }
+
+ [Test]
+ public void InsertAllDuplicate1()
+ {
+ lst.Insert(0, 3);
+ Assert.IsTrue(IC.eq(lst, 3));
+ lst.Insert(0, 7);
+ Assert.IsTrue(IC.eq(lst, 7, 3));
+ lst.InsertAll<int>(1, new int[] { 1, 2, 3, 4 });
+ Assert.IsTrue(IC.eq(lst, 7, 1, 2, 3, 4, 3));
+ Assert.IsTrue(lst.Check());
+ }
+ [Test]
+ public void InsertAllDuplicate2()
+ {
+ lst.Insert(0, 3);
+ Assert.IsTrue(IC.eq(lst, 3));
+ lst.Insert(0, 7);
+ Assert.IsTrue(IC.eq(lst, 7, 3));
+ lst.InsertAll<int>(1, new int[] { 5, 6, 5, 8 });
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 5, 6, 5, 8, 3));
+ }
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void BadInsertLow()
+ {
+ lst.Add(7);
+ lst.Insert(-1, 9);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void BadInsertHi()
+ {
+ lst.Add(6);
+ lst.Insert(2, 11);
+ }
+
+
+ [Test]
+ public void FIFO()
+ {
+ for (int i = 0; i < 7; i++)
+ lst.Add(2 * i);
+
+ Assert.IsTrue(lst.FIFO);
+ Assert.AreEqual(0, lst.Remove());
+ Assert.AreEqual(2, lst.Remove());
+ lst.FIFO = false;
+ Assert.AreEqual(12, lst.Remove());
+ Assert.AreEqual(10, lst.Remove());
+ lst.FIFO = true;
+ Assert.AreEqual(4, lst.Remove());
+ Assert.AreEqual(6, lst.Remove());
+ }
+
+
+ [Test]
+ public void InsertFirstLast()
+ {
+ lst.InsertFirst(4);
+ lst.InsertLast(5);
+ lst.InsertFirst(14);
+ lst.InsertLast(15);
+ lst.InsertFirst(24);
+ lst.InsertLast(25);
+ lst.InsertFirst(34);
+ lst.InsertLast(55);
+ Assert.IsTrue(IC.eq(lst, 34, 24, 14, 4, 5, 15, 25, 55));
+ }
+
+
+ [Test]
+ public void InsertFirst()
+ {
+ lst.Add(2);
+ lst.Add(3);
+ lst.Add(2);
+ lst.Add(5);
+ lst.ViewOf(2).InsertFirst(7);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 2, 3, 2, 5));
+ lst.ViewOf(3).InsertFirst(8);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 2, 8, 3, 2, 5));
+ lst.ViewOf(5).InsertFirst(9);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 2, 8, 3, 2, 9, 5));
+ }
+
+
+ [Test]
+ public void BadInsertFirst()
+ {
+ lst.Add(2);
+ lst.Add(3);
+ lst.Add(2);
+ lst.Add(5);
+ Assert.IsNull(lst.ViewOf(4));
+ }
+
+
+ [Test]
+ public void InsertAfter()
+ {
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ lst.Add(2);
+ lst.Add(5);
+ lst.LastViewOf(2).InsertLast(7);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 1, 2, 3, 2, 7, 5));
+ lst.LastViewOf(1).InsertLast(8);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 1, 8, 2, 3, 2, 7, 5));
+ lst.LastViewOf(5).InsertLast(9);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 1, 8, 2, 3, 2, 7, 5, 9));
+ }
+
+
+ [Test]
+ public void BadInsertAfter()
+ {
+ lst.Add(2);
+ lst.Add(3);
+ lst.Add(2);
+ lst.Add(5);
+ Assert.IsNull(lst.ViewOf(4));
+ }
+
+
+ [Test]
+ public void InsertAll()
+ {
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ lst.Add(4);
+
+ IList<int> lst2 = new LinkedList<int>();
+
+ lst2.Add(7); lst2.Add(8); lst2.Add(9);
+ lst.InsertAll(0, lst2);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 8, 9, 1, 2, 3, 4));
+ lst.InsertAll(7, lst2);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 8, 9, 1, 2, 3, 4, 7, 8, 9));
+ lst.InsertAll(5, lst2);
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 8, 9, 1, 2, 7, 8, 9, 3, 4, 7, 8, 9));
+ }
+
+
+ [Test]
+ public void Map()
+ {
+ Fun<int, string> m = delegate(int i) { return "<<" + i + ">>"; };
+ IList<string> r = lst.Map(m);
+
+ Assert.IsTrue(r.Check());
+ Assert.IsTrue(r.IsEmpty);
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ lst.Add(4);
+ r = lst.Map(m);
+ Assert.IsTrue(r.Check());
+ Assert.AreEqual(4, r.Count);
+ for (int i = 0; i < 4; i++)
+ Assert.AreEqual("<<" + (i + 1) + ">>", r[i]);
+ }
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void BadMapper()
+ {
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ Fun<int, bool> m = delegate(int i) { if (i == 2) lst.Add(7); return true; };
+ lst.Map(m);
+ }
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void ModifyingFindAll()
+ {
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ Fun<int, bool> m = delegate(int i) { if (i == 2) lst.Add(7); return true; };
+ lst.FindAll(m);
+ }
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void BadMapperView()
+ {
+ lst = lst.View(0, 0);
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ Fun<int, bool> m = delegate(int i) { if (i == 2) lst.Add(7); return true; };
+ lst.Map(m);
+ }
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void ModifyingFindAllView()
+ {
+ lst = lst.View(0, 0);
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ Fun<int, bool> m = delegate(int i) { if (i == 2) lst.Add(7); return true; };
+ lst.FindAll(m);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void BadRemove() { lst.Remove(); }
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void BadRemoveFirst() { lst.RemoveFirst(); }
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void BadRemoveLast() { lst.RemoveLast(); }
+
+
+ [Test]
+ public void RemoveFirstLast()
+ {
+ lst.Add(1);
+ lst.Add(2);
+ lst.Add(3);
+ lst.Add(4);
+ Assert.AreEqual(1, lst.RemoveFirst());
+ Assert.AreEqual(4, lst.RemoveLast());
+ Assert.AreEqual(2, lst.RemoveFirst());
+ Assert.AreEqual(3, lst.RemoveLast());
+ Assert.IsTrue(lst.IsEmpty);
+ }
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void RemoveFirstEmpty()
+ {
+ lst.RemoveFirst();
+ }
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void RemoveLastEmpty()
+ {
+ lst.RemoveLast();
+ }
+
+ [Test]
+ public void Reverse()
+ {
+ for (int i = 0; i < 10; i++)
+ lst.Add(i);
+
+ lst.Reverse();
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0));
+ lst.View(0, 3).Reverse();
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 8, 9, 6, 5, 4, 3, 2, 1, 0));
+ lst.View(7, 0).Reverse();
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 8, 9, 6, 5, 4, 3, 2, 1, 0));
+ lst.View(7, 3).Reverse();
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 8, 9, 6, 5, 4, 3, 0, 1, 2));
+ lst.View(5, 1).Reverse();
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(IC.eq(lst, 7, 8, 9, 6, 5, 4, 3, 0, 1, 2));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void BadReverse()
+ {
+ for (int i = 0; i < 10; i++)
+ lst.Add(i);
+
+ lst.View(8, 3).Reverse();
+ }
+ }
+
+
+
+ [TestFixture]
+ public class SortingTests
+ {
+ private IList<int> lst;
+
+
+ [SetUp]
+ public void Init() { lst = new LinkedList<int>(); }
+
+
+ [TearDown]
+ public void Dispose() { lst = null; }
+
+
+ [Test]
+ public void Sort()
+ {
+ lst.Add(5); lst.Add(6); lst.Add(5); lst.Add(7); lst.Add(3);
+ Assert.IsFalse(lst.IsSorted(new IC()));
+ lst.Sort(new IC());
+ Assert.IsTrue(lst.Check());
+ Assert.IsTrue(lst.IsSorted());
+ Assert.IsTrue(lst.IsSorted(new IC()));
+ Assert.IsTrue(IC.eq(lst, 3, 5, 5, 6, 7));
+ }
+
+
+ [Test]
+ public void Stability()
+ {
+ IList<KeyValuePair<int, string>> lst2 = new LinkedList<KeyValuePair<int, string>>();
+ SCG.IComparer<KeyValuePair<int, string>> c = new KeyValuePairComparer<int, string>(new IC());
+
+ lst2.Add(new KeyValuePair<int, string>(5, "a"));
+ lst2.Add(new KeyValuePair<int, string>(5, "b"));
+ lst2.Add(new KeyValuePair<int, string>(6, "c"));
+ lst2.Add(new KeyValuePair<int, string>(4, "d"));
+ lst2.Add(new KeyValuePair<int, string>(3, "e"));
+ lst2.Add(new KeyValuePair<int, string>(4, "f"));
+ lst2.Add(new KeyValuePair<int, string>(5, "handle"));
+ Assert.IsFalse(lst2.IsSorted(c));
+ lst2.Sort(c);
+ Assert.IsTrue(lst2.IsSorted(c));
+
+ KeyValuePair<int, string> p = lst2.RemoveFirst();
+
+ Assert.AreEqual(3, p.Key);
+ Assert.AreEqual("e", p.Value);
+ p = lst2.RemoveFirst();
+ Assert.AreEqual(4, p.Key);
+ Assert.AreEqual("d", p.Value);
+ p = lst2.RemoveFirst();
+ Assert.AreEqual(4, p.Key);
+ Assert.AreEqual("f", p.Value);
+ p = lst2.RemoveFirst();
+ Assert.AreEqual(5, p.Key);
+ Assert.AreEqual("a", p.Value);
+ p = lst2.RemoveFirst();
+ Assert.AreEqual(5, p.Key);
+ Assert.AreEqual("b", p.Value);
+ p = lst2.RemoveFirst();
+ Assert.AreEqual(5, p.Key);
+ Assert.AreEqual("handle", p.Value);
+ p = lst2.RemoveFirst();
+ Assert.AreEqual(6, p.Key);
+ Assert.AreEqual("c", p.Value);
+ Assert.IsTrue(lst2.IsEmpty);
+ }
+ }
+ [TestFixture]
+ public class ShuffleTests
+ {
+ private IList<int> lst;
+
+
+ [SetUp]
+ public void Init() { lst = new LinkedList<int>(); }
+
+
+ [TearDown]
+ public void Dispose() { lst = null; }
+
+
+ [Test]
+ public void Shuffle()
+ {
+ lst.Add(5); lst.Add(6); lst.Add(5); lst.Add(7); lst.Add(3);
+ for (int i = 0; i < 100; i++)
+ {
+ lst.Shuffle(new C5Random(i + 1));
+ Assert.IsTrue(lst.Check(), "Check " + i);
+ int[] lst2 = lst.ToArray();
+ Sorting.IntroSort<int>(lst2);
+ Assert.IsTrue(IC.eq(lst2, 3, 5, 5, 6, 7), "Contents " + i);
+ }
+ }
+ }
+ }
+
+
+ namespace IStackQueue
+ {
+ [TestFixture]
+ public class Stack
+ {
+ private IStack<int> list;
+
+
+ [SetUp]
+ public void Init() { list = new LinkedList<int>(); }
+
+
+ [Test]
+ public void Normal()
+ {
+ list.Push(7);
+ list.Push(5);
+ list.Push(7);
+ list.Push(8);
+ list.Push(9);
+ Assert.AreEqual(9, list.Pop());
+ Assert.AreEqual(8, list.Pop());
+ Assert.AreEqual(7, list.Pop());
+ Assert.AreEqual(5, list.Pop());
+ Assert.AreEqual(7, list.Pop());
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void PopEmpty()
+ {
+ list.Push(5);
+ Assert.AreEqual(5, list.Pop());
+ list.Pop();
+ }
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+ }
+ [TestFixture]
+ public class Queue
+ {
+ private IQueue<int> list;
+
+
+ [SetUp]
+ public void Init() { list = new LinkedList<int>(); }
+
+
+ [Test]
+ public void Normal()
+ {
+ list.Enqueue(7);
+ list.Enqueue(5);
+ list.Enqueue(7);
+ list.Enqueue(8);
+ list.Enqueue(9);
+ Assert.AreEqual(7, list.Dequeue());
+ Assert.AreEqual(5, list.Dequeue());
+ Assert.AreEqual(7, list.Dequeue());
+ Assert.AreEqual(8, list.Dequeue());
+ Assert.AreEqual(9, list.Dequeue());
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void DeQueueEmpty()
+ {
+ list.Enqueue(5);
+ Assert.AreEqual(5, list.Dequeue());
+ list.Dequeue();
+ }
+
+
+ [TearDown]
+ public void Dispose() { list = null; }
+ }
+ }
+
+
+ namespace Range
+ {
+ [TestFixture]
+ public class Range
+ {
+ private IList<int> lst;
+
+
+ [SetUp]
+ public void Init() { lst = new LinkedList<int>(); }
+
+
+ [TearDown]
+ public void Dispose() { lst = null; }
+
+
+ [Test]
+ public void GetRange()
+ {
+ //Assert.IsTrue(IC.eq(lst[0, 0)));
+ for (int i = 0; i < 10; i++) lst.Add(i);
+
+ Assert.IsTrue(IC.eq(lst[0, 3], 0, 1, 2));
+ Assert.IsTrue(IC.eq(lst[3, 4], 3, 4, 5, 6));
+ Assert.IsTrue(IC.eq(lst[6, 4], 6, 7, 8, 9));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void BadGetRange()
+ {
+ object foo = lst[0, 11];
+ }
+
+
+ [Test]
+ public void Backwards()
+ {
+ for (int i = 0; i < 10; i++) lst.Add(i);
+
+ Assert.IsTrue(IC.eq(lst.Backwards(), 9, 8, 7, 6, 5, 4, 3, 2, 1, 0));
+ Assert.IsTrue(IC.eq(lst[0, 4].Backwards(), 3, 2, 1, 0));
+ Assert.IsTrue(IC.eq(lst[3, 4].Backwards(), 6, 5, 4, 3));
+ Assert.IsTrue(IC.eq(lst[6, 4].Backwards(), 9, 8, 7, 6));
+ }
+
+
+ [Test]
+ public void DirectionAndCount()
+ {
+ for (int i = 0; i < 10; i++) lst.Add(i);
+
+ Assert.AreEqual(EnumerationDirection.Forwards, lst.Direction);
+ Assert.AreEqual(EnumerationDirection.Forwards, lst[3, 7].Direction);
+ Assert.AreEqual(EnumerationDirection.Backwards, lst[3, 7].Backwards().Direction);
+ Assert.AreEqual(EnumerationDirection.Backwards, lst.Backwards().Direction);
+ Assert.AreEqual(4, lst[3, 4].Count);
+ Assert.AreEqual(4, lst[3, 4].Backwards().Count);
+ Assert.AreEqual(10, lst.Backwards().Count);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void MoveNextAfterUpdate()
+ {
+ for (int i = 0; i < 10; i++) lst.Add(i);
+
+ foreach (int i in lst)
+ {
+ lst.Add(45 + i);
+ }
+ }
+ }
+ }
+
+
+
+
+ namespace View
+ {
+ [TestFixture]
+ public class Simple
+ {
+ LinkedList<int> list, view;
+
+
+ [SetUp]
+ public void Init()
+ {
+ list = new LinkedList<int>();
+ list.Add(0); list.Add(1); list.Add(2); list.Add(3);
+ view = (LinkedList<int>)list.View(1, 2);
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ list = view = null;
+ }
+
+
+ void check()
+ {
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(view.Check());
+ }
+
+
+ [Test]
+ public void InsertPointer()
+ {
+ IList<int> view2 = list.View(2, 0);
+ list.Insert(view2, 7);
+ check();
+ list.Insert(list, 8);
+ check();
+ view.Insert(view2, 9);
+ check();
+ view.Insert(list.View(3, 2), 10);
+ check();
+ view.Insert(list.ViewOf(0), 11);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 11, 1, 9, 7, 2, 10, 3, 8));
+ Assert.IsTrue(IC.eq(view, 11, 1, 9, 7, 2, 10));
+ }
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void InsertPointerBad1()
+ {
+ view.Insert(list.View(0, 0), 7);
+ }
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void InsertPointerBad2()
+ {
+ view.Insert(list, 7);
+ }
+
+ [Test]
+ [ExpectedException(typeof(IncompatibleViewException))]
+ public void InsertPointerBad3()
+ {
+ list.Insert(new ArrayList<int>(), 7);
+ }
+
+ [Test]
+ [ExpectedException(typeof(IncompatibleViewException))]
+ public void InsertPointerBad4()
+ {
+ list.Insert(new ArrayList<int>().View(0, 0), 7);
+ }
+
+ [Test]
+ public void Span()
+ {
+ IList<int> span = list.View(1, 0).Span(list.View(2, 0));
+ Assert.IsTrue(span.Check());
+ Assert.AreEqual(1, span.Offset);
+ Assert.AreEqual(1, span.Count);
+ span = list.View(0, 2).Span(list.View(2, 2));
+ Assert.IsTrue(span.Check());
+ Assert.AreEqual(0, span.Offset);
+ Assert.AreEqual(4, span.Count);
+ span = list.View(3, 1).Span(list.View(1, 1));
+ Assert.IsNull(span);
+ }
+
+ [Test]
+ public void ViewOf()
+ {
+ for (int i = 0; i < 4; i++)
+ list.Add(i);
+ IList<int> v = view.ViewOf(2);
+ Assert.IsTrue(v.Check());
+ Assert.IsTrue(IC.eq(v, 2));
+ Assert.AreEqual(2, v.Offset);
+ v = list.ViewOf(2);
+ Assert.IsTrue(v.Check());
+ Assert.IsTrue(IC.eq(v, 2));
+ Assert.AreEqual(2, v.Offset);
+ v = list.LastViewOf(2);
+ Assert.IsTrue(v.Check());
+ Assert.IsTrue(IC.eq(v, 2));
+ Assert.AreEqual(6, v.Offset);
+ }
+
+ [Test]
+ public void BadViewOf()
+ {
+ Assert.IsNull(view.ViewOf(5));
+ Assert.IsNull(view.LastViewOf(5));
+ Assert.IsNull(view.ViewOf(3));
+ Assert.IsNull(view.LastViewOf(3));
+ Assert.IsNull(view.ViewOf(0));
+ Assert.IsNull(view.LastViewOf(0));
+ }
+
+ [Test]
+ public void ArrayStuff()
+ {
+ Assert.IsTrue(IC.eq(view.ToArray(), 1, 2));
+ int[] extarray = new int[5];
+ view.CopyTo(extarray, 2);
+ Assert.IsTrue(IC.eq(extarray, 0, 0, 1, 2, 0));
+ }
+
+
+ [Test]
+ public void Add()
+ {
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 1, 2, 3));
+ Assert.IsTrue(IC.eq(view, 1, 2));
+ view.InsertFirst(10);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 10, 1, 2, 3));
+ Assert.IsTrue(IC.eq(view, 10, 1, 2));
+ view.Clear();
+ Assert.IsFalse(view.IsReadOnly);
+ Assert.IsTrue(view.AllowsDuplicates);
+ Assert.IsTrue(view.IsEmpty);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 3));
+ Assert.IsTrue(IC.eq(view));
+ view.Add(8);
+ Assert.IsFalse(view.IsEmpty);
+ Assert.IsTrue(view.AllowsDuplicates);
+ Assert.IsFalse(view.IsReadOnly);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 8, 3));
+ Assert.IsTrue(IC.eq(view, 8));
+ view.Add(12);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 8, 12, 3));
+ Assert.IsTrue(IC.eq(view, 8, 12));
+ view./*ViewOf(12).*/InsertLast(15);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 8, 12, 15, 3));
+ Assert.IsTrue(IC.eq(view, 8, 12, 15));
+ view.ViewOf(12).InsertFirst(18);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 8, 18, 12, 15, 3));
+ Assert.IsTrue(IC.eq(view, 8, 18, 12, 15));
+
+ LinkedList<int> lst2 = new LinkedList<int>();
+
+ lst2.Add(90); lst2.Add(92);
+ view.AddAll(lst2);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 8, 18, 12, 15, 90, 92, 3));
+ Assert.IsTrue(IC.eq(view, 8, 18, 12, 15, 90, 92));
+ view.InsertLast(66);
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 8, 18, 12, 15, 90, 92, 66, 3));
+ Assert.IsTrue(IC.eq(view, 8, 18, 12, 15, 90, 92, 66));
+ }
+
+
+ [Test]
+ public void Bxxx()
+ {
+ Assert.IsTrue(IC.eq(view.Backwards(), 2, 1));
+ Assert.AreSame(list, view.Underlying);
+ Assert.IsNull(list.Underlying);
+ Assert.AreEqual(EnumerationDirection.Forwards, view.Direction);
+ Assert.AreEqual(EnumerationDirection.Backwards, view.Backwards().Direction);
+ Assert.AreEqual(0, list.Offset);
+ Assert.AreEqual(1, view.Offset);
+ }
+
+
+ [Test]
+ public void Contains()
+ {
+ Assert.IsTrue(view.Contains(1));
+ Assert.IsFalse(view.Contains(0));
+
+ LinkedList<int> lst2 = new LinkedList<int>();
+
+ lst2.Add(2);
+ Assert.IsTrue(view.ContainsAll(lst2));
+ lst2.Add(3);
+ Assert.IsFalse(view.ContainsAll(lst2));
+ Assert.AreEqual(Speed.Linear, view.ContainsSpeed);
+ Assert.AreEqual(2, view.Count);
+ view.Add(1);
+ Assert.AreEqual(1, view.ContainsCount(2));
+ Assert.AreEqual(2, view.ContainsCount(1));
+ Assert.AreEqual(3, view.Count);
+ }
+
+
+ [Test]
+ public void CreateView()
+ {
+ LinkedList<int> view2 = (LinkedList<int>)view.View(1, 0);
+
+ Assert.AreSame(list, view2.Underlying);
+ }
+
+
+ [Test]
+ public void FIFO()
+ {
+ Assert.IsTrue(view.FIFO);
+ view.Add(23); view.Add(24); view.Add(25);
+ check();
+ Assert.IsTrue(IC.eq(view, 1, 2, 23, 24, 25));
+ Assert.AreEqual(1, view.Remove());
+ check();
+ Assert.IsTrue(IC.eq(view, 2, 23, 24, 25));
+ view.FIFO = false;
+ Assert.IsFalse(view.FIFO);
+ Assert.AreEqual(25, view.Remove());
+ check();
+ Assert.IsTrue(IC.eq(view, 2, 23, 24));
+ }
+
+
+ [Test]
+ public void MapEtc()
+ {
+ LinkedList<double> dbl = (LinkedList<double>)view.Map(new Fun<int, double>(delegate(int i) { return i / 10.0; }));
+
+ Assert.IsTrue(dbl.Check());
+ Assert.AreEqual(0.1, dbl[0]);
+ Assert.AreEqual(0.2, dbl[1]);
+ for (int i = 0; i < 10; i++) view.Add(i);
+
+ list = (LinkedList<int>)view.FindAll(new Fun<int, bool>(delegate(int i) { return i % 4 == 1; }));
+ Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 1, 1, 5, 9));
+ }
+
+
+ [Test]
+ public void FL()
+ {
+ Assert.AreEqual(1, view.First);
+ Assert.AreEqual(2, view.Last);
+ }
+
+
+ [Test]
+ public void Indexing()
+ {
+ list.Clear();
+ for (int i = 0; i < 20; i++) list.Add(i);
+
+ view = (LinkedList<int>)list.View(5, 7);
+ for (int i = 0; i < 7; i++) Assert.AreEqual(i + 5, view[i]);
+
+ for (int i = 0; i < 7; i++) Assert.AreEqual(i, view.IndexOf(i + 5));
+
+ for (int i = 0; i < 7; i++) Assert.AreEqual(i, view.LastIndexOf(i + 5));
+ }
+
+
+ [Test]
+ public void INsert()
+ {
+ view.Insert(0, 34);
+ view.Insert(1, 35);
+ view.Insert(4, 36);
+ Assert.IsTrue(view.Check());
+ Assert.IsTrue(IC.eq(view, 34, 35, 1, 2, 36));
+
+ IList<int> list2 = new LinkedList<int>();
+
+ list2.AddAll(view);
+ view.InsertAll(3, list2);
+ Assert.IsTrue(view.Check());
+ Assert.IsTrue(IC.eq(view, 34, 35, 1, 34, 35, 1, 2, 36, 2, 36));
+ }
+
+
+ [Test]
+ public void Sort()
+ {
+ view.Add(45); view.Add(47); view.Add(46); view.Add(48);
+ Assert.IsFalse(view.IsSorted(new IC()));
+ view.Sort(new IC());
+ check();
+ Assert.IsTrue(IC.eq(list, 0, 1, 2, 45, 46, 47, 48, 3));
+ Assert.IsTrue(IC.eq(view, 1, 2, 45, 46, 47, 48));
+ }
+
+
+ [Test]
+ public void Remove()
+ {
+ view.FIFO = false;
+ view.Add(1); view.Add(5); view.Add(3); view.Add(1); view.Add(3); view.Add(0);
+ Assert.IsTrue(IC.eq(view, 1, 2, 1, 5, 3, 1, 3, 0));
+ Assert.IsTrue(view.Remove(1));
+ check();
+ Assert.IsTrue(IC.eq(view, 1, 2, 1, 5, 3, 3, 0));
+ Assert.IsTrue(view.Remove(1));
+ check();
+ Assert.IsTrue(IC.eq(view, 1, 2, 5, 3, 3, 0));
+ Assert.IsTrue(view.Remove(0));
+ check();
+ Assert.IsTrue(IC.eq(view, 1, 2, 5, 3, 3));
+ view.RemoveAllCopies(3);
+ check();
+ Assert.IsTrue(IC.eq(view, 1, 2, 5));
+ Assert.IsTrue(IC.eq(list, 0, 1, 2, 5, 3));
+ view.Add(1); view.Add(5); view.Add(3); view.Add(1); view.Add(3); view.Add(0);
+ Assert.IsTrue(IC.eq(view, 1, 2, 5, 1, 5, 3, 1, 3, 0));
+
+ view.FIFO = true;
+ view.Clear(); view.Add(1); view.Add(2);
+
+ view.Add(1); view.Add(5); view.Add(3); view.Add(1); view.Add(3); view.Add(0);
+ Assert.IsTrue(IC.eq(view, 1, 2, 1, 5, 3, 1, 3, 0));
+ Assert.IsTrue(view.Remove(1));
+ check();
+ Assert.IsTrue(IC.eq(view, 2, 1, 5, 3, 1, 3, 0));
+ Assert.IsTrue(view.Remove(1));
+ check();
+ Assert.IsTrue(IC.eq(view, 2, 5, 3, 1, 3, 0));
+ Assert.IsTrue(view.Remove(0));
+ check();
+ Assert.IsTrue(IC.eq(view, 2, 5, 3, 1, 3));
+ view.RemoveAllCopies(3);
+ check();
+ Assert.IsTrue(IC.eq(view, 2, 5, 1));
+ Assert.IsTrue(IC.eq(list, 0, 2, 5, 1, 3));
+ view.Add(1); view.Add(5); view.Add(3); view.Add(1); view.Add(3); view.Add(0);
+ Assert.IsTrue(IC.eq(view, 2, 5, 1, 1, 5, 3, 1, 3, 0));
+
+ LinkedList<int> l2 = new LinkedList<int>();
+
+ l2.Add(1); l2.Add(2); l2.Add(2); l2.Add(3); l2.Add(1);
+ view.RemoveAll(l2);
+ check();
+ Assert.IsTrue(IC.eq(view, 5, 5, 1, 3, 0));
+ view.RetainAll(l2);
+ check();
+ Assert.IsTrue(IC.eq(view, 1, 3));
+ view.Add(2); view.Add(4); view.Add(5);
+ Assert.AreEqual(1, view.RemoveAt(0));
+ Assert.AreEqual(5, view.RemoveAt(3));
+ Assert.AreEqual(2, view.RemoveAt(1));
+ check();
+ Assert.IsTrue(IC.eq(view, 3, 4));
+ view.Add(8);
+ Assert.AreEqual(3, view.RemoveFirst());
+ Assert.AreEqual(8, view.RemoveLast());
+ view.Add(2); view.Add(5); view.Add(3); view.Add(1);
+ view.RemoveInterval(1, 2);
+ check();
+ Assert.IsTrue(IC.eq(view, 4, 3, 1));
+ }
+
+
+ [Test]
+ public void Reverse()
+ {
+ view.Clear();
+ for (int i = 0; i < 10; i++) view.Add(10 + i);
+
+ view.View(3, 4).Reverse();
+ check();
+ Assert.IsTrue(IC.eq(view, 10, 11, 12, 16, 15, 14, 13, 17, 18, 19));
+ view.Reverse();
+ Assert.IsTrue(IC.eq(view, 19, 18, 17, 13, 14, 15, 16, 12, 11, 10));
+ Assert.IsTrue(IC.eq(list, 0, 19, 18, 17, 13, 14, 15, 16, 12, 11, 10, 3));
+ }
+
+
+ [Test]
+ public void Slide()
+ {
+ view.Slide(1);
+ check();
+ Assert.IsTrue(IC.eq(view, 2, 3));
+ view.Slide(-2);
+ check();
+ Assert.IsTrue(IC.eq(view, 0, 1));
+ view.Slide(0, 3);
+ check();
+ Assert.IsTrue(IC.eq(view, 0, 1, 2));
+ view.Slide(2, 1);
+ check();
+ Assert.IsTrue(IC.eq(view, 2));
+ Assert.AreEqual(view, view.Slide(-1, 0));
+ check();
+ Assert.IsTrue(IC.eq(view));
+ view.Add(28);
+ Assert.IsTrue(IC.eq(list, 0, 28, 1, 2, 3));
+ }
+ [Test]
+ public void Iterate()
+ {
+ list.Clear();
+ view = null;
+ foreach (int i in new int[] { 2, 4, 8, 13, 6, 1, 2, 7 }) list.Add(i);
+
+ view = (LinkedList<int>)list.View(list.Count - 2, 2);
+ while (true)
+ {
+ //Console.WriteLine("View: {0}: {1} --> {2}", view.Count, view.First, view.Last);
+ if ((view.Last - view.First) % 2 == 1)
+ view.Insert(1, 666);
+ check();
+ if (view.Offset == 0)
+ break;
+ else
+ view.Slide(-1, 2);
+ }
+ //foreach (int cell in list) Console.Write(" " + cell);
+ //Assert.IsTrue(list.Check());
+ Assert.IsTrue(IC.eq(list, 2, 4, 8, 666, 13, 6, 1, 666, 2, 666, 7));
+ }
+
+
+ [Test]
+ public void SyncRoot()
+ {
+ Assert.AreSame(view.SyncRoot, list.SyncRoot);
+ }
+ }
+
+ [TestFixture]
+ public class MulipleViews
+ {
+ IList<int> list;
+ IList<int>[][] views;
+ [SetUp]
+ public void Init()
+ {
+ list = new LinkedList<int>();
+ for (int i = 0; i < 6; i++)
+ list.Add(i);
+ views = new IList<int>[7][];
+ for (int i = 0; i < 7; i++)
+ {
+ views[i] = new IList<int>[7 - i];
+ for (int j = 0; j < 7 - i; j++)
+ views[i][j] = list.View(i, j);
+ }
+ }
+ [TearDown]
+ public void Dispose()
+ {
+ list = null;
+ views = null;
+ }
+ [Test]
+ public void Insert()
+ {
+ Assert.IsTrue(list.Check(), "list check before insert");
+ list.Insert(3, 777);
+ Assert.IsTrue(list.Check(), "list check after insert");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i < 3 || (i == 3 && j == 0) ? i : i + 1, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(i < 3 && i + j > 3 ? j + 1 : j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+ [Test]
+ public void RemoveAt()
+ {
+ Assert.IsTrue(list.Check(), "list check before remove");
+ list.RemoveAt(3);
+ Assert.IsTrue(list.Check(), "list check after remove");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i <= 3 ? i : i - 1, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(i <= 3 && i + j > 3 ? j - 1 : j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+
+ [Test]
+ public void RemoveInterval()
+ {
+ Assert.IsTrue(list.Check(), "list check before remove");
+ list.RemoveInterval(3, 2);
+ Assert.IsTrue(list.Check(), "list check after remove");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i <= 3 ? i : i <= 5 ? 3 : i - 2, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(j == 0 ? 0 : i <= 3 && i + j > 4 ? j - 2 : i > 4 || i + j <= 3 ? j : j - 1, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+
+
+ [Test]
+ public void InsertAtEnd()
+ {
+ Assert.IsTrue(list.Check(), "list check before insert");
+ list.InsertLast(777);
+ Assert.IsTrue(list.Check(), "list check after insert");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+ [Test]
+ public void RemoveAtEnd()
+ {
+ Assert.IsTrue(list.Check(), "list check before remove");
+ list.RemoveAt(5);
+ Assert.IsTrue(list.Check(), "list check after remove");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i <= 5 ? i : i - 1, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(i <= 5 && i + j > 5 ? j - 1 : j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+ [Test]
+ public void InsertAtStart()
+ {
+ Assert.IsTrue(list.Check(), "list check before insert");
+ list.Insert(0, 777);
+ Assert.IsTrue(list.Check(), "list check after insert");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i == 0 && j == 0 ? 0 : i + 1, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+ [Test]
+ public void RemoveAtStart()
+ {
+ Assert.IsTrue(list.Check(), "list check before remove");
+ list.RemoveAt(0);
+ Assert.IsTrue(list.Check(), "list check after remove");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i == 0 ? i : i - 1, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(i == 0 && j > 0 ? j - 1 : j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+ [Test]
+ public void Clear()
+ {
+ Assert.IsTrue(list.Check(), "list check before clear");
+ views[2][3].Clear();
+ Assert.IsTrue(list.Check(), "list check after clear");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i < 2 ? i : i < 6 ? 2 : i - 3, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(s(i, j), views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+
+ private int s(int i, int j)
+ {
+ if (j == 0) return 0;
+ int k = i + j - 1; //end
+ if (i > 4 || k <= 1) return j;
+ if (i >= 2) return k > 4 ? k - 4 : 0;
+ if (i <= 2) return k >= 4 ? j - 3 : 2 - i;
+ return -1;
+ }
+ [Test]
+ public void InsertAll()
+ {
+ LinkedList<int> list2 = new LinkedList<int>();
+ for (int i = 0; i < 5; i++) { list2.Add(100 + i); }
+ Assert.IsTrue(list.Check(), "list check before insertAll");
+ list.InsertAll(3, list2);
+ Assert.IsTrue(list.Check(), "list check after insertAll");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i < 3 || (i == 3 && j == 0) ? i : i + 5, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(i < 3 && i + j > 3 ? j + 5 : j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+
+ [Test]
+ public void AddAll()
+ {
+ LinkedList<int> list2 = new LinkedList<int>();
+ for (int i = 0; i < 5; i++) { list2.Add(100 + i); }
+ Assert.IsTrue(list.Check(), "list check before AddAll");
+ list.View(1, 2).AddAll(list2);
+ Assert.IsTrue(list.Check(), "list check after AddAll");
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ Assert.AreEqual(i < 3 || (i == 3 && j == 0) ? i : i + 5, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ Assert.AreEqual(i < 3 && i + j > 3 ? j + 5 : j, views[i][j].Count, "view[" + i + "][" + j + "] count");
+ }
+ }
+
+ [Test]
+ public void RemoveAll1()
+ {
+ LinkedList<int> list2 = new LinkedList<int>();
+ list2.Add(1); list2.Add(3); list2.Add(4);
+
+ for (int i = 0; i < 7; i++)
+ {
+ for (int j = 0; j < 7 - i; j++)
+ {
+ list = new LinkedList<int>();
+ for (int k = 0; k < 6; k++) list.Add(k);
+ LinkedList<int> v = (LinkedList<int>)list.View(i, j);
+ list.RemoveAll(list2);
+ Assert.IsTrue(list.Check(), "list check after RemoveAll, i=" + i + ", j=" + j);
+ }
+ }
+ }
+ [Test]
+ public void RemoveAll2()
+ {
+ LinkedList<int> list2 = new LinkedList<int>();
+ list2.Add(1); list2.Add(3); list2.Add(4);
+ Assert.IsTrue(list.Check(), "list check before RemoveAll");
+ list.RemoveAll(list2);
+
+ Assert.AreEqual(0, views[0][0].Offset, "view [0][0] offset");
+ Assert.AreEqual(0, views[0][1].Offset, "view [0][1] offset");
+ Assert.AreEqual(0, views[0][2].Offset, "view [0][2] offset");
+ Assert.AreEqual(0, views[0][3].Offset, "view [0][3] offset");
+ Assert.AreEqual(0, views[0][4].Offset, "view [0][4] offset");
+ Assert.AreEqual(0, views[0][5].Offset, "view [0][5] offset");
+ Assert.AreEqual(0, views[0][6].Offset, "view [0][6] offset");
+ Assert.AreEqual(1, views[1][0].Offset, "view [1][0] offset");
+ Assert.AreEqual(1, views[1][1].Offset, "view [1][1] offset");
+ Assert.AreEqual(1, views[1][2].Offset, "view [1][2] offset");
+ Assert.AreEqual(1, views[1][3].Offset, "view [1][3] offset");
+ Assert.AreEqual(1, views[1][4].Offset, "view [1][4] offset");
+ Assert.AreEqual(1, views[1][5].Offset, "view [1][5] offset");
+ Assert.AreEqual(1, views[2][0].Offset, "view [2][0] offset");
+ Assert.AreEqual(1, views[2][1].Offset, "view [2][1] offset");
+ Assert.AreEqual(1, views[2][2].Offset, "view [2][2] offset");
+ Assert.AreEqual(1, views[2][3].Offset, "view [2][3] offset");
+ Assert.AreEqual(1, views[2][4].Offset, "view [2][4] offset");
+ Assert.AreEqual(2, views[3][0].Offset, "view [3][0] offset");
+ Assert.AreEqual(2, views[3][1].Offset, "view [3][1] offset");
+ Assert.AreEqual(2, views[3][2].Offset, "view [3][2] offset");
+ Assert.AreEqual(2, views[3][3].Offset, "view [3][3] offset");
+ Assert.AreEqual(2, views[4][0].Offset, "view [4][0] offset");
+ Assert.AreEqual(2, views[4][1].Offset, "view [4][1] offset");
+ Assert.AreEqual(2, views[4][2].Offset, "view [4][2] offset");
+ Assert.AreEqual(2, views[5][0].Offset, "view [5][0] offset");
+ Assert.AreEqual(2, views[5][1].Offset, "view [5][1] offset");
+ Assert.AreEqual(3, views[6][0].Offset, "view [6][0] offset");
+
+ Assert.AreEqual(0, views[0][0].Count, "view [0][0] count");
+ Assert.AreEqual(1, views[0][1].Count, "view [0][1] count");
+ Assert.AreEqual(1, views[0][2].Count, "view [0][2] count");
+ Assert.AreEqual(2, views[0][3].Count, "view [0][3] count");
+ Assert.AreEqual(2, views[0][4].Count, "view [0][4] count");
+ Assert.AreEqual(2, views[0][5].Count, "view [0][5] count");
+ Assert.AreEqual(3, views[0][6].Count, "view [0][6] count");
+ Assert.AreEqual(0, views[1][0].Count, "view [1][0] count");
+ Assert.AreEqual(0, views[1][1].Count, "view [1][1] count");
+ Assert.AreEqual(1, views[1][2].Count, "view [1][2] count");
+ Assert.AreEqual(1, views[1][3].Count, "view [1][3] count");
+ Assert.AreEqual(1, views[1][4].Count, "view [1][4] count");
+ Assert.AreEqual(2, views[1][5].Count, "view [1][5] count");
+ Assert.AreEqual(0, views[2][0].Count, "view [2][0] count");
+ Assert.AreEqual(1, views[2][1].Count, "view [2][1] count");
+ Assert.AreEqual(1, views[2][2].Count, "view [2][2] count");
+ Assert.AreEqual(1, views[2][3].Count, "view [2][3] count");
+ Assert.AreEqual(2, views[2][4].Count, "view [2][4] count");
+ Assert.AreEqual(0, views[3][0].Count, "view [3][0] count");
+ Assert.AreEqual(0, views[3][1].Count, "view [3][1] count");
+ Assert.AreEqual(0, views[3][2].Count, "view [3][2] count");
+ Assert.AreEqual(1, views[3][3].Count, "view [3][3] count");
+ Assert.AreEqual(0, views[4][0].Count, "view [4][0] count");
+ Assert.AreEqual(0, views[4][1].Count, "view [4][1] count");
+ Assert.AreEqual(1, views[4][2].Count, "view [4][2] count");
+ Assert.AreEqual(0, views[5][0].Count, "view [5][0] count");
+ Assert.AreEqual(1, views[5][1].Count, "view [5][1] count");
+ Assert.AreEqual(0, views[6][0].Count, "view [6][0] count");
+
+ Assert.IsTrue(list.Check(), "list check after RemoveAll");
+ }
+
+ [Test]
+ public void RetainAll()
+ {
+ LinkedList<int> list2 = new LinkedList<int>();
+ list2.Add(2); list2.Add(4); list2.Add(5);
+ Assert.IsTrue(list.Check(), "list check before RetainAll");
+ list.RetainAll(list2);
+ Assert.AreEqual(0, views[0][0].Offset, "view [0][0] offset");
+ Assert.AreEqual(0, views[0][1].Offset, "view [0][1] offset");
+ Assert.AreEqual(0, views[0][2].Offset, "view [0][2] offset");
+ Assert.AreEqual(0, views[0][3].Offset, "view [0][3] offset");
+ Assert.AreEqual(0, views[0][4].Offset, "view [0][4] offset");
+ Assert.AreEqual(0, views[0][5].Offset, "view [0][5] offset");
+ Assert.AreEqual(0, views[0][6].Offset, "view [0][6] offset");
+ Assert.AreEqual(0, views[1][0].Offset, "view [1][0] offset");
+ Assert.AreEqual(0, views[1][1].Offset, "view [1][1] offset");
+ Assert.AreEqual(0, views[1][2].Offset, "view [1][2] offset");
+ Assert.AreEqual(0, views[1][3].Offset, "view [1][3] offset");
+ Assert.AreEqual(0, views[1][4].Offset, "view [1][4] offset");
+ Assert.AreEqual(0, views[1][5].Offset, "view [1][5] offset");
+ Assert.AreEqual(0, views[2][0].Offset, "view [2][0] offset");
+ Assert.AreEqual(0, views[2][1].Offset, "view [2][1] offset");
+ Assert.AreEqual(0, views[2][2].Offset, "view [2][2] offset");
+ Assert.AreEqual(0, views[2][3].Offset, "view [2][3] offset");
+ Assert.AreEqual(0, views[2][4].Offset, "view [2][4] offset");
+ Assert.AreEqual(1, views[3][0].Offset, "view [3][0] offset");
+ Assert.AreEqual(1, views[3][1].Offset, "view [3][1] offset");
+ Assert.AreEqual(1, views[3][2].Offset, "view [3][2] offset");
+ Assert.AreEqual(1, views[3][3].Offset, "view [3][3] offset");
+ Assert.AreEqual(1, views[4][0].Offset, "view [4][0] offset");
+ Assert.AreEqual(1, views[4][1].Offset, "view [4][1] offset");
+ Assert.AreEqual(1, views[4][2].Offset, "view [4][2] offset");
+ Assert.AreEqual(2, views[5][0].Offset, "view [5][0] offset");
+ Assert.AreEqual(2, views[5][1].Offset, "view [5][1] offset");
+ Assert.AreEqual(3, views[6][0].Offset, "view [6][0] offset");
+
+ Assert.AreEqual(0, views[0][0].Count, "view [0][0] count");
+ Assert.AreEqual(0, views[0][1].Count, "view [0][1] count");
+ Assert.AreEqual(0, views[0][2].Count, "view [0][2] count");
+ Assert.AreEqual(1, views[0][3].Count, "view [0][3] count");
+ Assert.AreEqual(1, views[0][4].Count, "view [0][4] count");
+ Assert.AreEqual(2, views[0][5].Count, "view [0][5] count");
+ Assert.AreEqual(3, views[0][6].Count, "view [0][6] count");
+ Assert.AreEqual(0, views[1][0].Count, "view [1][0] count");
+ Assert.AreEqual(0, views[1][1].Count, "view [1][1] count");
+ Assert.AreEqual(1, views[1][2].Count, "view [1][2] count");
+ Assert.AreEqual(1, views[1][3].Count, "view [1][3] count");
+ Assert.AreEqual(2, views[1][4].Count, "view [1][4] count");
+ Assert.AreEqual(3, views[1][5].Count, "view [1][5] count");
+ Assert.AreEqual(0, views[2][0].Count, "view [2][0] count");
+ Assert.AreEqual(1, views[2][1].Count, "view [2][1] count");
+ Assert.AreEqual(1, views[2][2].Count, "view [2][2] count");
+ Assert.AreEqual(2, views[2][3].Count, "view [2][3] count");
+ Assert.AreEqual(3, views[2][4].Count, "view [2][4] count");
+ Assert.AreEqual(0, views[3][0].Count, "view [3][0] count");
+ Assert.AreEqual(0, views[3][1].Count, "view [3][1] count");
+ Assert.AreEqual(1, views[3][2].Count, "view [3][2] count");
+ Assert.AreEqual(2, views[3][3].Count, "view [3][3] count");
+ Assert.AreEqual(0, views[4][0].Count, "view [4][0] count");
+ Assert.AreEqual(1, views[4][1].Count, "view [4][1] count");
+ Assert.AreEqual(2, views[4][2].Count, "view [4][2] count");
+ Assert.AreEqual(0, views[5][0].Count, "view [5][0] count");
+ Assert.AreEqual(1, views[5][1].Count, "view [5][1] count");
+ Assert.AreEqual(0, views[6][0].Count, "view [6][0] count");
+
+
+ Assert.IsTrue(list.Check(), "list check after RetainAll");
+ }
+
+ [Test]
+ public void RemoveAllCopies()
+ {
+ LinkedList<int> list2 = new LinkedList<int>();
+ list2.Add(0); list2.Add(2); list2.Add(2); list2.Add(2); list2.Add(5); list2.Add(2); list2.Add(1);
+ for (int i = 0; i < 7; i++)
+ {
+ for (int j = 0; j < 7 - i; j++)
+ {
+ list = new LinkedList<int>();
+ list.AddAll(list2);
+ LinkedList<int> v = (LinkedList<int>)list.View(i, j);
+ list.RemoveAllCopies(2);
+ Assert.AreEqual(i == 0 ? 0 : i <= 4 ? 1 : i <= 6 ? 2 : 3, v.Offset, "v.Offset, i=" + i + ", j=" + j);
+ Assert.AreEqual((i == 0 && j > 0 ? 1 : 0) + (i <= 4 && i + j > 4 ? 1 : 0) + (i <= 6 && i + j > 6 ? 1 : 0), v.Count, "v.Count, i=" + i + ", j=" + j);
+ Assert.IsTrue(list.Check(), "list check after RemoveAllCopies, i=" + i + ", j=" + j);
+ }
+ }
+ }
+
+ private void checkDisposed(bool reverse, int start, int count)
+ {
+ int k = 0;
+ for (int i = 0; i < 7; i++)
+ for (int j = 0; j < 7 - i; j++)
+ {
+ if (i + j <= start || i >= start + count || (i <= start && i + j >= start + count) || (reverse && start <= i && start + count >= i + j))
+ {
+ try
+ {
+ k = views[i][j].Count;
+ }
+ catch (ViewDisposedException)
+ {
+ Assert.Fail("view[" + i + "][" + j + "] threw");
+ }
+ Assert.AreEqual(j, views[i][j].Count, "view[" + i + "][" + j + "] size");
+ if (reverse && ((j > 0 && start <= i && start + count >= i + j) || (j == 0 && start < i && start + count > i)))
+ Assert.AreEqual(start + (start + count - i - j), views[i][j].Offset, "view[" + i + "][" + j + "] offset (mirrored)");
+ else
+ Assert.AreEqual(i, views[i][j].Offset, "view[" + i + "][" + j + "] offset");
+ }
+ else
+ {
+ try
+ {
+ k = views[i][j].Count;
+ Assert.Fail("view[" + i + "][" + j + "] no throw");
+ }
+ catch (ViewDisposedException) { }
+ }
+ }
+ }
+
+ [Test]
+ public void Reverse()
+ {
+ int start = 2, count = 3;
+ IList<int> list2 = list.View(start, count);
+ Assert.IsTrue(list.Check(), "list check before Reverse");
+ list2.Reverse();
+ Assert.IsTrue(list.Check(), "list check after Reverse");
+ checkDisposed(true, start, count);
+ }
+ [Test]
+ public void Sort()
+ {
+ int start = 2, count = 3;
+ IList<int> list2 = list.View(start, count);
+ Assert.IsTrue(list.Check(), "list check before Sort");
+ list2.Sort();
+ Assert.IsTrue(list.Check(), "list check after Sort");
+ checkDisposed(false, start, count);
+ }
+ [Test]
+ public void Shuffle()
+ {
+ int start = 2, count = 3;
+ IList<int> list2 = list.View(start, count);
+ Assert.IsTrue(list.Check(), "list check before Shuffle");
+ list2.Shuffle();
+ Assert.IsTrue(list.Check(), "list check after Shuffle");
+ checkDisposed(false, start, count);
+ }
+
+
+ }
+
+
+ [TestFixture]
+ public class Validity
+ {
+ IList<int> list;
+ IList<int> view;
+ [SetUp]
+ public void Init()
+ {
+ list = new LinkedList<int>();
+ for (int i = 0; i < 6; i++)
+ list.Add(i);
+ view = list.View(2, 3);
+ view.Dispose();
+ }
+ [TearDown]
+ public void Dispose()
+ {
+ list = null;
+ view = null;
+ }
+
+ //Properties
+
+ //
+ /*ActiveEvents,
+AllowsDuplicates,
+ContainsSpeed,
+Count,
+CountSpeed,
+Direction,
+DuplicatesByCounting,
+FIFO,
+First,
+EqualityComparer,
+IsEmpty,
+IsReadOnly,
+this[int index],
+this[int start, int count],
+Last,
+Offset,
+SyncRoot,
+Underlying
+*/
+ [Test]
+ [ExpectedException(typeof(ViewDisposedException))]
+ public void Add()
+ {
+ view.Add(5);
+ }
+ [Test]
+ [ExpectedException(typeof(ViewDisposedException))]
+ public void AddAll_int_()
+ {
+ view.AddAll<int>(new int[] { });
+ }
+ [Test]
+ [ExpectedException(typeof(ViewDisposedException))]
+ public void AddAll()
+ {
+ view.AddAll<int>(new int[] { });
+ }
+ [Test]
+ [ExpectedException(typeof(ViewDisposedException))]
+ public void All()
+ {
+ view.All(delegate(int i) { return false; });
+ }
+ [Test]
+ [ExpectedException(typeof(ViewDisposedException))]
+ public void Apply()
+ {
+ view.Apply(delegate(int i) { });
+ }
+ [Test]
+ [ExpectedException(typeof(ViewDisposedException))]
+ public void Backwards()
+ {
+ view.Backwards();
+ }
+ [Test]
+ [ExpectedException(typeof(ViewDisposedException))]
+ public void Choose()
+ {
+ view.Choose();
+ }
+ [Test]
+ [ExpectedException(typeof(ViewDisposedException))]
+ public void Contains()
+ {
+ view.Contains(0);
+ }
+ [Test]
+ [ExpectedException(typeof(ViewDisposedException))]
+ public void Clear()
+ {
+ view.Clear();
+ }
+ [Test]
+ [ExpectedException(typeof(ViewDisposedException))]
+ public void ContainsAll()
+ {
+ view.ContainsAll<int>(new int[] { });
+ }
+ [Test]
+ [ExpectedException(typeof(ViewDisposedException))]
+ public void ContainsCount()
+ {
+ view.ContainsCount(0);
+ }
+ [Test]
+ [ExpectedException(typeof(ViewDisposedException))]
+ public void CopyTo()
+ {
+ view.CopyTo(new int[1], 0);
+ }
+ [Test]
+ [ExpectedException(typeof(ViewDisposedException))]
+ public void Dequeue()
+ {
+ ((LinkedList<int>)view).Dequeue();
+ }
+ [Test]
+ [ExpectedException(typeof(ViewDisposedException))]
+ public void Enqueue()
+ {
+ ((LinkedList<int>)view).Enqueue(0);
+ }
+ [Test]
+ [ExpectedException(typeof(ViewDisposedException))]
+ public void Exists()
+ {
+ view.Exists(delegate(int i) { return false; });
+ }
+ [Test]
+ [ExpectedException(typeof(ViewDisposedException))]
+ public void Filter()
+ {
+ view.Filter(delegate(int i) { return true; });
+ }
+ [Test]
+ [ExpectedException(typeof(ViewDisposedException))]
+ public void Find()
+ {
+ int i = 0;
+ view.Find(ref i);
+ }
+ [Test]
+ [ExpectedException(typeof(ViewDisposedException))]
+ public void FindAll()
+ {
+ view.FindAll(delegate(int i) { return false; });
+ }
+ [Test]
+ [ExpectedException(typeof(ViewDisposedException))]
+ public void FindOrAdd()
+ {
+ int i = 0;
+ view.FindOrAdd(ref i);
+ }
+
+ //TODO: wonder if it is allright to wait with the exception till the enumerator is actually used?
+ /* [Test]
+ [ExpectedException(typeof(ListDisposedException))]
+ public void GetEnumerator()
+ {
+ view.GetEnumerator();
+ }
+ */
+ /*Method overview
+ Check(),
+ checkRange(int start, int count),
+ Dispose(),
+ Equals(object obj),
+ Finalize(),
+ fireBagItemsAdded(T item, int count),
+ fireBagItemsRemoved(T item, int count),
+ fireCollectionChanged(),
+ fireCollectionCleared(int start, int count),
+ fireItemAdded(T item),
+ fireItemInserted(T item, int index),
+ fireItemRemoved(T item),
+ fireItemRemovedAt(T item, int index),
+ GetEnumerator(),
+ GetHashCode(),
+ GetSequencedHashCode(),
+ GetType(),
+ GetUnsequencedHashCode(),
+ IndexOf(T item),
+ Insert(int i, T item),
+ ViewOf().InsertLast(T item, T target),
+ InsertAll(int i, IEnumerable<T> items),
+ ViewOf().InsertFirst(T item, T target),
+ InsertFirst(T item),
+ InsertLast(T item),
+ IsSorted(SCG.IComparer<T> c),
+ LastIndexOf(T item),
+ LastViewOf(T item),
+ Map<V>(Fun<T,V> mapper),
+ Map<V>(Fun<T,V> mapper, SCG.IEqualityComparer<V> equalityComparer),
+ MemberwiseClone(),
+ modifycheck(int stamp),
+ Pop(),
+ Push(T item),
+ Remove(),
+ Remove(T item),
+ Remove(T item, out T removeditem),
+ RemoveAll(IEnumerable<T> items),
+ RemoveAllCopies(T item),
+ RemoveAt(int i),
+ RemoveFirst(),
+ RemoveInterval(int start, int count),
+ RemoveLast(),
+ RetainAll(IEnumerable<T> items),
+ Reverse(),
+ Reverse(int start, int count),
+ SequencedEquals(ISequenced<T> that),
+ Shuffle(),
+ Shuffle(System.Random rnd),
+ Slide(int offset),
+ Slide(int offset, int size),
+ Sort(),
+ Sort(SCG.IComparer<T> c),
+ ToArray(),
+ ToString(),
+ UnsequencedEquals(ICollection<T> that),
+ Update(T item),
+ Update(T item, out T olditem),
+ updatecheck(),
+ UpdateOrAdd(T item),
+ UpdateOrAdd(T item, out T olditem),
+ View(int start, int count),
+ ViewOf(T item)
+ */
+ }
+ }
+
+
+
+
+ namespace LinkedListOfTreesORLists
+ {
+ [TestFixture]
+ public class MultiLevelUnorderedOfUnOrdered
+ {
+ private ICollection<int> dit, dat, dut;
+
+ private ICollection<ICollection<int>> Dit, Dat, Dut;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new LinkedList<int>();
+ dat = new TreeSet<int>(Comparer<int>.Default, EqualityComparer<int>.Default);
+ dut = new LinkedList<int>();
+ dit.Add(2); dit.Add(1);
+ dat.Add(1); dat.Add(2);
+ dut.Add(3);
+ Dit = new LinkedList<ICollection<int>>();
+ Dat = new LinkedList<ICollection<int>>();
+ Dut = new LinkedList<ICollection<int>>();
+ }
+
+
+ [Test]
+ public void Check()
+ {
+ Assert.IsTrue(dit.UnsequencedEquals(dat));
+ Assert.IsFalse(dit.UnsequencedEquals(dut));
+ }
+
+
+ [Test]
+ public void Multi()
+ {
+ Dit.Add(dit); Dit.Add(dut); Dit.Add(dit);
+ Dat.Add(dut); Dat.Add(dit); Dat.Add(dat);
+ Assert.IsTrue(Dit.UnsequencedEquals(Dat));
+ Assert.IsFalse(Dit.UnsequencedEquals(Dut));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = dat = dut = null;
+ Dit = Dat = Dut = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class MultiLevelOrderedOfUnOrdered
+ {
+ private ICollection<int> dit, dat, dut;
+
+ private ISequenced<ICollection<int>> Dit, Dat, Dut;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new LinkedList<int>();
+ dat = new TreeSet<int>(Comparer<int>.Default, EqualityComparer<int>.Default);
+ dut = new LinkedList<int>();
+ dit.Add(2); dit.Add(1);
+ dat.Add(1); dat.Add(2);
+ dut.Add(3);
+ Dit = new LinkedList<ICollection<int>>();
+ Dat = new LinkedList<ICollection<int>>();
+ Dut = new LinkedList<ICollection<int>>();
+ }
+
+
+ [Test]
+ public void Check()
+ {
+ Assert.IsTrue(dit.UnsequencedEquals(dat));
+ Assert.IsFalse(dit.UnsequencedEquals(dut));
+ }
+
+
+ [Test]
+ public void Multi()
+ {
+ Dit.Add(dit); Dit.Add(dut); Dit.Add(dit);
+ Dat.Add(dut); Dat.Add(dit); Dat.Add(dat);
+ Dut.Add(dit); Dut.Add(dut); Dut.Add(dat);
+ Assert.IsFalse(Dit.SequencedEquals(Dat));
+ Assert.IsTrue(Dit.SequencedEquals(Dut));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = dat = dut = null;
+ Dit = Dat = Dut = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class MultiLevelUnOrderedOfOrdered
+ {
+ private ISequenced<int> dit, dat, dut, dot;
+
+ private ICollection<ISequenced<int>> Dit, Dat, Dut, Dot;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new TreeSet<int>(Comparer<int>.Default, EqualityComparer<int>.Default);
+ dat = new LinkedList<int>();
+ dut = new LinkedList<int>();
+ dot = new LinkedList<int>();
+ dit.Add(2); dit.Add(1);
+ dat.Add(2); dat.Add(1);
+ dut.Add(3);
+ dot.Add(1); dot.Add(2);
+ Dit = new LinkedList<ISequenced<int>>();
+ Dat = new LinkedList<ISequenced<int>>();
+ Dut = new LinkedList<ISequenced<int>>();
+ Dot = new LinkedList<ISequenced<int>>();
+ }
+
+
+ [Test]
+ public void Check()
+ {
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ Assert.IsTrue(dit.SequencedEquals(dot));
+ Assert.IsFalse(dit.SequencedEquals(dut));
+ }
+
+
+ [Test]
+ public void Multi()
+ {
+ Dit.Add(dit); Dit.Add(dut); Dit.Add(dit);
+ Dat.Add(dut); Dat.Add(dit); Dat.Add(dat);
+ Dut.Add(dot); Dut.Add(dut); Dut.Add(dit);
+ Dot.Add(dit); Dot.Add(dit); Dot.Add(dut);
+ Assert.IsTrue(Dit.UnsequencedEquals(Dut));
+ Assert.IsFalse(Dit.UnsequencedEquals(Dat));
+ Assert.IsTrue(Dit.UnsequencedEquals(Dot));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = dat = dut = dot = null;
+ Dit = Dat = Dut = Dot = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class MultiLevelOrderedOfOrdered
+ {
+ private ISequenced<int> dit, dat, dut, dot;
+
+ private ISequenced<ISequenced<int>> Dit, Dat, Dut, Dot;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new TreeSet<int>(Comparer<int>.Default, EqualityComparer<int>.Default);
+ dat = new LinkedList<int>();
+ dut = new LinkedList<int>();
+ dot = new LinkedList<int>();
+ dit.Add(2); dit.Add(1);
+ dat.Add(2); dat.Add(1);
+ dut.Add(3);
+ dot.Add(1); dot.Add(2);
+ Dit = new LinkedList<ISequenced<int>>();
+ Dat = new LinkedList<ISequenced<int>>();
+ Dut = new LinkedList<ISequenced<int>>();
+ Dot = new LinkedList<ISequenced<int>>();
+ }
+
+
+ [Test]
+ public void Check()
+ {
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ Assert.IsTrue(dit.SequencedEquals(dot));
+ Assert.IsFalse(dit.SequencedEquals(dut));
+ }
+
+
+ [Test]
+ public void Multi()
+ {
+ Dit.Add(dit); Dit.Add(dut); Dit.Add(dit);
+ Dat.Add(dut); Dat.Add(dit); Dat.Add(dat);
+ Dut.Add(dot); Dut.Add(dut); Dut.Add(dit);
+ Dot.Add(dit); Dot.Add(dit); Dot.Add(dut);
+ Assert.IsTrue(Dit.SequencedEquals(Dut));
+ Assert.IsFalse(Dit.SequencedEquals(Dat));
+ Assert.IsFalse(Dit.SequencedEquals(Dot));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = dat = dut = dot = null;
+ Dit = Dat = Dut = Dot = null;
+ }
+ }
+ }
+
+
+
+
+ namespace HashingAndEquals
+ {
+ [TestFixture]
+ public class ISequenced
+ {
+ private ISequenced<int> dit, dat, dut;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new LinkedList<int>();
+ dat = new LinkedList<int>();
+ dut = new LinkedList<int>();
+ }
+
+
+ [Test]
+ public void EmptyEmpty()
+ {
+ Assert.IsTrue(dit.SequencedEquals(dat));
+ }
+
+
+ [Test]
+ public void EmptyNonEmpty()
+ {
+ dit.Add(3);
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ Assert.IsFalse(dat.SequencedEquals(dit));
+ }
+
+ [Test]
+ public void HashVal()
+ {
+ Assert.AreEqual(CHC.sequencedhashcode(), dit.GetSequencedHashCode());
+ dit.Add(3);
+ Assert.AreEqual(CHC.sequencedhashcode(3), dit.GetSequencedHashCode());
+ dit.Add(7);
+ Assert.AreEqual(CHC.sequencedhashcode(3, 7), dit.GetSequencedHashCode());
+ Assert.AreEqual(CHC.sequencedhashcode(), dut.GetSequencedHashCode());
+ dut.Add(7);
+ Assert.AreEqual(CHC.sequencedhashcode(7), dut.GetSequencedHashCode());
+ dut.Add(3);
+ Assert.AreEqual(CHC.sequencedhashcode(7, 3), dut.GetSequencedHashCode());
+ }
+
+
+ [Test]
+ public void EqualHashButDifferent()
+ {
+ dit.Add(0); dit.Add(31);
+ dat.Add(1); dat.Add(0);
+ Assert.AreEqual(dit.GetSequencedHashCode(), dat.GetSequencedHashCode());
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ }
+
+
+ [Test]
+ public void Normal()
+ {
+ dit.Add(3);
+ dit.Add(7);
+ dat.Add(3);
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ Assert.IsFalse(dat.SequencedEquals(dit));
+ dat.Add(7);
+ Assert.IsTrue(dit.SequencedEquals(dat));
+ Assert.IsTrue(dat.SequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void WrongOrder()
+ {
+ dit.Add(3);
+ dut.Add(3);
+ Assert.IsTrue(dit.SequencedEquals(dut));
+ Assert.IsTrue(dut.SequencedEquals(dit));
+ dit.Add(7);
+ ((LinkedList<int>)dut).InsertFirst(7);
+ Assert.IsFalse(dit.SequencedEquals(dut));
+ Assert.IsFalse(dut.SequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void Reflexive()
+ {
+ Assert.IsTrue(dit.SequencedEquals(dit));
+ dit.Add(3);
+ Assert.IsTrue(dit.SequencedEquals(dit));
+ dit.Add(7);
+ Assert.IsTrue(dit.SequencedEquals(dit));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = null;
+ dat = null;
+ dut = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class IEditableCollection
+ {
+ private ICollection<int> dit, dat, dut;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new LinkedList<int>();
+ dat = new LinkedList<int>();
+ dut = new LinkedList<int>();
+ }
+
+
+ [Test]
+ public void EmptyEmpty()
+ {
+ Assert.IsTrue(dit.UnsequencedEquals(dat));
+ }
+
+
+ [Test]
+ public void EmptyNonEmpty()
+ {
+ dit.Add(3);
+ Assert.IsFalse(dit.UnsequencedEquals(dat));
+ Assert.IsFalse(dat.UnsequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void HashVal()
+ {
+ Assert.AreEqual(CHC.unsequencedhashcode(), dit.GetUnsequencedHashCode());
+ dit.Add(3);
+ Assert.AreEqual(CHC.unsequencedhashcode(3), dit.GetUnsequencedHashCode());
+ dit.Add(7);
+ Assert.AreEqual(CHC.unsequencedhashcode(3, 7), dit.GetUnsequencedHashCode());
+ Assert.AreEqual(CHC.unsequencedhashcode(), dut.GetUnsequencedHashCode());
+ dut.Add(3);
+ Assert.AreEqual(CHC.unsequencedhashcode(3), dut.GetUnsequencedHashCode());
+ dut.Add(7);
+ Assert.AreEqual(CHC.unsequencedhashcode(7, 3), dut.GetUnsequencedHashCode());
+ }
+
+
+ [Test]
+ public void EqualHashButDifferent()
+ {
+ dit.Add(-1657792980); dit.Add(-1570288808);
+ dat.Add(1862883298); dat.Add(-272461342);
+ Assert.AreEqual(dit.GetUnsequencedHashCode(), dat.GetUnsequencedHashCode());
+ Assert.IsFalse(dit.UnsequencedEquals(dat));
+ }
+
+
+ [Test]
+ public void Normal()
+ {
+ dit.Add(3);
+ dit.Add(7);
+ dat.Add(3);
+ Assert.IsFalse(dit.UnsequencedEquals(dat));
+ Assert.IsFalse(dat.UnsequencedEquals(dit));
+ dat.Add(7);
+ Assert.IsTrue(dit.UnsequencedEquals(dat));
+ Assert.IsTrue(dat.UnsequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void WrongOrder()
+ {
+ dit.Add(3);
+ dut.Add(3);
+ Assert.IsTrue(dit.UnsequencedEquals(dut));
+ Assert.IsTrue(dut.UnsequencedEquals(dit));
+ dit.Add(7);
+ dut.Add(7);
+ Assert.IsTrue(dit.UnsequencedEquals(dut));
+ Assert.IsTrue(dut.UnsequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void Reflexive()
+ {
+ Assert.IsTrue(dit.UnsequencedEquals(dit));
+ dit.Add(3);
+ Assert.IsTrue(dit.UnsequencedEquals(dit));
+ dit.Add(7);
+ Assert.IsTrue(dit.UnsequencedEquals(dit));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = null;
+ dat = null;
+ dut = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class MultiLevelUnorderedOfUnOrdered
+ {
+ private ICollection<int> dit, dat, dut;
+
+ private ICollection<ICollection<int>> Dit, Dat, Dut;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new LinkedList<int>();
+ dat = new LinkedList<int>();
+ dut = new LinkedList<int>();
+ dit.Add(2); dit.Add(1);
+ dat.Add(1); dat.Add(2);
+ dut.Add(3);
+ Dit = new LinkedList<ICollection<int>>();
+ Dat = new LinkedList<ICollection<int>>();
+ Dut = new LinkedList<ICollection<int>>();
+ }
+
+
+ [Test]
+ public void Check()
+ {
+ Assert.IsTrue(dit.UnsequencedEquals(dat));
+ Assert.IsFalse(dit.UnsequencedEquals(dut));
+ }
+
+
+ [Test]
+ public void Multi()
+ {
+ Dit.Add(dit); Dit.Add(dut); Dit.Add(dit);
+ Dat.Add(dut); Dat.Add(dit); Dat.Add(dat);
+ Assert.IsTrue(Dit.UnsequencedEquals(Dat));
+ Assert.IsFalse(Dit.UnsequencedEquals(Dut));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = dat = dut = null;
+ Dit = Dat = Dut = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class MultiLevelOrderedOfUnOrdered
+ {
+ private ICollection<int> dit, dat, dut;
+
+ private ISequenced<ICollection<int>> Dit, Dat, Dut;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new LinkedList<int>();
+ dat = new LinkedList<int>();
+ dut = new LinkedList<int>();
+ dit.Add(2); dit.Add(1);
+ dat.Add(1); dat.Add(2);
+ dut.Add(3);
+ Dit = new LinkedList<ICollection<int>>();
+ Dat = new LinkedList<ICollection<int>>();
+ Dut = new LinkedList<ICollection<int>>();
+ }
+
+
+ [Test]
+ public void Check()
+ {
+ Assert.IsTrue(dit.UnsequencedEquals(dat));
+ Assert.IsFalse(dit.UnsequencedEquals(dut));
+ }
+
+
+ [Test]
+ public void Multi()
+ {
+ Dit.Add(dit); Dit.Add(dut); Dit.Add(dit);
+ Dat.Add(dut); Dat.Add(dit); Dat.Add(dat);
+ Dut.Add(dit); Dut.Add(dut); Dut.Add(dat);
+ Assert.IsFalse(Dit.SequencedEquals(Dat));
+ Assert.IsTrue(Dit.SequencedEquals(Dut));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = dat = dut = null;
+ Dit = Dat = Dut = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class MultiLevelUnOrderedOfOrdered
+ {
+ private ISequenced<int> dit, dat, dut, dot;
+
+ private ICollection<ISequenced<int>> Dit, Dat, Dut, Dot;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new LinkedList<int>();
+ dat = new LinkedList<int>();
+ dut = new LinkedList<int>();
+ dot = new LinkedList<int>();
+ dit.Add(2); dit.Add(1);
+ dat.Add(1); dat.Add(2);
+ dut.Add(3);
+ dot.Add(2); dot.Add(1);
+ Dit = new LinkedList<ISequenced<int>>();
+ Dat = new LinkedList<ISequenced<int>>();
+ Dut = new LinkedList<ISequenced<int>>();
+ Dot = new LinkedList<ISequenced<int>>();
+ }
+
+
+ [Test]
+ public void Check()
+ {
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ Assert.IsTrue(dit.SequencedEquals(dot));
+ Assert.IsFalse(dit.SequencedEquals(dut));
+ }
+
+
+ [Test]
+ public void Multi()
+ {
+ Dit.Add(dit); Dit.Add(dut); Dit.Add(dit);
+ Dat.Add(dut); Dat.Add(dit); Dat.Add(dat);
+ Dut.Add(dot); Dut.Add(dut); Dut.Add(dit);
+ Dot.Add(dit); Dot.Add(dit); Dot.Add(dut);
+ Assert.IsTrue(Dit.UnsequencedEquals(Dut));
+ Assert.IsFalse(Dit.UnsequencedEquals(Dat));
+ Assert.IsTrue(Dit.UnsequencedEquals(Dot));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = dat = dut = dot = null;
+ Dit = Dat = Dut = Dot = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class MultiLevelOrderedOfOrdered
+ {
+ private ISequenced<int> dit, dat, dut, dot;
+
+ private ISequenced<ISequenced<int>> Dit, Dat, Dut, Dot;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new LinkedList<int>();
+ dat = new LinkedList<int>();
+ dut = new LinkedList<int>();
+ dot = new LinkedList<int>();
+ dit.Add(2); dit.Add(1);
+ dat.Add(1); dat.Add(2);
+ dut.Add(3);
+ dot.Add(2); dot.Add(1);
+ Dit = new LinkedList<ISequenced<int>>();
+ Dat = new LinkedList<ISequenced<int>>();
+ Dut = new LinkedList<ISequenced<int>>();
+ Dot = new LinkedList<ISequenced<int>>();
+ }
+
+
+ [Test]
+ public void Check()
+ {
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ Assert.IsTrue(dit.SequencedEquals(dot));
+ Assert.IsFalse(dit.SequencedEquals(dut));
+ }
+
+
+ [Test]
+ public void Multi()
+ {
+ Dit.Add(dit); Dit.Add(dut); Dit.Add(dit);
+ Dat.Add(dut); Dat.Add(dit); Dat.Add(dat);
+ Dut.Add(dot); Dut.Add(dut); Dut.Add(dit);
+ Dot.Add(dit); Dot.Add(dit); Dot.Add(dut);
+ Assert.IsTrue(Dit.SequencedEquals(Dut));
+ Assert.IsFalse(Dit.SequencedEquals(Dat));
+ Assert.IsFalse(Dit.SequencedEquals(Dot));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = dat = dut = dot = null;
+ Dit = Dat = Dut = Dot = null;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/1.0/Test/nunit.csproj b/mcs/class/Mono.C5/1.0/Test/nunit.csproj
new file mode 100644
index 00000000000..48ae348935d
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/Test/nunit.csproj
@@ -0,0 +1,118 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <ProductVersion>8.0.50727</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{08CBFDEB-A2E2-4F0E-A4E1-B996B05569DE}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <StartupObject>
+ </StartupObject>
+ <RootNamespace>nunit</RootNamespace>
+ <NoStandardLibraries>false</NoStandardLibraries>
+ <AssemblyName>nunit</AssemblyName>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
+ <DebugSymbols>true</DebugSymbols>
+ <Optimize>false</Optimize>
+ <OutputPath>.\bin\Debug\</OutputPath>
+ <EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <WarningLevel>4</WarningLevel>
+ <IncrementalBuild>false</IncrementalBuild>
+ </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>
+ </PropertyGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\C5\C5.csproj">
+ <Project>{D70489CD-ABDA-48FF-BD1E-BE3F7495BE71}</Project>
+ <Package>{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</Package>
+ <Name>C5</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="arrays\CircularQueueTest.cs" />
+ <Compile Include="AssemblyInfo.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="BasesTest.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="Records.cs" />
+ <Compile Include="Sorting.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="SupportClasses.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="arrays\ArrayListTest.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="arrays\HashedArrayListTest.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="arrays\SortedArrayTests.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="hashing\HashBagTests.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="hashing\HashDictionaryTests.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="hashing\HashTableTests.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="heaps\HeapTests.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="linkedlists\HashedLinkedListTest.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="linkedlists\LinkedListTest.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="templates\Clone.cs" />
+ <Compile Include="templates\Events.cs" />
+ <Compile Include="templates\GenericCollectionTester.cs" />
+ <Compile Include="templates\List.cs" />
+ <Compile Include="trees\Bag.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="trees\Dictionary.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="trees\RedBlackTreeSetTests.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="WrappersTest.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <AppDesigner Include="Properties\" />
+ </ItemGroup>
+ <ItemGroup>
+ <Reference Include="nunit.framework, Version=2.2.6.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL" />
+ </ItemGroup>
+ <ItemGroup>
+ <Folder Include="Properties\" />
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSHARP.Targets" />
+ <PropertyGroup>
+ <PreBuildEvent>
+ </PreBuildEvent>
+ <PostBuildEvent>
+ </PostBuildEvent>
+ </PropertyGroup>
+ <ProjectExtensions>
+ <VisualStudio>
+ </VisualStudio>
+ </ProjectExtensions>
+</Project> \ No newline at end of file
diff --git a/mcs/class/Mono.C5/1.0/Test/templates/Clone.cs b/mcs/class/Mono.C5/1.0/Test/templates/Clone.cs
new file mode 100644
index 00000000000..b8b655fdca8
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/Test/templates/Clone.cs
@@ -0,0 +1,117 @@
+/*
+ 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 C5;
+using NUnit.Framework;
+using SCG = System.Collections.Generic;
+
+namespace C5UnitTests.Templates.Extensible
+{
+ class Clone
+ {
+ public static void Tester<U>() where U : class, IExtensible<int>, new()
+ {
+ U extensible = new U();
+ RealTester<U>(extensible);
+ extensible.Add(12);
+ extensible.Add(23);
+ extensible.Add(56);
+ RealTester<U>(extensible);
+ }
+
+ public static void ViewTester<U>() where U : class, IList<int>, new()
+ {
+ U baselist = new U();
+ baselist.Add(12);
+ baselist.Add(23);
+ baselist.Add(56);
+ baselist.Add(112);
+ baselist.Add(123);
+ baselist.Add(156);
+ U view = (U)baselist.View(2, 2);
+ RealTester<U>(view);
+ }
+
+ public static void RealTester<U>(U extensible) where U : class, IExtensible<int>, new()
+ {
+ object clone = extensible.Clone();
+ Assert.IsNotNull(clone);
+ Assert.AreEqual(typeof(U), clone.GetType(),
+ String.Format("Wrong type '{0}' of clone of '{1}'", clone.GetType(), typeof(U)));
+ U theClone = clone as U;
+ Assert.IsTrue(theClone.Check(), "Clone does not pass Check()");
+ if (typeof(ICollection<int>).IsAssignableFrom(typeof(U)))
+ Assert.IsTrue(EqualityComparer<U>.Default.Equals(extensible, theClone), "Clone has wrong contents");
+ else //merely extensible
+ Assert.IsTrue(IC.eq(theClone, extensible.ToArray()), "Clone has wrong contents");
+ }
+ }
+
+ class Serialization
+ {
+ public static void Tester<U>() where U : class, IExtensible<int>, new()
+ {
+ U extensible = new U();
+ realtester<U>(extensible);
+ extensible.Add(12);
+ extensible.Add(23);
+ extensible.Add(56);
+ realtester<U>(extensible);
+ }
+
+ public static void ViewTester<U>() where U : class, IList<int>, new()
+ {
+ U baselist = new U();
+ baselist.Add(12);
+ baselist.Add(23);
+ baselist.Add(56);
+ baselist.Add(112);
+ baselist.Add(123);
+ baselist.Add(156);
+ U view = (U)baselist.View(2, 2);
+ realtester<U>(view);
+ }
+
+ private static void realtester<U>(U extensible) where U : class, IExtensible<int>, new()
+ {
+ System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter =
+ new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
+ System.IO.Stream stream = new System.IO.MemoryStream();
+ formatter.Serialize(stream, extensible);
+ stream.Flush();
+ stream.Seek(0L, System.IO.SeekOrigin.Begin);
+ object clone = formatter.Deserialize(stream);
+
+ Assert.IsNotNull(clone);
+ Assert.AreEqual(typeof(U), clone.GetType(),
+ String.Format("Wrong type '{0}' of clone of '{1}'", clone.GetType(), typeof(U)));
+ U theClone = clone as U;
+ Assert.IsTrue(theClone.Check(), "Clone does not pass Check()");
+ if (typeof(ICollection<int>).IsAssignableFrom(typeof(U)))
+ Assert.IsTrue(EqualityComparer<U>.Default.Equals(extensible, theClone), "Clone has wrong contents");
+ else //merely extensible
+ Assert.IsTrue(IC.eq(theClone, extensible.ToArray()), "Clone has wrong contents");
+ }
+ }
+
+}
+
diff --git a/mcs/class/Mono.C5/1.0/Test/templates/Events.cs b/mcs/class/Mono.C5/1.0/Test/templates/Events.cs
new file mode 100644
index 00000000000..80ca259c237
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/Test/templates/Events.cs
@@ -0,0 +1,928 @@
+/*
+ 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 C5;
+using NUnit.Framework;
+using SCG = System.Collections.Generic;
+using System.Reflection;
+
+namespace C5UnitTests.Templates.Events
+{
+ public abstract class CollectionValueTester<TCollection, TItem> : GenericCollectionTester<TCollection, EventTypeEnum>
+ where TCollection : ICollectionValue<TItem>
+ {
+ protected TCollection collection;
+ protected CollectionEventList<TItem> seen;
+ protected EventTypeEnum listenTo;
+ protected void listen() { seen.Listen(collection, listenTo); }
+
+ public override void SetUp(TCollection list, EventTypeEnum testSpec)
+ {
+ this.collection = list;
+ listenTo = testSpec;
+ seen = new CollectionEventList<TItem>(EqualityComparer<TItem>.Default);
+ }
+
+ public SCG.IEnumerable<EventTypeEnum> SpecsBasic
+ {
+ get
+ {
+ CircularQueue<EventTypeEnum> specs = new CircularQueue<EventTypeEnum>();
+ //foreach (EventTypeEnum listenTo in Enum.GetValues(typeof(EventTypeEnum)))
+ // if ((listenTo & ~EventTypeEnum.Basic) == 0)
+ // specs.Enqueue(listenTo);
+ //specs.Enqueue(EventTypeEnum.Added | EventTypeEnum.Removed);
+ for (int spec = 0; spec <= (int)EventTypeEnum.Basic; spec++)
+ specs.Enqueue((EventTypeEnum)spec);
+ return specs;
+ }
+ }
+ public SCG.IEnumerable<EventTypeEnum> SpecsAll
+ {
+ get
+ {
+ CircularQueue<EventTypeEnum> specs = new CircularQueue<EventTypeEnum>();
+ //foreach (EventTypeEnum listenTo in Enum.GetValues(typeof(EventTypeEnum)))
+ // specs.Enqueue(listenTo);
+ //specs.Enqueue(EventTypeEnum.Added | EventTypeEnum.Removed);
+
+ for (int spec = 0; spec <= (int)EventTypeEnum.All; spec++)
+ specs.Enqueue((EventTypeEnum)spec);
+ return specs;
+ }
+ }
+ }
+ public abstract class CollectionValueTester<U> : CollectionValueTester<U, int> where U : ICollectionValue<int>
+ {
+ }
+
+ public class ExtensibleTester<U> : CollectionValueTester<U> where U : IExtensible<int>
+ {
+ public override SCG.IEnumerable<EventTypeEnum> GetSpecs()
+ {
+ return SpecsBasic;
+ }
+ [Test]
+ public virtual void Listenable()
+ {
+ Assert.AreEqual(EventTypeEnum.Basic, collection.ListenableEvents);
+ Assert.AreEqual(EventTypeEnum.None, collection.ActiveEvents);
+ listen();
+ Assert.AreEqual(listenTo, collection.ActiveEvents);
+ }
+
+ [Test]
+ public void Add()
+ {
+ listen();
+ seen.Check(new CollectionEvent<int>[0]);
+ collection.Add(23);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(23, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)});
+ }
+
+ [Test]
+ public void AddAll()
+ {
+ for (int i = 0; i < 10; i++)
+ {
+ collection.Add(10 * i + 5);
+ }
+ listen();
+ collection.AddAll<int>(new int[] { 45, 200, 56, 67 });
+ seen.Check(collection.AllowsDuplicates ?
+ collection.DuplicatesByCounting ?
+ new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(45, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(200, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(55, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(65, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)}
+ :
+ new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(45, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(200, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(56, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(67, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)}
+ :
+ new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(200, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)});
+ collection.AddAll<int>(new int[] { });
+ seen.Check(new CollectionEvent<int>[] { });
+ }
+
+ }
+
+ public class CollectionTester<U> : ExtensibleTester<U> where U : ICollection<int>
+ {
+ [Test]
+ public void Update()
+ {
+ collection.Add(4); collection.Add(54); collection.Add(56); collection.Add(8);
+ listen();
+ collection.Update(53);
+ seen.Check(
+ collection.AllowsDuplicates ?
+ collection.DuplicatesByCounting ?
+ new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(54, 2), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(53, 2), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)
+ }
+ : new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(54, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(53, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)
+ }
+ : new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(54, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(53, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)
+ });
+ collection.Update(67);
+ seen.Check(new CollectionEvent<int>[] { });
+ }
+
+ [Test]
+ public void FindOrAdd()
+ {
+ collection.Add(4); collection.Add(56); collection.Add(8);
+ listen();
+ int val = 53;
+ collection.FindOrAdd(ref val);
+ seen.Check(new CollectionEvent<int>[] { });
+ val = 67;
+ collection.FindOrAdd(ref val);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(67, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)
+ });
+ }
+
+ [Test]
+ public void UpdateOrAdd()
+ {
+ collection.Add(4); collection.Add(56); collection.Add(8);
+ listen();
+ int val = 53;
+ collection.UpdateOrAdd(val);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(56, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(53, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)
+ });
+ val = 67;
+ collection.UpdateOrAdd(val);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(67, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)
+ });
+ collection.UpdateOrAdd(51, out val);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(53, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(51, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)
+ });
+ val = 67;
+ collection.UpdateOrAdd(81, out val);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(81, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)
+ });
+ }
+
+ [Test]
+ public void RemoveItem()
+ {
+ collection.Add(4); collection.Add(56); collection.Add(18);
+ listen();
+ collection.Remove(53);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(56, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)});
+ collection.Remove(11);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(18, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)});
+ }
+
+ [Test]
+ public void RemoveAll()
+ {
+ for (int i = 0; i < 10; i++)
+ {
+ collection.Add(10 * i + 5);
+ }
+ listen();
+ collection.RemoveAll<int>(new int[] { 32, 187, 45 });
+ //TODO: the order depends on internals of the HashSet
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(35, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(45, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)});
+ collection.RemoveAll<int>(new int[] { 200, 300 });
+ seen.Check(new CollectionEvent<int>[] { });
+ }
+
+ [Test]
+ public void RetainAll()
+ {
+ for (int i = 0; i < 10; i++)
+ {
+ collection.Add(10 * i + 5);
+ }
+ listen();
+ collection.RetainAll<int>(new int[] { 32, 187, 45, 62, 75, 82, 95, 2 });
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(15, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(25, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(55, 1), collection),
+ //new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(75, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)});
+ collection.RetainAll<int>(new int[] { 32, 187, 45, 62, 75, 82, 95, 2 });
+ seen.Check(new CollectionEvent<int>[] { });
+ }
+
+ [Test]
+ public void RemoveAllCopies()
+ {
+ for (int i = 0; i < 10; i++)
+ {
+ collection.Add(3 * i + 5);
+ }
+ listen();
+ collection.RemoveAllCopies(14);
+ seen.Check(
+ collection.AllowsDuplicates ?
+ collection.DuplicatesByCounting ?
+ new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(11, 3), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)}
+ :
+ new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(11, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(14, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(17, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)}
+ :
+ new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(11, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)});
+ collection.RemoveAllCopies(14);
+ seen.Check(new CollectionEvent<int>[] { });
+ }
+
+ [Test]
+ public virtual void Clear()
+ {
+ collection.Add(4); collection.Add(56); collection.Add(8);
+ listen();
+ collection.Clear();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Cleared, new ClearedEventArgs(true, collection.AllowsDuplicates ? 3 : 2), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)
+ });
+ collection.Clear();
+ seen.Check(new CollectionEvent<int>[] { });
+ }
+
+ }
+
+ public class IndexedTester<U> : CollectionTester<U> where U : IIndexed<int>
+ {
+ [Test]
+ public void RemoveAt()
+ {
+ collection.Add(4); collection.Add(16); collection.Add(28);
+ listen();
+ collection.RemoveAt(1);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(16,1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(16, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)});
+ }
+
+ [Test]
+ public void RemoveInterval()
+ {
+ collection.Add(4); collection.Add(56); collection.Add(18);
+ listen();
+ collection.RemoveInterval(1, 2);
+ seen.Check(new CollectionEvent<int>[] {
+ collection is IList<int> ?
+ new CollectionEvent<int>(EventTypeEnum.Cleared, new ClearedRangeEventArgs(false,2,1), collection):
+ new CollectionEvent<int>(EventTypeEnum.Cleared, new ClearedEventArgs(false,2), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)
+ });
+ collection.RemoveInterval(1, 0);
+ seen.Check(new CollectionEvent<int>[] { });
+ }
+ }
+
+ public class SortedIndexedTester<U> : IndexedTester<U> where U : IIndexedSorted<int>
+ {
+ [Test]
+ public void DeleteMinMax()
+ {
+ collection.Add(34);
+ collection.Add(56);
+ collection.Add(34);
+ collection.Add(12);
+ listen();
+ collection.DeleteMax();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(56, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection),
+ });
+ collection.DeleteMin();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(12, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection),
+ });
+ }
+
+ [Test]
+ public void AddSorted()
+ {
+ listen();
+ collection.AddSorted(collection.AllowsDuplicates ? new int[] { 31, 62, 63, 93 } : new int[] { 31, 62, 93 });
+ seen.Check(collection.AllowsDuplicates ?
+ collection.DuplicatesByCounting ?
+ new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(31, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(62, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(62, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(93, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)}
+ :
+ new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(31, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(62, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(63, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(93, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)}
+ :
+ new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(31, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(62, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(93, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)});
+ collection.AddSorted(new int[] { });
+ seen.Check(new CollectionEvent<int>[] { });
+ }
+
+ [Test]
+ public void RemoveRange()
+ {
+ for (int i = 0; i < 20; i++)
+ collection.Add(i * 10 + 5);
+ listen();
+ collection.RemoveRangeFrom(173);
+ //TODO: fix order to remove in:
+ seen.Check(
+ new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(195, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(185, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(175, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)});
+ collection.RemoveRangeFromTo(83, 113);
+ seen.Check(
+ new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(105, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(95, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(85, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)});
+ collection.RemoveRangeTo(33);
+ seen.Check(
+ new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(5, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(15, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(25, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)});
+ collection.RemoveRangeFrom(173);
+ seen.Check(new CollectionEvent<int>[] { });
+ collection.RemoveRangeFromTo(83, 113);
+ seen.Check(new CollectionEvent<int>[] { });
+ collection.RemoveRangeTo(33);
+ seen.Check(new CollectionEvent<int>[] { });
+ }
+ }
+
+ public class ListTester<U> : IndexedTester<U> where U : IList<int>
+ {
+ public override SCG.IEnumerable<EventTypeEnum> GetSpecs()
+ {
+ return SpecsAll;
+ }
+
+ [Test]
+ public override void Listenable()
+ {
+ Assert.AreEqual(EventTypeEnum.All, collection.ListenableEvents);
+ Assert.AreEqual(EventTypeEnum.None, collection.ActiveEvents);
+ listen();
+ Assert.AreEqual(listenTo, collection.ActiveEvents);
+ }
+ [Test]
+ public void SetThis()
+ {
+ collection.Add(4); collection.Add(56); collection.Add(8);
+ listen();
+ collection[1] = 45;
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(56, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(56,1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(45, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(45,1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)
+ });
+ }
+
+ [Test]
+ public void Insert()
+ {
+ collection.Add(4); collection.Add(56); collection.Add(8);
+ listen();
+ collection.Insert(1, 45);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(45,1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(45, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)
+ });
+ }
+
+ [Test]
+ public void InsertAll()
+ {
+ collection.Add(4); collection.Add(56); collection.Add(8);
+ listen();
+ collection.InsertAll<int>(1, new int[] { 666, 777, 888 });
+ //seen.Print(Console.Error);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(666,1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(666, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(777,2), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(777, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(888,3), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(888, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)
+ });
+ collection.InsertAll<int>(1, new int[] { });
+ seen.Check(new CollectionEvent<int>[] { });
+ }
+
+ [Test]
+ public void InsertFirstLast()
+ {
+ collection.Add(4); collection.Add(56); collection.Add(18);
+ listen();
+ collection.InsertFirst(45);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(45,0), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(45, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)
+ });
+ collection.InsertLast(88);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(88,4), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(88, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)
+ });
+ }
+
+ [Test]
+ public void Remove()
+ {
+ collection.FIFO = false;
+ collection.Add(4); collection.Add(56); collection.Add(18);
+ listen();
+ collection.Remove();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(18, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)});
+ collection.FIFO = true;
+ collection.Remove();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(4, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)});
+ }
+
+ [Test]
+ public void RemoveFirst()
+ {
+ collection.Add(4); collection.Add(56); collection.Add(18);
+ listen();
+ collection.RemoveFirst();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(4,0), collection),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(4, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)});
+ }
+
+ [Test]
+ public void RemoveLast()
+ {
+ collection.Add(4); collection.Add(56); collection.Add(18);
+ listen();
+ collection.RemoveLast();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(18,2), collection),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(18, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)});
+ }
+
+ [Test]
+ public void Reverse()
+ {
+ collection.Add(4); collection.Add(56); collection.Add(8);
+ listen();
+ collection.Reverse();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)
+ });
+ collection.View(1, 0).Reverse();
+ seen.Check(new CollectionEvent<int>[] { });
+ }
+
+
+ [Test]
+ public void Sort()
+ {
+ collection.Add(4); collection.Add(56); collection.Add(8);
+ listen();
+ collection.Sort();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)
+ });
+ collection.View(1, 0).Sort();
+ seen.Check(new CollectionEvent<int>[] { });
+ }
+
+ [Test]
+ public void Shuffle()
+ {
+ collection.Add(4); collection.Add(56); collection.Add(8);
+ listen();
+ collection.Shuffle();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)
+ });
+ collection.View(1, 0).Shuffle();
+ seen.Check(new CollectionEvent<int>[] { });
+ }
+
+ [Test]
+ public override void Clear()
+ {
+ collection.Add(4); collection.Add(56); collection.Add(18);
+ listen();
+ collection.View(1, 1).Clear();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Cleared, new ClearedRangeEventArgs(false,1,1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)
+ });
+ collection.Clear();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Cleared, new ClearedRangeEventArgs(true,2,0), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)
+ });
+ collection.Clear();
+ seen.Check(new CollectionEvent<int>[] { });
+ }
+
+ [Test]
+ public void ListDispose()
+ {
+ collection.Add(4); collection.Add(56); collection.Add(18);
+ listen();
+ collection.View(1, 1).Dispose();
+ seen.Check(new CollectionEvent<int>[] { });
+ collection.Dispose();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Cleared, new ClearedRangeEventArgs(true,3,0), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)
+ });
+ collection.Dispose();
+ seen.Check(new CollectionEvent<int>[] { });
+ }
+
+ /*
+
+ * /
+ //[TearDown]
+ //public void Dispose() { list = null; seen = null; }
+ /*
+ [Test]
+ [ExpectedException(typeof(UnlistenableEventException))]
+ public void ViewChanged()
+ {
+ IList<int> w = collection.View(0, 0);
+ w.CollectionChanged += new CollectionChangedHandler<int>(w_CollectionChanged);
+ }
+
+ [Test]
+ [ExpectedException(typeof(UnlistenableEventException))]
+ public void ViewCleared()
+ {
+ IList<int> w = collection.View(0, 0);
+ w.CollectionCleared += new CollectionClearedHandler<int>(w_CollectionCleared);
+ }
+
+ [Test]
+ [ExpectedException(typeof(UnlistenableEventException))]
+ public void ViewAdded()
+ {
+ IList<int> w = collection.View(0, 0);
+ w.ItemsAdded += new ItemsAddedHandler<int>(w_ItemAdded);
+ }
+
+ [Test]
+ [ExpectedException(typeof(UnlistenableEventException))]
+ public void ViewInserted()
+ {
+ IList<int> w = collection.View(0, 0);
+ w.ItemInserted += new ItemInsertedHandler<int>(w_ItemInserted);
+ }
+
+ [Test]
+ [ExpectedException(typeof(UnlistenableEventException))]
+ public void ViewRemoved()
+ {
+ IList<int> w = collection.View(0, 0);
+ w.ItemsRemoved += new ItemsRemovedHandler<int>(w_ItemRemoved);
+ }
+
+ [Test]
+ [ExpectedException(typeof(UnlistenableEventException))]
+ public void ViewRemovedAt()
+ {
+ IList<int> w = collection.View(0, 0);
+ w.ItemRemovedAt += new ItemRemovedAtHandler<int>(w_ItemRemovedAt);
+ }
+
+ void w_CollectionChanged(object sender)
+ {
+ throw new NotImplementedException();
+ }
+
+ void w_CollectionCleared(object sender, ClearedEventArgs eventArgs)
+ {
+ throw new NotImplementedException();
+ }
+
+ void w_ItemAdded(object sender, ItemCountEventArgs<int> eventArgs)
+ {
+ throw new NotImplementedException();
+ }
+
+ void w_ItemInserted(object sender, ItemAtEventArgs<int> eventArgs)
+ {
+ throw new NotImplementedException();
+ }
+
+ void w_ItemRemoved(object sender, ItemCountEventArgs<int> eventArgs)
+ {
+ throw new NotImplementedException();
+ }
+
+ void w_ItemRemovedAt(object sender, ItemAtEventArgs<int> eventArgs)
+ {
+ throw new NotImplementedException();
+ }*/
+ }
+
+ public class StackTester<U> : CollectionValueTester<U> where U : IStack<int>
+ {
+ public override SCG.IEnumerable<EventTypeEnum> GetSpecs()
+ {
+ return SpecsBasic;
+ }
+
+ [Test]
+ public void PushPop()
+ {
+ listen();
+ seen.Check(new CollectionEvent<int>[0]);
+ collection.Push(23);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(23,0), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(23, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)});
+ collection.Push(-12);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(-12,1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(-12, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)});
+ collection.Pop();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(-12,1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(-12, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)});
+ collection.Pop();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(23,0), collection),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(23, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)});
+ }
+ }
+
+ public class QueueTester<U> : CollectionValueTester<U> where U : IQueue<int>
+ {
+ public override SCG.IEnumerable<EventTypeEnum> GetSpecs()
+ {
+ return SpecsBasic;
+ }
+
+ [Test]
+ public void EnqueueDequeue()
+ {
+ listen();
+ collection.Enqueue(67);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(67,0), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(67, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)});
+ collection.Enqueue(2);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Inserted, new ItemAtEventArgs<int>(2,1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(2, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)});
+ collection.Dequeue();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(67,0), collection),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(67, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)});
+ collection.Dequeue();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.RemovedAt, new ItemAtEventArgs<int>(2,0), collection),
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(2, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)});
+ }
+
+ }
+
+ public class PriorityQueueTester<U> : ExtensibleTester<U> where U : IPriorityQueue<int>
+ {
+ public override System.Collections.Generic.IEnumerable<EventTypeEnum> GetSpecs()
+ {
+ return SpecsBasic;
+ }
+
+ [Test]
+ public void Direct()
+ {
+ listen();
+ collection.Add(34);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(34, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection),
+ });
+ collection.Add(56);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(56, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection),
+ });
+ collection.AddAll<int>(new int[] { });
+ seen.Check(new CollectionEvent<int>[] {
+ });
+ collection.Add(34);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(34, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection),
+ });
+ collection.Add(12);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(12, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection),
+ });
+ collection.DeleteMax();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(56, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection),
+ });
+ collection.DeleteMin();
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(12, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection),
+ });
+ collection.AddAll<int>(new int[] { 4, 5, 6, 2 });
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(4, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(5, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(6, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(2, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection)
+ });
+ }
+
+ [Test]
+ public void WithHandles()
+ {
+ listen();
+ IPriorityQueueHandle<int> handle = null, handle2;
+ collection.Add(34);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(34, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection),
+ });
+ collection.Add(56);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(56, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection),
+ });
+ collection.Add(ref handle, 34);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(34, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection),
+ });
+ collection.Add(12);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(12, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection),
+ });
+ collection.DeleteMax(out handle2);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(56, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection),
+ });
+ collection.DeleteMin(out handle2);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(12, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection),
+ });
+
+ collection.Replace(handle, 117);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(34, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Added, new ItemCountEventArgs<int>(117, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection),
+ });
+
+ collection.Delete(handle);
+ seen.Check(new CollectionEvent<int>[] {
+ new CollectionEvent<int>(EventTypeEnum.Removed, new ItemCountEventArgs<int>(117, 1), collection),
+ new CollectionEvent<int>(EventTypeEnum.Changed, new EventArgs(), collection),
+ });
+ }
+ }
+
+ public class DictionaryTester<U> : CollectionValueTester<U, KeyValuePair<int, int>> where U : IDictionary<int, int>
+ {
+ public override SCG.IEnumerable<EventTypeEnum> GetSpecs()
+ {
+ return SpecsBasic;
+ }
+
+ [Test]
+ public virtual void Listenable()
+ {
+ Assert.AreEqual(EventTypeEnum.Basic, collection.ListenableEvents);
+ Assert.AreEqual(EventTypeEnum.None, collection.ActiveEvents);
+ listen();
+ Assert.AreEqual(listenTo, collection.ActiveEvents);
+ }
+
+ [Test]
+ public void AddAndREmove()
+ {
+ listen();
+ seen.Check(new CollectionEvent<KeyValuePair<int, int>>[0]);
+ collection.Add(23, 45);
+ seen.Check(new CollectionEvent<KeyValuePair<int,int>>[] {
+ new CollectionEvent<KeyValuePair<int,int>>(EventTypeEnum.Added, new ItemCountEventArgs<KeyValuePair<int,int>>(new KeyValuePair<int,int>(23,45), 1), collection),
+ new CollectionEvent<KeyValuePair<int,int>>(EventTypeEnum.Changed, new EventArgs(), collection)});
+ collection.Remove(25);
+ seen.Check(new CollectionEvent<KeyValuePair<int, int>>[] {
+ new CollectionEvent<KeyValuePair<int,int>>(EventTypeEnum.Removed, new ItemCountEventArgs<KeyValuePair<int,int>>(new KeyValuePair<int,int>(23,45), 1), collection),
+ new CollectionEvent<KeyValuePair<int,int>>(EventTypeEnum.Changed, new EventArgs(), collection)});
+ }
+
+
+
+ }
+
+}
+
+
diff --git a/mcs/class/Mono.C5/1.0/Test/templates/GenericCollectionTester.cs b/mcs/class/Mono.C5/1.0/Test/templates/GenericCollectionTester.cs
new file mode 100644
index 00000000000..20445636909
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/Test/templates/GenericCollectionTester.cs
@@ -0,0 +1,87 @@
+/*
+ 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 C5;
+using NUnit.Framework;
+using SCG = System.Collections.Generic;
+using System.Reflection;
+
+namespace C5UnitTests.Templates
+{
+ public abstract class GenericCollectionTester<U, W>
+ {
+ protected CircularQueue<MethodInfo> testMethods;
+ public GenericCollectionTester()
+ {
+ testMethods = new CircularQueue<MethodInfo>();
+ foreach (MethodInfo minfo in this.GetType().GetMethods())
+ {
+ if (minfo.GetParameters().Length == 0 &&
+ minfo.GetCustomAttributes(typeof(TestAttribute), false).Length > 0)
+ testMethods.Enqueue(minfo);
+ }
+ }
+
+ public virtual void Test(Fun<U> factory)
+ {
+ foreach (MethodInfo minfo in testMethods)
+ {
+ foreach (W testSpec in GetSpecs())
+ {
+ SetUp(factory(), testSpec);
+ //Console.WriteLine("Testing {0}, with method {1} and testSpec {{{2}}}", typeof(U), minfo.Name, testSpec);
+ try
+ {
+ minfo.Invoke(this, null);
+ }
+ catch (TargetInvocationException)
+ {
+ //if (e.InnerException is ExpectedExceptionAttribute)
+ //{
+ //}
+ //else
+ throw;
+ }
+ //tearDown
+ }
+ }
+ }
+
+ public abstract void SetUp(U collection, W testSpec);
+ public abstract SCG.IEnumerable<W> GetSpecs();
+ }
+
+ public abstract class GenericCollectionTester<U> : GenericCollectionTester<U, int>
+ {
+ public override System.Collections.Generic.IEnumerable<int> GetSpecs()
+ {
+ return new int[] { 0 };
+ }
+
+ public override void SetUp(U collection, int testSpec)
+ {
+ SetUp(collection);
+ }
+
+ public abstract void SetUp(object collection);
+ }
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/1.0/Test/templates/List.cs b/mcs/class/Mono.C5/1.0/Test/templates/List.cs
new file mode 100644
index 00000000000..5ea90dc39d6
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/Test/templates/List.cs
@@ -0,0 +1,40 @@
+/*
+ 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 C5;
+using NUnit.Framework;
+using SCG = System.Collections.Generic;
+
+namespace C5UnitTests.Templates.List
+{
+ class Foo
+ {
+ public static void Tester<U>() where U : class, IList<int>, new()
+ {
+ U extensible = new U();
+ extensible.Add(12);
+ extensible.Add(23);
+ extensible.Add(56);
+ }
+ }
+}
+
diff --git a/mcs/class/Mono.C5/1.0/Test/trees/Bag.cs b/mcs/class/Mono.C5/1.0/Test/trees/Bag.cs
new file mode 100644
index 00000000000..3c7b38ec177
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/Test/trees/Bag.cs
@@ -0,0 +1,2931 @@
+/*
+ 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 C5;
+using NUnit.Framework;
+using SCG = System.Collections.Generic;
+
+
+namespace C5UnitTests.trees.TreeBag
+{
+ using CollectionOfInt = TreeBag<int>;
+
+ [TestFixture]
+ public class GenericTesters
+ {
+ [Test]
+ public void TestEvents()
+ {
+ Fun<CollectionOfInt> factory = delegate() { return new CollectionOfInt(TenEqualityComparer.Default); };
+ new C5UnitTests.Templates.Events.SortedIndexedTester<CollectionOfInt>().Test(factory);
+ }
+
+ [Test]
+ public void Extensible()
+ {
+ C5UnitTests.Templates.Extensible.Clone.Tester<CollectionOfInt>();
+ C5UnitTests.Templates.Extensible.Serialization.Tester<CollectionOfInt>();
+ }
+ }
+
+ static class Factory
+ {
+ public static ICollection<T> New<T>() { return new TreeBag<T>(); }
+ }
+
+
+ [TestFixture]
+ public class Formatting
+ {
+ ICollection<int> coll;
+ IFormatProvider rad16;
+ [SetUp]
+ public void Init() { coll = Factory.New<int>(); rad16 = new RadixFormatProvider(16); }
+ [TearDown]
+ public void Dispose() { coll = null; rad16 = null; }
+ [Test]
+ public void Format()
+ {
+ Assert.AreEqual("{{ }}", coll.ToString());
+ coll.AddAll<int>(new int[] { -4, 28, 129, 65530, -4, 28 });
+ Assert.AreEqual("{{ -4(*2), 28(*2), 129(*1), 65530(*1) }}", coll.ToString());
+ Assert.AreEqual("{{ -4(*2), 1C(*2), 81(*1), FFFA(*1) }}", coll.ToString(null, rad16));
+ Assert.AreEqual("{{ -4(*2), 28(*2)... }}", coll.ToString("L18", null));
+ Assert.AreEqual("{{ -4(*2), 1C(*2)... }}", coll.ToString("L18", rad16));
+ }
+ }
+
+ [TestFixture]
+ public class Combined
+ {
+ private IIndexedSorted<KeyValuePair<int, int>> lst;
+
+
+ [SetUp]
+ public void Init()
+ {
+ lst = new TreeBag<KeyValuePair<int, int>>(new KeyValuePairComparer<int, int>(new IC()));
+ for (int i = 0; i < 10; i++)
+ lst.Add(new KeyValuePair<int, int>(i, i + 30));
+ }
+
+
+ [TearDown]
+ public void Dispose() { lst = null; }
+
+
+ [Test]
+ public void Find()
+ {
+ KeyValuePair<int, int> p = new KeyValuePair<int, int>(3, 78);
+
+ Assert.IsTrue(lst.Find(ref p));
+ Assert.AreEqual(3, p.Key);
+ Assert.AreEqual(33, p.Value);
+ p = new KeyValuePair<int, int>(13, 78);
+ Assert.IsFalse(lst.Find(ref p));
+ }
+
+
+ [Test]
+ public void FindOrAdd()
+ {
+ KeyValuePair<int, int> p = new KeyValuePair<int, int>(3, 78);
+
+ Assert.IsTrue(lst.FindOrAdd(ref p));
+ Assert.AreEqual(3, p.Key);
+ Assert.AreEqual(33, p.Value);
+ p = new KeyValuePair<int, int>(13, 79);
+ Assert.IsFalse(lst.FindOrAdd(ref p));
+ Assert.AreEqual(13, lst[11].Key);
+ Assert.AreEqual(79, lst[11].Value);
+ }
+
+
+ [Test]
+ public void Update()
+ {
+ KeyValuePair<int, int> p = new KeyValuePair<int, int>(3, 78);
+
+ Assert.IsTrue(lst.Update(p));
+ Assert.AreEqual(3, lst[3].Key);
+ Assert.AreEqual(78, lst[3].Value);
+ p = new KeyValuePair<int, int>(13, 78);
+ Assert.IsFalse(lst.Update(p));
+ }
+
+
+ [Test]
+ public void UpdateOrAdd()
+ {
+ KeyValuePair<int, int> p = new KeyValuePair<int, int>(3, 78);
+
+ Assert.IsTrue(lst.UpdateOrAdd(p));
+ Assert.AreEqual(3, lst[3].Key);
+ Assert.AreEqual(78, lst[3].Value);
+ p = new KeyValuePair<int, int>(13, 79);
+ Assert.IsFalse(lst.UpdateOrAdd(p));
+ Assert.AreEqual(13, lst[10].Key);
+ Assert.AreEqual(79, lst[10].Value);
+ }
+
+
+ [Test]
+ public void RemoveWithReturn()
+ {
+ KeyValuePair<int, int> p = new KeyValuePair<int, int>(3, 78);
+
+ Assert.IsTrue(lst.Remove(p, out p));
+ Assert.AreEqual(3, p.Key);
+ Assert.AreEqual(33, p.Value);
+ Assert.AreEqual(4, lst[3].Key);
+ Assert.AreEqual(34, lst[3].Value);
+ p = new KeyValuePair<int, int>(13, 78);
+ Assert.IsFalse(lst.Remove(p, out p));
+ }
+ }
+
+
+ [TestFixture]
+ public class Simple
+ {
+ private TreeBag<string> bag;
+
+
+ [SetUp]
+ public void Init()
+ {
+ bag = new TreeBag<string>(new SC());
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ bag = null;
+ }
+
+ [Test]
+ public void Initial()
+ {
+ bool res;
+
+ Assert.IsFalse(bag.IsReadOnly);
+ Assert.AreEqual(0, bag.Count, "new bag should be empty");
+ Assert.AreEqual(0, bag.ContainsCount("A"));
+ Assert.AreEqual(0, bag.ContainsCount("B"));
+ Assert.AreEqual(0, bag.ContainsCount("C"));
+ Assert.IsFalse(bag.Contains("A"));
+ Assert.IsFalse(bag.Contains("B"));
+ Assert.IsFalse(bag.Contains("C"));
+ bag.Add("A");
+ Assert.AreEqual(1, bag.Count);
+ Assert.AreEqual(1, bag.ContainsCount("A"));
+ Assert.AreEqual(0, bag.ContainsCount("B"));
+ Assert.AreEqual(0, bag.ContainsCount("C"));
+ Assert.IsTrue(bag.Contains("A"));
+ Assert.IsFalse(bag.Contains("B"));
+ Assert.IsFalse(bag.Contains("C"));
+ bag.Add("C");
+ Assert.AreEqual(2, bag.Count);
+ Assert.AreEqual(1, bag.ContainsCount("A"));
+ Assert.AreEqual(0, bag.ContainsCount("B"));
+ Assert.AreEqual(1, bag.ContainsCount("C"));
+ Assert.IsTrue(bag.Contains("A"));
+ Assert.IsFalse(bag.Contains("B"));
+ Assert.IsTrue(bag.Contains("C"));
+ bag.Add("C");
+ Assert.AreEqual(3, bag.Count);
+ Assert.AreEqual(1, bag.ContainsCount("A"));
+ Assert.AreEqual(0, bag.ContainsCount("B"));
+ Assert.AreEqual(2, bag.ContainsCount("C"));
+ Assert.IsTrue(bag.Contains("A"));
+ Assert.IsFalse(bag.Contains("B"));
+ Assert.IsTrue(bag.Contains("C"));
+ bag.Add("B");
+ bag.Add("C");
+ Assert.AreEqual(5, bag.Count);
+ Assert.AreEqual(1, bag.ContainsCount("A"));
+ Assert.AreEqual(1, bag.ContainsCount("B"));
+ Assert.AreEqual(3, bag.ContainsCount("C"));
+ Assert.IsTrue(bag.Contains("A"));
+ Assert.IsTrue(bag.Contains("B"));
+ Assert.IsTrue(bag.Contains("C"));
+ res = bag.Remove("C");
+ Assert.AreEqual(4, bag.Count);
+ Assert.AreEqual(1, bag.ContainsCount("A"));
+ Assert.AreEqual(1, bag.ContainsCount("B"));
+ Assert.AreEqual(2, bag.ContainsCount("C"));
+ Assert.IsTrue(bag.Contains("A"));
+ Assert.IsTrue(bag.Contains("B"));
+ Assert.IsTrue(bag.Contains("C"));
+ res = bag.Remove("A");
+ Assert.AreEqual(3, bag.Count);
+ Assert.AreEqual(0, bag.ContainsCount("A"));
+ Assert.AreEqual(1, bag.ContainsCount("B"));
+ Assert.AreEqual(2, bag.ContainsCount("C"));
+ Assert.IsFalse(bag.Contains("A"));
+ Assert.IsTrue(bag.Contains("B"));
+ Assert.IsTrue(bag.Contains("C"));
+ bag.RemoveAllCopies("C");
+ Assert.AreEqual(1, bag.Count);
+ Assert.AreEqual(0, bag.ContainsCount("A"));
+ Assert.AreEqual(1, bag.ContainsCount("B"));
+ Assert.AreEqual(0, bag.ContainsCount("C"));
+ Assert.IsFalse(bag.Contains("A"));
+ Assert.IsTrue(bag.Contains("B"));
+ Assert.IsFalse(bag.Contains("C"));
+ Assert.IsFalse(bag.Contains("Z"));
+ Assert.IsFalse(bag.Remove("Z"));
+ bag.RemoveAllCopies("Z");
+ Assert.AreEqual(1, bag.Count);
+ Assert.AreEqual(0, bag.ContainsCount("A"));
+ Assert.AreEqual(1, bag.ContainsCount("B"));
+ Assert.AreEqual(0, bag.ContainsCount("C"));
+ Assert.IsFalse(bag.Contains("A"));
+ Assert.IsTrue(bag.Contains("B"));
+ Assert.IsFalse(bag.Contains("C"));
+ Assert.IsFalse(bag.Contains("Z"));
+ }
+ }
+
+ [TestFixture]
+ public class FindOrAdd
+ {
+ private TreeBag<KeyValuePair<int, string>> bag;
+
+
+ [SetUp]
+ public void Init()
+ {
+ bag = new TreeBag<KeyValuePair<int, string>>(new KeyValuePairComparer<int, string>(new IC()));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ bag = null;
+ }
+
+
+ [Test]
+ public void Test()
+ {
+ KeyValuePair<int, string> p = new KeyValuePair<int, string>(3, "tre");
+ Assert.IsFalse(bag.FindOrAdd(ref p));
+ p.Value = "drei";
+ Assert.IsTrue(bag.FindOrAdd(ref p));
+ Assert.AreEqual("tre", p.Value);
+ p.Value = "three";
+ Assert.AreEqual(2, bag.ContainsCount(p));
+ Assert.AreEqual("tre", bag[0].Value);
+ }
+ }
+
+
+ [TestFixture]
+ public class Enumerators
+ {
+ private TreeBag<string> bag;
+
+ private SCG.IEnumerator<string> bagenum;
+
+
+ [SetUp]
+ public void Init()
+ {
+ bag = new TreeBag<string>(new SC());
+ foreach (string s in new string[] { "A", "B", "A", "A", "B", "C", "D", "B" })
+ bag.Add(s);
+
+ bagenum = bag.GetEnumerator();
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ bagenum = null;
+ bag = null;
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void MoveNextOnModified()
+ {
+ //TODO: also problem before first MoveNext!!!!!!!!!!
+ bagenum.MoveNext();
+ bag.Add("T");
+ bagenum.MoveNext();
+ }
+
+
+ [Test]
+ public void NormalUse()
+ {
+ Assert.IsTrue(bagenum.MoveNext());
+ Assert.AreEqual(bagenum.Current, "A");
+ Assert.IsTrue(bagenum.MoveNext());
+ Assert.AreEqual(bagenum.Current, "A");
+ Assert.IsTrue(bagenum.MoveNext());
+ Assert.AreEqual(bagenum.Current, "A");
+ Assert.IsTrue(bagenum.MoveNext());
+ Assert.AreEqual(bagenum.Current, "B");
+ Assert.IsTrue(bagenum.MoveNext());
+ Assert.AreEqual(bagenum.Current, "B");
+ Assert.IsTrue(bagenum.MoveNext());
+ Assert.AreEqual(bagenum.Current, "B");
+ Assert.IsTrue(bagenum.MoveNext());
+ Assert.AreEqual(bagenum.Current, "C");
+ Assert.IsTrue(bagenum.MoveNext());
+ Assert.AreEqual(bagenum.Current, "D");
+ Assert.IsFalse(bagenum.MoveNext());
+ }
+ }
+
+ [TestFixture]
+ public class Ranges
+ {
+ private TreeBag<int> tree;
+
+ private SCG.IComparer<int> c;
+
+
+ [SetUp]
+ public void Init()
+ {
+ c = new IC();
+ tree = new TreeBag<int>(c);
+ for (int i = 1; i <= 10; i++)
+ {
+ tree.Add(i * 2); tree.Add(i);
+ }
+ }
+
+
+ [Test]
+ public void Enumerator()
+ {
+ SCG.IEnumerator<int> e = tree.RangeFromTo(5, 17).GetEnumerator();
+ int i = 0;
+ int[] all = new int[] { 5, 6, 6, 7, 8, 8, 9, 10, 10, 12, 14, 16 };
+ while (e.MoveNext())
+ {
+ Assert.AreEqual(all[i++], e.Current);
+ }
+
+ Assert.AreEqual(12, i);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(InvalidOperationException))]
+ public void Enumerator2()
+ {
+ SCG.IEnumerator<int> e = tree.RangeFromTo(5, 17).GetEnumerator();
+ int i = e.Current;
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(InvalidOperationException))]
+ public void Enumerator3()
+ {
+ SCG.IEnumerator<int> e = tree.RangeFromTo(5, 17).GetEnumerator();
+
+ while (e.MoveNext()) ;
+
+ int i = e.Current;
+ }
+
+
+ [Test]
+ public void Remove()
+ {
+ int[] all = new int[] { 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 10, 10, 12, 14, 16, 18, 20 };
+
+ tree.RemoveRangeFrom(18);
+ Assert.IsTrue(IC.eq(tree, new int[] { 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 10, 10, 12, 14, 16 }));
+ tree.RemoveRangeFrom(28);
+ Assert.IsTrue(IC.eq(tree, new int[] { 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 10, 10, 12, 14, 16 }));
+ tree.RemoveRangeFrom(1);
+ Assert.IsTrue(IC.eq(tree));
+ foreach (int i in all) tree.Add(i);
+
+ tree.RemoveRangeTo(10);
+ Assert.IsTrue(IC.eq(tree, new int[] { 10, 10, 12, 14, 16, 18, 20 }));
+ tree.RemoveRangeTo(2);
+ Assert.IsTrue(IC.eq(tree, new int[] { 10, 10, 12, 14, 16, 18, 20 }));
+ tree.RemoveRangeTo(21);
+ Assert.IsTrue(IC.eq(tree));
+ foreach (int i in all) tree.Add(i);
+
+ tree.RemoveRangeFromTo(4, 8);
+ Assert.IsTrue(IC.eq(tree, 1, 2, 2, 3, 8, 8, 9, 10, 10, 12, 14, 16, 18, 20));
+ tree.RemoveRangeFromTo(14, 28);
+ Assert.IsTrue(IC.eq(tree, 1, 2, 2, 3, 8, 8, 9, 10, 10, 12));
+ tree.RemoveRangeFromTo(0, 9);
+ Assert.IsTrue(IC.eq(tree, 9, 10, 10, 12));
+ tree.RemoveRangeFromTo(0, 81);
+ Assert.IsTrue(IC.eq(tree));
+ }
+
+
+ [Test]
+ public void Normal()
+ {
+ int[] all = new int[] { 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 10, 10, 12, 14, 16, 18, 20 };
+
+ Assert.IsTrue(IC.eq(tree, all));
+ Assert.IsTrue(IC.eq(tree.RangeAll(), all));
+ Assert.AreEqual(20, tree.RangeAll().Count);
+ Assert.IsTrue(IC.eq(tree.RangeFrom(11), new int[] { 12, 14, 16, 18, 20 }));
+ Assert.AreEqual(5, tree.RangeFrom(11).Count);
+ Assert.IsTrue(IC.eq(tree.RangeFrom(12), new int[] { 12, 14, 16, 18, 20 }));
+ Assert.IsTrue(IC.eq(tree.RangeFrom(1), all));
+ Assert.IsTrue(IC.eq(tree.RangeFrom(0), all));
+ Assert.IsTrue(IC.eq(tree.RangeFrom(21), new int[] { }));
+ Assert.IsTrue(IC.eq(tree.RangeFrom(20), new int[] { 20 }));
+ Assert.IsTrue(IC.eq(tree.RangeTo(8), new int[] { 1, 2, 2, 3, 4, 4, 5, 6, 6, 7 }));
+ Assert.IsTrue(IC.eq(tree.RangeTo(7), new int[] { 1, 2, 2, 3, 4, 4, 5, 6, 6 }));
+ Assert.AreEqual(9, tree.RangeTo(7).Count);
+ Assert.IsTrue(IC.eq(tree.RangeTo(1), new int[] { }));
+ Assert.IsTrue(IC.eq(tree.RangeTo(0), new int[] { }));
+ Assert.IsTrue(IC.eq(tree.RangeTo(3), new int[] { 1, 2, 2 }));
+ Assert.IsTrue(IC.eq(tree.RangeTo(20), new int[] { 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 10, 10, 12, 14, 16, 18 }));
+ Assert.IsTrue(IC.eq(tree.RangeTo(21), all));
+ Assert.IsTrue(IC.eq(tree.RangeFromTo(7, 12), new int[] { 7, 8, 8, 9, 10, 10 }));
+ Assert.IsTrue(IC.eq(tree.RangeFromTo(6, 11), new int[] { 6, 6, 7, 8, 8, 9, 10, 10 }));
+ Assert.IsTrue(IC.eq(tree.RangeFromTo(1, 12), new int[] { 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 10, 10 }));
+ Assert.AreEqual(15, tree.RangeFromTo(1, 12).Count);
+ Assert.IsTrue(IC.eq(tree.RangeFromTo(2, 12), new int[] { 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 10, 10 }));
+ Assert.IsTrue(IC.eq(tree.RangeFromTo(6, 21), new int[] { 6, 6, 7, 8, 8, 9, 10, 10, 12, 14, 16, 18, 20 }));
+ Assert.IsTrue(IC.eq(tree.RangeFromTo(6, 20), new int[] { 6, 6, 7, 8, 8, 9, 10, 10, 12, 14, 16, 18 }));
+ }
+
+
+ [Test]
+ public void Backwards()
+ {
+ int[] all = new int[] { 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 10, 10, 12, 14, 16, 18, 20 };
+ int[] lla = new int[] { 20, 18, 16, 14, 12, 10, 10, 9, 8, 8, 7, 6, 6, 5, 4, 4, 3, 2, 2, 1 };
+
+ Assert.IsTrue(IC.eq(tree, all));
+ Assert.IsTrue(IC.eq(tree.RangeAll().Backwards(), lla));
+ Assert.IsTrue(IC.eq(tree.RangeFrom(11).Backwards(), new int[] { 20, 18, 16, 14, 12 }));
+ Assert.IsTrue(IC.eq(tree.RangeFrom(12).Backwards(), new int[] { 20, 18, 16, 14, 12 }));
+ Assert.IsTrue(IC.eq(tree.RangeFrom(1).Backwards(), lla));
+ Assert.IsTrue(IC.eq(tree.RangeFrom(0).Backwards(), lla));
+ Assert.IsTrue(IC.eq(tree.RangeFrom(21).Backwards(), new int[] { }));
+ Assert.IsTrue(IC.eq(tree.RangeFrom(20).Backwards(), new int[] { 20 }));
+ Assert.IsTrue(IC.eq(tree.RangeTo(8).Backwards(), new int[] { 7, 6, 6, 5, 4, 4, 3, 2, 2, 1 }));
+ Assert.IsTrue(IC.eq(tree.RangeTo(7).Backwards(), new int[] { 6, 6, 5, 4, 4, 3, 2, 2, 1 }));
+ Assert.IsTrue(IC.eq(tree.RangeTo(1).Backwards(), new int[] { }));
+ Assert.IsTrue(IC.eq(tree.RangeTo(0).Backwards(), new int[] { }));
+ Assert.IsTrue(IC.eq(tree.RangeTo(3).Backwards(), new int[] { 2, 2, 1 }));
+ Assert.IsTrue(IC.eq(tree.RangeTo(20).Backwards(), new int[] { 18, 16, 14, 12, 10, 10, 9, 8, 8, 7, 6, 6, 5, 4, 4, 3, 2, 2, 1 }));
+ Assert.IsTrue(IC.eq(tree.RangeTo(21).Backwards(), lla));
+ Assert.IsTrue(IC.eq(tree.RangeFromTo(7, 12).Backwards(), new int[] { 10, 10, 9, 8, 8, 7 }));
+ Assert.IsTrue(IC.eq(tree.RangeFromTo(6, 11).Backwards(), new int[] { 10, 10, 9, 8, 8, 7, 6, 6 }));
+ Assert.IsTrue(IC.eq(tree.RangeFromTo(0, 12).Backwards(), new int[] { 10, 10, 9, 8, 8, 7, 6, 6, 5, 4, 4, 3, 2, 2, 1 }));
+ Assert.IsTrue(IC.eq(tree.RangeFromTo(1, 12).Backwards(), new int[] { 10, 10, 9, 8, 8, 7, 6, 6, 5, 4, 4, 3, 2, 2, 1 }));
+ Assert.IsTrue(IC.eq(tree.RangeFromTo(6, 21).Backwards(), new int[] { 20, 18, 16, 14, 12, 10, 10, 9, 8, 8, 7, 6, 6 }));
+ Assert.IsTrue(IC.eq(tree.RangeFromTo(6, 20).Backwards(), new int[] { 18, 16, 14, 12, 10, 10, 9, 8, 8, 7, 6, 6 }));
+ }
+
+
+ [Test]
+ public void Direction()
+ {
+ Assert.AreEqual(EnumerationDirection.Forwards, tree.Direction);
+ Assert.AreEqual(EnumerationDirection.Forwards, tree.RangeFrom(20).Direction);
+ Assert.AreEqual(EnumerationDirection.Forwards, tree.RangeTo(7).Direction);
+ Assert.AreEqual(EnumerationDirection.Forwards, tree.RangeFromTo(1, 12).Direction);
+ Assert.AreEqual(EnumerationDirection.Forwards, tree.RangeAll().Direction);
+ Assert.AreEqual(EnumerationDirection.Backwards, tree.Backwards().Direction);
+ Assert.AreEqual(EnumerationDirection.Backwards, tree.RangeFrom(20).Backwards().Direction);
+ Assert.AreEqual(EnumerationDirection.Backwards, tree.RangeTo(7).Backwards().Direction);
+ Assert.AreEqual(EnumerationDirection.Backwards, tree.RangeFromTo(1, 12).Backwards().Direction);
+ Assert.AreEqual(EnumerationDirection.Backwards, tree.RangeAll().Backwards().Direction);
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ tree = null;
+ c = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class BagItf
+ {
+ private TreeBag<int> tree;
+
+
+ [SetUp]
+ public void Init()
+ {
+ tree = new TreeBag<int>(new IC());
+ for (int i = 10; i < 20; i++)
+ {
+ tree.Add(i);
+ tree.Add(i + 5);
+ }
+ }
+
+
+ [Test]
+ public void Both()
+ {
+ Assert.AreEqual(0, tree.ContainsCount(7));
+ Assert.AreEqual(1, tree.ContainsCount(10));
+ Assert.AreEqual(2, tree.ContainsCount(17));
+ tree.RemoveAllCopies(17);
+ Assert.AreEqual(0, tree.ContainsCount(17));
+ tree.RemoveAllCopies(7);
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ tree = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class Div
+ {
+ private TreeBag<int> tree;
+
+
+ [SetUp]
+ public void Init()
+ {
+ tree = new TreeBag<int>(new IC());
+ }
+
+
+ private void loadup()
+ {
+ for (int i = 10; i < 20; i++)
+ {
+ tree.Add(i);
+ tree.Add(i + 5);
+ }
+ }
+
+ [Test]
+ [ExpectedException(typeof(NullReferenceException))]
+ public void NullEqualityComparerinConstructor1()
+ {
+ new TreeBag<int>(null);
+ }
+
+ [Test]
+ [ExpectedException(typeof(NullReferenceException))]
+ public void NullEqualityComparerinConstructor3()
+ {
+ new TreeBag<int>(null, EqualityComparer<int>.Default);
+ }
+
+ [Test]
+ [ExpectedException(typeof(NullReferenceException))]
+ public void NullEqualityComparerinConstructor4()
+ {
+ new TreeBag<int>(Comparer<int>.Default, null);
+ }
+
+ [Test]
+ [ExpectedException(typeof(NullReferenceException))]
+ public void NullEqualityComparerinConstructor5()
+ {
+ new TreeBag<int>(null, null);
+ }
+
+ [Test]
+ public void Choose()
+ {
+ tree.Add(7);
+ Assert.AreEqual(7, tree.Choose());
+ }
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void BadChoose()
+ {
+ tree.Choose();
+ }
+
+
+ [Test]
+ public void NoDuplicates()
+ {
+ Assert.IsTrue(tree.AllowsDuplicates);
+ loadup();
+ Assert.IsTrue(tree.AllowsDuplicates);
+ }
+
+
+ [Test]
+ public void Add()
+ {
+ Assert.IsTrue(tree.Add(17));
+ Assert.IsTrue(tree.Add(17));
+ Assert.IsTrue(tree.Add(18));
+ Assert.IsTrue(tree.Add(18));
+ Assert.AreEqual(4, tree.Count);
+ Assert.IsTrue(IC.eq(tree, 17, 17, 18, 18));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ tree = null;
+ }
+ }
+
+ [TestFixture]
+ public class FindPredicate
+ {
+ private TreeBag<int> list;
+ Fun<int, bool> pred;
+
+ [SetUp]
+ public void Init()
+ {
+ list = new TreeBag<int>(TenEqualityComparer.Default);
+ pred = delegate(int i) { return i % 5 == 0; };
+ }
+
+ [TearDown]
+ public void Dispose() { list = null; }
+
+ [Test]
+ public void Find()
+ {
+ int i;
+ Assert.IsFalse(list.Find(pred, out i));
+ list.AddAll<int>(new int[] { 4, 22, 67, 37 });
+ Assert.IsFalse(list.Find(pred, out i));
+ list.AddAll<int>(new int[] { 45, 122, 675, 137 });
+ Assert.IsTrue(list.Find(pred, out i));
+ Assert.AreEqual(45, i);
+ }
+
+ [Test]
+ public void FindLast()
+ {
+ int i;
+ Assert.IsFalse(list.FindLast(pred, out i));
+ list.AddAll<int>(new int[] { 4, 22, 67, 37 });
+ Assert.IsFalse(list.FindLast(pred, out i));
+ list.AddAll<int>(new int[] { 45, 122, 675, 137 });
+ Assert.IsTrue(list.FindLast(pred, out i));
+ Assert.AreEqual(675, i);
+ }
+
+ [Test]
+ public void FindIndex()
+ {
+ Assert.IsFalse(0 <= list.FindIndex(pred));
+ list.AddAll<int>(new int[] { 4, 22, 67, 37 });
+ Assert.IsFalse(0 <= list.FindIndex(pred));
+ list.AddAll<int>(new int[] { 45, 122, 675, 137 });
+ Assert.AreEqual(3, list.FindIndex(pred));
+ }
+
+ [Test]
+ public void FindLastIndex()
+ {
+ Assert.IsFalse(0 <= list.FindLastIndex(pred));
+ list.AddAll<int>(new int[] { 4, 22, 67, 37 });
+ Assert.IsFalse(0 <= list.FindLastIndex(pred));
+ list.AddAll<int>(new int[] { 45, 122, 675, 137 });
+ Assert.AreEqual(7, list.FindLastIndex(pred));
+ }
+ }
+
+ [TestFixture]
+ public class UniqueItems
+ {
+ private TreeBag<int> list;
+
+ [SetUp]
+ public void Init() { list = new TreeBag<int>(); }
+
+ [TearDown]
+ public void Dispose() { list = null; }
+
+ [Test]
+ public void Test()
+ {
+ Assert.IsTrue(IC.seteq(list.UniqueItems()));
+ Assert.IsTrue(IC.seteq(list.ItemMultiplicities()));
+ list.AddAll<int>(new int[] { 7, 9, 7 });
+ Assert.IsTrue(IC.seteq(list.UniqueItems(), 7, 9));
+ Assert.IsTrue(IC.seteq(list.ItemMultiplicities(), 7, 2, 9, 1));
+ }
+ }
+
+ [TestFixture]
+ public class ArrayTest
+ {
+ private TreeBag<int> tree;
+
+ int[] a;
+
+
+ [SetUp]
+ public void Init()
+ {
+ tree = new TreeBag<int>(new IC());
+ a = new int[10];
+ for (int i = 0; i < 10; i++)
+ a[i] = 1000 + i;
+ }
+
+
+ [TearDown]
+ public void Dispose() { tree = null; }
+
+
+ private string aeq(int[] a, params int[] b)
+ {
+ if (a.Length != b.Length)
+ return "Lengths differ: " + a.Length + " != " + b.Length;
+
+ for (int i = 0; i < a.Length; i++)
+ if (a[i] != b[i])
+ return String.Format("{0}'th elements differ: {1} != {2}", i, a[i], b[i]);
+
+ return "Alles klar";
+ }
+
+
+ [Test]
+ public void ToArray()
+ {
+ Assert.AreEqual("Alles klar", aeq(tree.ToArray()));
+ tree.Add(4);
+ tree.Add(7);
+ tree.Add(4);
+ Assert.AreEqual("Alles klar", aeq(tree.ToArray(), 4, 4, 7));
+ }
+
+
+ [Test]
+ public void CopyTo()
+ {
+ tree.CopyTo(a, 1);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009));
+ tree.Add(6);
+ tree.Add(6);
+ tree.CopyTo(a, 2);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 6, 6, 1004, 1005, 1006, 1007, 1008, 1009));
+ tree.Add(4);
+ tree.Add(9);
+ tree.CopyTo(a, 4);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 6, 6, 4, 6, 6, 9, 1008, 1009));
+ tree.Clear();
+ tree.Add(7);
+ tree.CopyTo(a, 9);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 6, 6, 4, 6, 6, 9, 1008, 7));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void CopyToBad()
+ {
+ tree.CopyTo(a, 11);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void CopyToBad2()
+ {
+ tree.CopyTo(a, -1);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void CopyToTooFar()
+ {
+ tree.Add(3);
+ tree.Add(4);
+ tree.CopyTo(a, 9);
+ }
+ }
+
+
+
+ [TestFixture]
+ public class Remove
+ {
+ private TreeBag<int> tree;
+
+
+ [SetUp]
+ public void Init()
+ {
+ tree = new TreeBag<int>(new IC());
+ for (int i = 10; i < 20; i++)
+ {
+ tree.Add(i);
+ tree.Add(i + 5);
+ }
+ //10,11,12,13,14,15,15,16,16,17,17,18,18,19,19,20,21,22,23,24
+ }
+
+
+ [Test]
+ public void SmallTrees()
+ {
+ tree.Clear();
+ tree.Add(9);
+ tree.Add(7);
+ tree.Add(9);
+ Assert.IsTrue(tree.Remove(7));
+ Assert.IsTrue(tree.Check(""));
+ }
+
+
+ [Test]
+ public void ByIndex()
+ {
+ //Remove root!
+ int n = tree.Count;
+ int i = tree[10];
+
+ Assert.AreEqual(17, tree.RemoveAt(10));
+ Assert.IsTrue(tree.Check(""));
+ Assert.IsTrue(tree.Contains(i));
+ Assert.AreEqual(n - 1, tree.Count);
+ Assert.AreEqual(17, tree.RemoveAt(9));
+ Assert.IsTrue(tree.Check(""));
+ Assert.IsFalse(tree.Contains(i));
+ Assert.AreEqual(n - 2, tree.Count);
+
+ //Low end
+ i = tree.FindMin();
+ tree.RemoveAt(0);
+ Assert.IsTrue(tree.Check(""));
+ Assert.IsFalse(tree.Contains(i));
+ Assert.AreEqual(n - 3, tree.Count);
+
+ //high end
+ i = tree.FindMax();
+ tree.RemoveAt(tree.Count - 1);
+ Assert.IsTrue(tree.Check(""));
+ Assert.IsFalse(tree.Contains(i));
+ Assert.AreEqual(n - 4, tree.Count);
+
+ //Some leaf
+ //tree.dump();
+ i = 18;
+ Assert.AreEqual(i, tree.RemoveAt(9));
+ Assert.IsTrue(tree.Check(""));
+ Assert.AreEqual(i, tree.RemoveAt(8));
+ Assert.IsTrue(tree.Check(""));
+ Assert.IsFalse(tree.Contains(i));
+ Assert.AreEqual(n - 6, tree.Count);
+ }
+
+
+ [Test]
+ public void AlmostEmpty()
+ {
+ //Almost empty
+ tree.Clear();
+ tree.Add(3);
+ tree.RemoveAt(0);
+ Assert.IsTrue(tree.Check(""));
+ Assert.IsFalse(tree.Contains(3));
+ Assert.AreEqual(0, tree.Count);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException), "Index out of range for sequenced collectionvalue")]
+ public void Empty()
+ {
+ tree.Clear();
+ tree.RemoveAt(0);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException), "Index out of range for sequenced collectionvalue")]
+ public void HighIndex()
+ {
+ tree.RemoveAt(tree.Count);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException), "Index out of range for sequenced collectionvalue")]
+ public void LowIndex()
+ {
+ tree.RemoveAt(-1);
+ }
+
+
+ [Test]
+ public void Normal()
+ {
+ //Note: ids does not match for bag
+ Assert.IsFalse(tree.Remove(-20));
+
+ //1b
+ Assert.IsTrue(tree.Remove(20));
+ Assert.IsTrue(tree.Check("T1"));
+ Assert.IsFalse(tree.Remove(20));
+
+ //1b
+ Assert.IsTrue(tree.Remove(10));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+
+ //case 1c
+ Assert.IsTrue(tree.Remove(24));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+
+ //1a (terminating)
+ Assert.IsTrue(tree.Remove(16));
+ Assert.IsTrue(tree.Remove(16));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+
+ //2
+ Assert.IsTrue(tree.Remove(18));
+ Assert.IsTrue(tree.Remove(17));
+ Assert.IsTrue(tree.Remove(18));
+ Assert.IsTrue(tree.Remove(17));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+
+ //2+1b
+ Assert.IsTrue(tree.Remove(15));
+ Assert.IsTrue(tree.Remove(15));
+ for (int i = 0; i < 5; i++) tree.Add(17 + i);
+ Assert.IsTrue(tree.Remove(23));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+
+ //1a+1b
+ Assert.IsTrue(tree.Remove(11));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+
+ //2+1c
+ for (int i = 0; i < 10; i++)
+ tree.Add(50 - 2 * i);
+
+ Assert.IsTrue(tree.Remove(42));
+ Assert.IsTrue(tree.Remove(38));
+ Assert.IsTrue(tree.Remove(22));
+ Assert.IsTrue(tree.Remove(40));
+
+ //
+ for (int i = 0; i < 48; i++)
+ tree.Remove(i);
+
+ //Almost empty tree:*
+ Assert.IsFalse(tree.Remove(26));
+ Assert.IsTrue(tree.Remove(48));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+
+ //Empty tree:*
+ Assert.IsFalse(tree.Remove(26));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ tree = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class PredecessorStructure
+ {
+ private TreeBag<int> tree;
+
+
+ [SetUp]
+ public void Init()
+ {
+ tree = new TreeBag<int>(new IC());
+ }
+
+
+ private void loadup()
+ {
+ for (int i = 0; i < 20; i++)
+ tree.Add(2 * i);
+ for (int i = 0; i < 10; i++)
+ tree.Add(4 * i);
+ }
+
+
+ [Test]
+ public void Predecessor()
+ {
+ loadup();
+ Assert.AreEqual(6, tree.Predecessor(7));
+ Assert.AreEqual(6, tree.Predecessor(8));
+
+ //The bottom
+ Assert.AreEqual(0, tree.Predecessor(1));
+
+ //The top
+ Assert.AreEqual(38, tree.Predecessor(39));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void PredecessorTooLow1()
+ {
+ tree.Predecessor(-2);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void PredecessorTooLow2()
+ {
+ tree.Predecessor(0);
+ }
+
+
+ [Test]
+ public void WeakPredecessor()
+ {
+ loadup();
+ Assert.AreEqual(6, tree.WeakPredecessor(7));
+ Assert.AreEqual(8, tree.WeakPredecessor(8));
+
+ //The bottom
+ Assert.AreEqual(0, tree.WeakPredecessor(1));
+ Assert.AreEqual(0, tree.WeakPredecessor(0));
+
+ //The top
+ Assert.AreEqual(38, tree.WeakPredecessor(39));
+ Assert.AreEqual(38, tree.WeakPredecessor(38));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void WeakPredecessorTooLow1()
+ {
+ tree.WeakPredecessor(-2);
+ }
+
+
+ [Test]
+ public void Successor()
+ {
+ loadup();
+ Assert.AreEqual(8, tree.Successor(7));
+ Assert.AreEqual(10, tree.Successor(8));
+
+ //The bottom
+ Assert.AreEqual(2, tree.Successor(0));
+ Assert.AreEqual(0, tree.Successor(-1));
+
+ //The top
+ Assert.AreEqual(38, tree.Successor(37));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void SuccessorTooHigh1()
+ {
+ tree.Successor(38);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void SuccessorTooHigh2()
+ {
+ tree.Successor(39);
+ }
+
+
+ [Test]
+ public void WeakSuccessor()
+ {
+ loadup();
+ Assert.AreEqual(6, tree.WeakSuccessor(6));
+ Assert.AreEqual(8, tree.WeakSuccessor(7));
+
+ //The bottom
+ Assert.AreEqual(0, tree.WeakSuccessor(-1));
+ Assert.AreEqual(0, tree.WeakSuccessor(0));
+
+ //The top
+ Assert.AreEqual(38, tree.WeakSuccessor(37));
+ Assert.AreEqual(38, tree.WeakSuccessor(38));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void WeakSuccessorTooHigh1()
+ {
+ tree.WeakSuccessor(39);
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ tree = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class PriorityQueue
+ {
+ private TreeBag<int> tree;
+
+
+ [SetUp]
+ public void Init()
+ {
+ tree = new TreeBag<int>(new IC());
+ }
+
+
+ private void loadup()
+ {
+ foreach (int i in new int[] { 1, 2, 3, 4 })
+ tree.Add(i);
+ tree.Add(1);
+ tree.Add(3);
+ }
+
+
+ [Test]
+ public void Normal()
+ {
+ loadup();
+ Assert.AreEqual(1, tree.FindMin());
+ Assert.AreEqual(4, tree.FindMax());
+ Assert.AreEqual(1, tree.DeleteMin());
+ Assert.AreEqual(4, tree.DeleteMax());
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+ Assert.AreEqual(1, tree.FindMin());
+ Assert.AreEqual(3, tree.FindMax());
+ Assert.AreEqual(1, tree.DeleteMin());
+ Assert.AreEqual(3, tree.DeleteMax());
+ Assert.IsTrue(tree.Check("Normal test 2"), "Bad tree");
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void Empty1()
+ {
+ tree.FindMin();
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void Empty2()
+ {
+ tree.FindMax();
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void Empty3()
+ {
+ tree.DeleteMin();
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void Empty4()
+ {
+ tree.DeleteMax();
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ tree = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class IndexingAndCounting
+ {
+ private TreeBag<int> tree;
+
+
+ [SetUp]
+ public void Init()
+ {
+ tree = new TreeBag<int>(new IC());
+ }
+
+
+ private void populate()
+ {
+ tree.Add(30);
+ tree.Add(30);
+ tree.Add(50);
+ tree.Add(10);
+ tree.Add(70);
+ tree.Add(70);
+ }
+
+
+ [Test]
+ public void ToArray()
+ {
+ populate();
+
+ int[] a = tree.ToArray();
+
+ Assert.AreEqual(6, a.Length);
+ Assert.AreEqual(10, a[0]);
+ Assert.AreEqual(30, a[1]);
+ Assert.AreEqual(30, a[2]);
+ Assert.AreEqual(50, a[3]);
+ Assert.AreEqual(70, a[4]);
+ Assert.AreEqual(70, a[5]);
+ }
+
+
+ [Test]
+ public void GoodIndex()
+ {
+ Assert.AreEqual(-1, tree.IndexOf(20));
+ Assert.AreEqual(-1, tree.LastIndexOf(20));
+ populate();
+ Assert.AreEqual(10, tree[0]);
+ Assert.AreEqual(30, tree[1]);
+ Assert.AreEqual(30, tree[2]);
+ Assert.AreEqual(50, tree[3]);
+ Assert.AreEqual(70, tree[4]);
+ Assert.AreEqual(70, tree[5]);
+ Assert.AreEqual(0, tree.IndexOf(10));
+ Assert.AreEqual(1, tree.IndexOf(30));
+ Assert.AreEqual(3, tree.IndexOf(50));
+ Assert.AreEqual(4, tree.IndexOf(70));
+ Assert.AreEqual(~1, tree.IndexOf(20));
+ Assert.AreEqual(~0, tree.IndexOf(0));
+ Assert.AreEqual(~6, tree.IndexOf(90));
+ Assert.AreEqual(0, tree.LastIndexOf(10));
+ Assert.AreEqual(2, tree.LastIndexOf(30));
+ Assert.AreEqual(3, tree.LastIndexOf(50));
+ Assert.AreEqual(5, tree.LastIndexOf(70));
+ Assert.AreEqual(~1, tree.LastIndexOf(20));
+ Assert.AreEqual(~0, tree.LastIndexOf(0));
+ Assert.AreEqual(~6, tree.LastIndexOf(90));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void IndexTooLarge()
+ {
+ populate();
+ Console.WriteLine(tree[6]);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void IndexTooSmall()
+ {
+ populate();
+ Console.WriteLine(tree[-1]);
+ }
+
+
+ [Test]
+ public void FilledTreeOutsideInput()
+ {
+ populate();
+ Assert.AreEqual(0, tree.CountFrom(90));
+ Assert.AreEqual(0, tree.CountFromTo(-20, 0));
+ Assert.AreEqual(0, tree.CountFromTo(80, 100));
+ Assert.AreEqual(0, tree.CountTo(0));
+ Assert.AreEqual(6, tree.CountTo(90));
+ Assert.AreEqual(6, tree.CountFromTo(-20, 90));
+ Assert.AreEqual(6, tree.CountFrom(0));
+ }
+
+
+ [Test]
+ public void FilledTreeIntermediateInput()
+ {
+ populate();
+ Assert.AreEqual(5, tree.CountFrom(20));
+ Assert.AreEqual(2, tree.CountFromTo(20, 40));
+ Assert.AreEqual(3, tree.CountTo(40));
+ }
+
+
+ [Test]
+ public void FilledTreeMatchingInput()
+ {
+ populate();
+ Assert.AreEqual(5, tree.CountFrom(30));
+ Assert.AreEqual(3, tree.CountFromTo(30, 70));
+ Assert.AreEqual(0, tree.CountFromTo(50, 30));
+ Assert.AreEqual(0, tree.CountFromTo(50, 50));
+ Assert.AreEqual(0, tree.CountTo(10));
+ Assert.AreEqual(3, tree.CountTo(50));
+ }
+
+
+ [Test]
+ public void CountEmptyTree()
+ {
+ Assert.AreEqual(0, tree.CountFrom(20));
+ Assert.AreEqual(0, tree.CountFromTo(20, 40));
+ Assert.AreEqual(0, tree.CountTo(40));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ tree = null;
+ }
+ }
+
+
+
+
+ namespace ModificationCheck
+ {
+ [TestFixture]
+ public class Enumerator
+ {
+ private TreeBag<int> tree;
+
+ private SCG.IEnumerator<int> e;
+
+
+ [SetUp]
+ public void Init()
+ {
+ tree = new TreeBag<int>(new IC());
+ for (int i = 0; i < 10; i++)
+ tree.Add(i);
+ tree.Add(3);
+ tree.Add(7);
+ e = tree.GetEnumerator();
+ }
+
+
+ [Test]
+ public void CurrentAfterModification()
+ {
+ e.MoveNext();
+ tree.Add(34);
+ Assert.AreEqual(0, e.Current);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void MoveNextAfterAdd()
+ {
+ tree.Add(34);
+ e.MoveNext();
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void MoveNextAfterRemove()
+ {
+ tree.Remove(34);
+ e.MoveNext();
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void MoveNextAfterClear()
+ {
+ tree.Clear();
+ e.MoveNext();
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ tree = null;
+ e = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class RangeEnumerator
+ {
+ private TreeBag<int> tree;
+
+ private SCG.IEnumerator<int> e;
+
+
+ [SetUp]
+ public void Init()
+ {
+ tree = new TreeBag<int>(new IC());
+ for (int i = 0; i < 10; i++)
+ tree.Add(i);
+
+ e = tree.RangeFromTo(3, 7).GetEnumerator();
+ }
+
+
+ [Test]
+ public void CurrentAfterModification()
+ {
+ e.MoveNext();
+ tree.Add(34);
+ Assert.AreEqual(3, e.Current);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void MoveNextAfterAdd()
+ {
+ tree.Add(34);
+ e.MoveNext();
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void MoveNextAfterRemove()
+ {
+ tree.Remove(34);
+ e.MoveNext();
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void MoveNextAfterClear()
+ {
+ tree.Clear();
+ e.MoveNext();
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ tree = null;
+ e = null;
+ }
+ }
+ }
+
+
+
+
+ namespace PathcopyPersistence
+ {
+ [TestFixture]
+ public class Navigation
+ {
+ private TreeBag<int> tree, snap;
+
+ private SCG.IComparer<int> ic;
+
+
+ [SetUp]
+ public void Init()
+ {
+ ic = new IC();
+ tree = new TreeBag<int>(ic);
+ for (int i = 0; i <= 20; i++)
+ tree.Add(2 * i + 1);
+ tree.Add(13);
+ snap = (TreeBag<int>)tree.Snapshot();
+ for (int i = 0; i <= 10; i++)
+ tree.Remove(4 * i + 1);
+ }
+
+
+ private bool twomodeleven(int i)
+ {
+ return i % 11 == 2;
+ }
+
+
+ [Test]
+ public void InternalEnum()
+ {
+ Assert.IsTrue(IC.eq(snap.FindAll(new Fun<int, bool>(twomodeleven)), 13, 13, 35));
+ }
+
+
+ public void MoreCut()
+ {
+ //TODO: Assert.Fail("more tests of Cut needed");
+ }
+
+
+ [Test]
+ public void Cut()
+ {
+ int lo, hi;
+ bool lv, hv;
+
+ Assert.IsFalse(snap.Cut(new HigherOrder.CubeRoot(64), out lo, out lv, out hi, out hv));
+ Assert.IsTrue(lv && hv);
+ Assert.AreEqual(5, hi);
+ Assert.AreEqual(3, lo);
+ Assert.IsTrue(snap.Cut(new HigherOrder.CubeRoot(125), out lo, out lv, out hi, out hv));
+ Assert.IsTrue(lv && hv);
+ Assert.AreEqual(7, hi);
+ Assert.AreEqual(3, lo);
+ Assert.IsFalse(snap.Cut(new HigherOrder.CubeRoot(125000), out lo, out lv, out hi, out hv));
+ Assert.IsTrue(lv && !hv);
+ Assert.AreEqual(41, lo);
+ Assert.IsFalse(snap.Cut(new HigherOrder.CubeRoot(-27), out lo, out lv, out hi, out hv));
+ Assert.IsTrue(!lv && hv);
+ Assert.AreEqual(1, hi);
+ }
+
+
+ [Test]
+ public void Range()
+ {
+ Assert.IsTrue(IC.eq(snap.RangeFromTo(5, 16), 5, 7, 9, 11, 13, 13, 15));
+ Assert.IsTrue(IC.eq(snap.RangeFromTo(5, 17), 5, 7, 9, 11, 13, 13, 15));
+ Assert.IsTrue(IC.eq(snap.RangeFromTo(6, 16), 7, 9, 11, 13, 13, 15));
+ }
+
+
+ [Test]
+ public void Contains()
+ {
+ Assert.IsTrue(snap.Contains(5));
+ Assert.IsTrue(snap.Contains(13));
+ Assert.AreEqual(1, snap.ContainsCount(5));
+ Assert.AreEqual(2, snap.ContainsCount(13));
+ }
+
+
+ [Test]
+ public void FindMin()
+ {
+ Assert.AreEqual(1, snap.FindMin());
+ }
+
+
+ [Test]
+ public void FindMax()
+ {
+ Assert.AreEqual(41, snap.FindMax());
+ }
+
+
+ [Test]
+ public void Predecessor()
+ {
+ Assert.AreEqual(13, snap.Predecessor(15));
+ Assert.AreEqual(15, snap.Predecessor(16));
+ Assert.AreEqual(15, snap.Predecessor(17));
+ Assert.AreEqual(17, snap.Predecessor(18));
+ }
+
+
+ [Test]
+ public void Successor()
+ {
+ Assert.AreEqual(17, snap.Successor(15));
+ Assert.AreEqual(17, snap.Successor(16));
+ Assert.AreEqual(19, snap.Successor(17));
+ Assert.AreEqual(19, snap.Successor(18));
+ }
+
+
+ [Test]
+ public void WeakPredecessor()
+ {
+ Assert.AreEqual(15, snap.WeakPredecessor(15));
+ Assert.AreEqual(15, snap.WeakPredecessor(16));
+ Assert.AreEqual(17, snap.WeakPredecessor(17));
+ Assert.AreEqual(17, snap.WeakPredecessor(18));
+ }
+
+
+ [Test]
+ public void WeakSuccessor()
+ {
+ Assert.AreEqual(15, snap.WeakSuccessor(15));
+ Assert.AreEqual(17, snap.WeakSuccessor(16));
+ Assert.AreEqual(17, snap.WeakSuccessor(17));
+ Assert.AreEqual(19, snap.WeakSuccessor(18));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NotSupportedException), "Indexing not supported for snapshots")]
+ public void CountTo()
+ {
+ int j = snap.CountTo(15);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NotSupportedException), "Indexing not supported for snapshots")]
+ public void Indexing()
+ {
+ int j = snap[4];
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NotSupportedException), "Indexing not supported for snapshots")]
+ public void Indexing2()
+ {
+ int j = snap.IndexOf(5);
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ tree = null;
+ ic = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class Single
+ {
+ private TreeBag<int> tree;
+
+ private SCG.IComparer<int> ic;
+
+
+ [SetUp]
+ public void Init()
+ {
+ ic = new IC();
+ tree = new TreeBag<int>(ic);
+ for (int i = 0; i < 10; i++)
+ tree.Add(2 * i + 1);
+ }
+
+
+ [Test]
+ public void EnumerationWithAdd()
+ {
+ int[] orig = new int[] { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 };
+ int i = 0;
+ TreeBag<int> snap = (TreeBag<int>)tree.Snapshot();
+
+ foreach (int j in snap)
+ {
+ Assert.AreEqual(1 + 2 * i++, j);
+ tree.Add(21 - j);
+ Assert.IsTrue(snap.Check("M"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+ Assert.IsTrue(tree.Check("Tree"), "Bad tree!");
+ }
+ }
+
+
+ [Test]
+ public void Remove()
+ {
+ int[] orig = new int[] { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 };
+ TreeBag<int> snap = (TreeBag<int>)tree.Snapshot();
+
+ Assert.IsTrue(snap.Check("Snap"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+ tree.Remove(19);
+ Assert.IsTrue(snap.Check("Snap"), "Bad snap!");
+ Assert.IsTrue(tree.Check("Tree"), "Bad tree!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+ }
+
+
+ [Test]
+ public void RemoveNormal()
+ {
+ tree.Clear();
+ for (int i = 10; i < 20; i++)
+ {
+ tree.Add(i);
+ tree.Add(i + 10);
+ }
+ tree.Add(15);
+
+ int[] orig = new int[] { 10, 11, 12, 13, 14, 15, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 };
+ TreeBag<int> snap = (TreeBag<int>)tree.Snapshot();
+
+ Assert.IsFalse(tree.Remove(-20));
+ Assert.IsTrue(snap.Check("Snap"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+
+
+ //decrease items case
+ Assert.IsTrue(tree.Remove(15));
+ Assert.IsTrue(tree.Check("T1"));
+ Assert.IsTrue(snap.Check("Snap"), "Bad snap!");
+ //snap.dump();
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+
+ //No demote case, with move_item
+ Assert.IsTrue(tree.Remove(20));
+ Assert.IsTrue(tree.Check("T1"));
+ Assert.IsTrue(snap.Check("Snap"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+ Assert.IsFalse(tree.Remove(20));
+
+ //plain case 2
+ tree.Snapshot();
+ Assert.IsTrue(tree.Remove(14));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+ Assert.IsTrue(snap.Check("Snap"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+
+ //case 1b
+ Assert.IsTrue(tree.Remove(25));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+ Assert.IsTrue(snap.Check("Snap"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+
+ //case 1c
+ Assert.IsTrue(tree.Remove(29));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+ Assert.IsTrue(snap.Check("Snap"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+
+ //1a (terminating)
+ Assert.IsTrue(tree.Remove(10));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+ Assert.IsTrue(snap.Check("Snap"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+
+ //2+1b
+ Assert.IsTrue(tree.Remove(12));
+ tree.Snapshot();
+ Assert.IsTrue(tree.Remove(11));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+ Assert.IsTrue(snap.Check("Snap"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+
+ //1a+1b
+ Assert.IsTrue(tree.Remove(18));
+ Assert.IsTrue(tree.Remove(13));
+ Assert.IsTrue(tree.Remove(15));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+ Assert.IsTrue(snap.Check("Snap"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+
+ //2+1c
+ for (int i = 0; i < 10; i++)
+ tree.Add(50 - 2 * i);
+
+ Assert.IsTrue(tree.Remove(42));
+ Assert.IsTrue(tree.Remove(38));
+ Assert.IsTrue(tree.Remove(28));
+ Assert.IsTrue(tree.Remove(40));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+ Assert.IsTrue(snap.Check("Snap"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+
+ //
+ Assert.IsTrue(tree.Remove(16));
+ Assert.IsTrue(tree.Remove(23));
+ Assert.IsTrue(tree.Remove(17));
+ Assert.IsTrue(tree.Remove(19));
+ Assert.IsTrue(tree.Remove(50));
+ Assert.IsTrue(tree.Remove(26));
+ Assert.IsTrue(tree.Remove(21));
+ Assert.IsTrue(tree.Remove(22));
+ Assert.IsTrue(tree.Remove(24));
+ for (int i = 0; i < 48; i++)
+ tree.Remove(i);
+
+ //Almost empty tree:
+ Assert.IsFalse(tree.Remove(26));
+ Assert.IsTrue(tree.Remove(48));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+ Assert.IsTrue(snap.Check("Snap"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+
+ //Empty tree:
+ Assert.IsFalse(tree.Remove(26));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+ Assert.IsTrue(snap.Check("Snap"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+ }
+
+
+ [Test]
+ public void Add()
+ {
+ int[] orig = new int[] { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 };
+ TreeBag<int> snap = (TreeBag<int>)tree.Snapshot();
+
+ Assert.IsTrue(snap.Check("M"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+ Assert.IsTrue(tree.Check("Tree"), "Bad tree!");
+ tree.Add(10);
+ Assert.IsTrue(snap.Check("M"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+ Assert.IsTrue(tree.Check("Tree"), "Bad tree!");
+ tree.Add(16);
+ Assert.IsTrue(snap.Check("M"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+ Assert.IsTrue(tree.Check("Tree"), "Bad tree!");
+
+ tree.Add(9);
+ Assert.IsTrue(snap.Check("M"), "Bad snap!");
+ Assert.IsTrue(tree.Check("Tree"), "Bad tree!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+
+ //Promote+zigzig
+ tree.Add(40);
+ Assert.IsTrue(snap.Check("M"), "Bad snap!");
+ Assert.IsTrue(tree.Check("Tree"), "Bad tree!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+ for (int i = 1; i < 4; i++)
+ tree.Add(40 - 2 * i);
+
+ Assert.IsTrue(snap.Check("M"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+ Assert.IsTrue(tree.Check("Tree"), "Bad tree!");
+
+ //Zigzag:
+ tree.Add(32);
+ Assert.IsTrue(snap.Check("M"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+ Assert.IsTrue(tree.Check("Tree"), "Bad tree!");
+ }
+
+
+ [Test]
+ public void Clear()
+ {
+ int[] orig = new int[] { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 };
+ TreeBag<int> snap = (TreeBag<int>)tree.Snapshot();
+
+ tree.Clear();
+ Assert.IsTrue(snap.Check("Snap"), "Bad snap!");
+ Assert.IsTrue(tree.Check("Tree"), "Bad tree!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+ Assert.AreEqual(0, tree.Count);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(InvalidOperationException), "Cannot snapshot a snapshot")]
+ public void SnapSnap()
+ {
+ TreeBag<int> snap = (TreeBag<int>)tree.Snapshot();
+
+ snap.Snapshot();
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ tree = null;
+ ic = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class Multiple
+ {
+ private TreeBag<int> tree;
+
+ private SCG.IComparer<int> ic;
+
+
+ private bool eq(SCG.IEnumerable<int> me, int[] that)
+ {
+ int i = 0, maxind = that.Length - 1;
+
+ foreach (int item in me)
+ if (i > maxind || ic.Compare(item, that[i++]) != 0)
+ return false;
+
+ return true;
+ }
+
+
+ [SetUp]
+ public void Init()
+ {
+ ic = new IC();
+ tree = new TreeBag<int>(ic);
+ for (int i = 0; i < 10; i++)
+ tree.Add(2 * i + 1);
+ }
+
+
+ [Test]
+ public void First()
+ {
+ TreeBag<int>[] snaps = new TreeBag<int>[10];
+
+ for (int i = 0; i < 10; i++)
+ {
+ snaps[i] = (TreeBag<int>)(tree.Snapshot());
+ tree.Add(2 * i);
+ }
+
+ for (int i = 0; i < 10; i++)
+ {
+ Assert.AreEqual(i + 10, snaps[i].Count);
+ }
+
+ snaps[5] = null;
+ snaps[9] = null;
+ GC.Collect();
+ snaps[8].Dispose();
+ tree.Remove(14);
+
+ int[] res = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 19 };
+ int[] snap7 = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 17, 19 };
+ int[] snap3 = new int[] { 0, 1, 2, 3, 4, 5, 7, 9, 11, 13, 15, 17, 19 };
+
+ Assert.IsTrue(IC.eq(snaps[3], snap3), "Snap 3 was changed!");
+ Assert.IsTrue(IC.eq(snaps[7], snap7), "Snap 7 was changed!");
+ Assert.IsTrue(IC.eq(tree, res));
+ Assert.IsTrue(tree.Check("B"));
+ Assert.IsTrue(snaps[3].Check("B"));
+ Assert.IsTrue(snaps[7].Check("B"));
+ }
+
+
+ [Test]
+ public void CollectingTheMaster()
+ {
+ TreeBag<int>[] snaps = new TreeBag<int>[10];
+
+ for (int i = 0; i < 10; i++)
+ {
+ snaps[i] = (TreeBag<int>)(tree.Snapshot());
+ tree.Add(2 * i);
+ }
+
+ tree = null;
+ GC.Collect();
+ for (int i = 0; i < 10; i++)
+ {
+ Assert.AreEqual(i + 10, snaps[i].Count);
+ }
+
+ snaps[5] = null;
+ snaps[9] = null;
+ GC.Collect();
+ snaps[8].Dispose();
+
+ int[] snap7 = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 17, 19 };
+ int[] snap3 = new int[] { 0, 1, 2, 3, 4, 5, 7, 9, 11, 13, 15, 17, 19 };
+
+ Assert.IsTrue(IC.eq(snaps[3], snap3), "Snap 3 was changed!");
+ Assert.IsTrue(IC.eq(snaps[7], snap7), "Snap 7 was changed!");
+ Assert.IsTrue(snaps[3].Check("B"));
+ Assert.IsTrue(snaps[7].Check("B"));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ tree = null;
+ ic = null;
+ }
+ }
+ }
+
+
+
+
+ namespace HigherOrder
+ {
+ internal class CubeRoot : IComparable<int>
+ {
+ private int c;
+
+
+ internal CubeRoot(int c) { this.c = c; }
+
+
+ public int CompareTo(int that) { return c - that * that * that; }
+ public bool Equals(int that) { return c == that * that * that; }
+ }
+
+
+
+ class Interval : IComparable<int>
+ {
+ private int b, t;
+
+
+ internal Interval(int b, int t) { this.b = b; this.t = t; }
+
+
+ public int CompareTo(int that) { return that < b ? 1 : that > t ? -1 : 0; }
+ public bool Equals(int that) { return that >= b && that <= t; }
+ }
+
+
+
+ [TestFixture]
+ public class Simple
+ {
+ private TreeBag<int> tree;
+
+ private SCG.IComparer<int> ic;
+
+
+ [SetUp]
+ public void Init()
+ {
+ ic = new IC();
+ tree = new TreeBag<int>(ic);
+ }
+
+
+ private bool never(int i) { return false; }
+
+
+ private bool always(int i) { return true; }
+
+
+ private bool even(int i) { return i % 2 == 0; }
+
+
+ private string themap(int i) { return String.Format("AA {0,4} BB", i); }
+
+
+ private string badmap(int i) { return String.Format("AA {0} BB", i); }
+
+
+ private int appfield1;
+
+ private int appfield2;
+
+
+ private void apply(int i) { appfield1++; appfield2 += i * i; }
+
+
+ [Test]
+ public void Apply()
+ {
+ Simple simple1 = new Simple();
+
+ tree.Apply(new Act<int>(simple1.apply));
+ Assert.AreEqual(0, simple1.appfield1);
+ Assert.AreEqual(0, simple1.appfield2);
+
+ Simple simple2 = new Simple();
+
+ for (int i = 0; i < 10; i++) tree.Add(i);
+ tree.Add(2);
+
+ tree.Apply(new Act<int>(simple2.apply));
+ Assert.AreEqual(11, simple2.appfield1);
+ Assert.AreEqual(289, simple2.appfield2);
+ }
+
+
+ [Test]
+ public void All()
+ {
+ Assert.IsTrue(tree.All(new Fun<int, bool>(never)));
+ Assert.IsTrue(tree.All(new Fun<int, bool>(even)));
+ Assert.IsTrue(tree.All(new Fun<int, bool>(always)));
+ for (int i = 0; i < 10; i++) tree.Add(i);
+
+ Assert.IsFalse(tree.All(new Fun<int, bool>(never)));
+ Assert.IsFalse(tree.All(new Fun<int, bool>(even)));
+ Assert.IsTrue(tree.All(new Fun<int, bool>(always)));
+ tree.Clear();
+ for (int i = 0; i < 10; i++) tree.Add(i * 2);
+
+ Assert.IsFalse(tree.All(new Fun<int, bool>(never)));
+ Assert.IsTrue(tree.All(new Fun<int, bool>(even)));
+ Assert.IsTrue(tree.All(new Fun<int, bool>(always)));
+ tree.Clear();
+ for (int i = 0; i < 10; i++) tree.Add(i * 2 + 1);
+
+ Assert.IsFalse(tree.All(new Fun<int, bool>(never)));
+ Assert.IsFalse(tree.All(new Fun<int, bool>(even)));
+ Assert.IsTrue(tree.All(new Fun<int, bool>(always)));
+ }
+
+
+ [Test]
+ public void Exists()
+ {
+ Assert.IsFalse(tree.Exists(new Fun<int, bool>(never)));
+ Assert.IsFalse(tree.Exists(new Fun<int, bool>(even)));
+ Assert.IsFalse(tree.Exists(new Fun<int, bool>(always)));
+ for (int i = 0; i < 10; i++) tree.Add(i);
+
+ Assert.IsFalse(tree.Exists(new Fun<int, bool>(never)));
+ Assert.IsTrue(tree.Exists(new Fun<int, bool>(even)));
+ Assert.IsTrue(tree.Exists(new Fun<int, bool>(always)));
+ tree.Clear();
+ for (int i = 0; i < 10; i++) tree.Add(i * 2);
+
+ Assert.IsFalse(tree.Exists(new Fun<int, bool>(never)));
+ Assert.IsTrue(tree.Exists(new Fun<int, bool>(even)));
+ Assert.IsTrue(tree.Exists(new Fun<int, bool>(always)));
+ tree.Clear();
+ for (int i = 0; i < 10; i++) tree.Add(i * 2 + 1);
+
+ Assert.IsFalse(tree.Exists(new Fun<int, bool>(never)));
+ Assert.IsFalse(tree.Exists(new Fun<int, bool>(even)));
+ Assert.IsTrue(tree.Exists(new Fun<int, bool>(always)));
+ }
+
+
+ [Test]
+ public void FindAll()
+ {
+ Assert.AreEqual(0, tree.FindAll(new Fun<int, bool>(never)).Count);
+ for (int i = 0; i < 10; i++)
+ tree.Add(i);
+ tree.Add(2);
+
+ Assert.AreEqual(0, tree.FindAll(new Fun<int, bool>(never)).Count);
+ Assert.AreEqual(11, tree.FindAll(new Fun<int, bool>(always)).Count);
+ Assert.AreEqual(6, tree.FindAll(new Fun<int, bool>(even)).Count);
+ Assert.IsTrue(((TreeBag<int>)tree.FindAll(new Fun<int, bool>(even))).Check("R"));
+ }
+
+
+ [Test]
+ public void Map()
+ {
+ Assert.AreEqual(0, tree.Map(new Fun<int, string>(themap), new SC()).Count);
+ for (int i = 0; i < 14; i++)
+ tree.Add(i * i * i);
+ tree.Add(1);
+
+ IIndexedSorted<string> res = tree.Map(new Fun<int, string>(themap), new SC());
+
+ Assert.IsTrue(((TreeBag<string>)res).Check("R"));
+ Assert.AreEqual(15, res.Count);
+ Assert.AreEqual("AA 0 BB", res[0]);
+ Assert.AreEqual("AA 1 BB", res[1]);
+ Assert.AreEqual("AA 1 BB", res[2]);
+ Assert.AreEqual("AA 8 BB", res[3]);
+ Assert.AreEqual("AA 27 BB", res[4]);
+ Assert.AreEqual("AA 125 BB", res[6]);
+ Assert.AreEqual("AA 1000 BB", res[11]);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentException), "mapper not monotonic")]
+ public void BadMap()
+ {
+ for (int i = 0; i < 11; i++)
+ tree.Add(i * i * i);
+
+ ISorted<string> res = tree.Map(new Fun<int, string>(badmap), new SC());
+ }
+
+
+ [Test]
+ public void Cut()
+ {
+ for (int i = 0; i < 10; i++)
+ tree.Add(i);
+ tree.Add(3);
+
+ int low, high;
+ bool lval, hval;
+
+ Assert.IsTrue(tree.Cut(new CubeRoot(27), out low, out lval, out high, out hval));
+ Assert.IsTrue(lval && hval);
+ Assert.AreEqual(4, high);
+ Assert.AreEqual(2, low);
+ Assert.IsFalse(tree.Cut(new CubeRoot(30), out low, out lval, out high, out hval));
+ Assert.IsTrue(lval && hval);
+ Assert.AreEqual(4, high);
+ Assert.AreEqual(3, low);
+ }
+
+
+ [Test]
+ public void CutInt()
+ {
+ for (int i = 0; i < 10; i++)
+ tree.Add(2 * i);
+
+ int low, high;
+ bool lval, hval;
+
+ Assert.IsFalse(tree.Cut(new IC(3), out low, out lval, out high, out hval));
+ Assert.IsTrue(lval && hval);
+ Assert.AreEqual(4, high);
+ Assert.AreEqual(2, low);
+ Assert.IsTrue(tree.Cut(new IC(6), out low, out lval, out high, out hval));
+ Assert.IsTrue(lval && hval);
+ Assert.AreEqual(8, high);
+ Assert.AreEqual(4, low);
+ }
+
+
+ [Test]
+ public void CutInterval()
+ {
+ for (int i = 0; i < 10; i++)
+ tree.Add(2 * i);
+
+ int lo, hi;
+ bool lv, hv;
+
+ Assert.IsTrue(tree.Cut(new Interval(5, 9), out lo, out lv, out hi, out hv));
+ Assert.IsTrue(lv && hv);
+ Assert.AreEqual(10, hi);
+ Assert.AreEqual(4, lo);
+ Assert.IsTrue(tree.Cut(new Interval(6, 10), out lo, out lv, out hi, out hv));
+ Assert.IsTrue(lv && hv);
+ Assert.AreEqual(12, hi);
+ Assert.AreEqual(4, lo);
+ for (int i = 0; i < 100; i++)
+ tree.Add(2 * i);
+
+ tree.Cut(new Interval(77, 105), out lo, out lv, out hi, out hv);
+ Assert.IsTrue(lv && hv);
+ Assert.AreEqual(106, hi);
+ Assert.AreEqual(76, lo);
+ tree.Cut(new Interval(5, 7), out lo, out lv, out hi, out hv);
+ Assert.IsTrue(lv && hv);
+ Assert.AreEqual(8, hi);
+ Assert.AreEqual(4, lo);
+ tree.Cut(new Interval(80, 110), out lo, out lv, out hi, out hv);
+ Assert.IsTrue(lv && hv);
+ Assert.AreEqual(112, hi);
+ Assert.AreEqual(78, lo);
+ }
+
+
+ [Test]
+ public void UpperCut()
+ {
+ for (int i = 0; i < 10; i++)
+ tree.Add(i);
+
+ int l, h;
+ bool lv, hv;
+
+ Assert.IsFalse(tree.Cut(new CubeRoot(1000), out l, out lv, out h, out hv));
+ Assert.IsTrue(lv && !hv);
+ Assert.AreEqual(9, l);
+ Assert.IsFalse(tree.Cut(new CubeRoot(-50), out l, out lv, out h, out hv));
+ Assert.IsTrue(!lv && hv);
+ Assert.AreEqual(0, h);
+ }
+
+
+ [TearDown]
+ public void Dispose() { ic = null; tree = null; }
+ }
+ }
+
+
+
+
+ namespace MultiOps
+ {
+ [TestFixture]
+ public class AddAll
+ {
+ private int sqr(int i) { return i * i; }
+
+
+ TreeBag<int> tree;
+
+
+ [SetUp]
+ public void Init() { tree = new TreeBag<int>(new IC()); }
+
+
+ [Test]
+ public void EmptyEmpty()
+ {
+ tree.AddAll(new FunEnumerable(0, new Fun<int, int>(sqr)));
+ Assert.AreEqual(0, tree.Count);
+ Assert.IsTrue(tree.Check());
+ }
+
+
+ [Test]
+ public void SomeEmpty()
+ {
+ for (int i = 4; i < 9; i++) tree.Add(i);
+
+ tree.AddAll(new FunEnumerable(0, new Fun<int, int>(sqr)));
+ Assert.AreEqual(5, tree.Count);
+ Assert.IsTrue(tree.Check());
+ }
+
+
+ [Test]
+ public void EmptySome()
+ {
+ tree.AddAll(new FunEnumerable(4, new Fun<int, int>(sqr)));
+ Assert.AreEqual(4, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.AreEqual(0, tree[0]);
+ Assert.AreEqual(1, tree[1]);
+ Assert.AreEqual(4, tree[2]);
+ Assert.AreEqual(9, tree[3]);
+ }
+
+
+ [Test]
+ public void SomeSome()
+ {
+ for (int i = 5; i < 9; i++) tree.Add(i);
+ tree.Add(1);
+
+ tree.AddAll(new FunEnumerable(4, new Fun<int, int>(sqr)));
+ Assert.AreEqual(9, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.IsTrue(IC.eq(tree, 0, 1, 1, 4, 5, 6, 7, 8, 9));
+ }
+
+
+ [TearDown]
+ public void Dispose() { tree = null; }
+ }
+
+
+
+ [TestFixture]
+ public class AddSorted
+ {
+ private int sqr(int i) { return i * i; }
+
+ private int step(int i) { return i / 3; }
+
+
+ private int bad(int i) { return i * (5 - i); }
+
+
+ TreeBag<int> tree;
+
+
+ [SetUp]
+ public void Init() { tree = new TreeBag<int>(new IC()); }
+
+
+ [Test]
+ public void EmptyEmpty()
+ {
+ tree.AddSorted(new FunEnumerable(0, new Fun<int, int>(sqr)));
+ Assert.AreEqual(0, tree.Count);
+ Assert.IsTrue(tree.Check());
+ }
+
+
+ [Test]
+ public void SomeEmpty()
+ {
+ for (int i = 4; i < 9; i++) tree.Add(i);
+
+ tree.AddSorted(new FunEnumerable(0, new Fun<int, int>(sqr)));
+ Assert.AreEqual(5, tree.Count);
+ Assert.IsTrue(tree.Check());
+ }
+
+
+ [Test]
+ public void EmptySome()
+ {
+ tree.AddSorted(new FunEnumerable(4, new Fun<int, int>(sqr)));
+ Assert.AreEqual(4, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.AreEqual(0, tree[0]);
+ Assert.AreEqual(1, tree[1]);
+ Assert.AreEqual(4, tree[2]);
+ Assert.AreEqual(9, tree[3]);
+ }
+
+ [Test]
+ public void EmptySome2()
+ {
+ tree.AddSorted(new FunEnumerable(4, new Fun<int, int>(step)));
+ //tree.dump();
+ Assert.AreEqual(4, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.AreEqual(0, tree[0]);
+ Assert.AreEqual(0, tree[1]);
+ Assert.AreEqual(0, tree[2]);
+ Assert.AreEqual(1, tree[3]);
+ }
+
+
+ [Test]
+ public void SomeSome()
+ {
+ for (int i = 5; i < 9; i++) tree.Add(i);
+ tree.Add(1);
+
+ tree.AddSorted(new FunEnumerable(4, new Fun<int, int>(sqr)));
+ Assert.AreEqual(9, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.IsTrue(IC.eq(tree, 0, 1, 1, 4, 5, 6, 7, 8, 9));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentException), "Argument not sorted")]
+ public void EmptyBad()
+ {
+ tree.AddSorted(new FunEnumerable(9, new Fun<int, int>(bad)));
+ }
+
+
+ [TearDown]
+ public void Dispose() { tree = null; }
+ }
+
+
+
+ [TestFixture]
+ public class Rest
+ {
+ TreeBag<int> tree, tree2;
+
+
+ [SetUp]
+ public void Init()
+ {
+ tree = new TreeBag<int>(new IC());
+ tree2 = new TreeBag<int>(new IC());
+ for (int i = 0; i < 10; i++)
+ tree.Add(i);
+ tree.Add(4);
+
+ for (int i = 0; i < 10; i++)
+ tree2.Add(2 * i);
+ }
+
+
+ [Test]
+ public void RemoveAll()
+ {
+ tree.RemoveAll(tree2.RangeFromTo(3, 7));
+ Assert.AreEqual(9, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.IsTrue(IC.eq(tree, 0, 1, 2, 3, 4, 5, 7, 8, 9));
+ tree.RemoveAll(tree2.RangeFromTo(3, 7));
+ Assert.AreEqual(8, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.IsTrue(IC.eq(tree, 0, 1, 2, 3, 5, 7, 8, 9));
+ tree.RemoveAll(tree2.RangeFromTo(13, 17));
+ Assert.AreEqual(8, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.IsTrue(IC.eq(tree, 0, 1, 2, 3, 5, 7, 8, 9));
+ tree.RemoveAll(tree2.RangeFromTo(3, 17));
+ Assert.AreEqual(7, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.IsTrue(IC.eq(tree, 0, 1, 2, 3, 5, 7, 9));
+ for (int i = 0; i < 10; i++) tree2.Add(i);
+
+ tree.RemoveAll(tree2.RangeFromTo(-1, 10));
+ Assert.AreEqual(0, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.IsTrue(IC.eq(tree));
+ }
+
+ private void pint<T>(SCG.IEnumerable<T> e)
+ {
+ foreach (T i in e)
+ Console.Write("{0} ", i);
+
+ Console.WriteLine();
+ }
+
+ [Test]
+ public void RetainAll()
+ {
+ tree.Add(8); tree2.Add(6);
+ //pint<int>(tree);
+ //pint<int>(tree2);
+ tree.RetainAll(tree2.RangeFromTo(3, 17));
+ Assert.AreEqual(3, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.IsTrue(IC.eq(tree, 4, 6, 8));
+ tree.RetainAll(tree2.RangeFromTo(1, 17));
+ Assert.AreEqual(3, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.IsTrue(IC.eq(tree, 4, 6, 8));
+ tree.RetainAll(tree2.RangeFromTo(3, 5));
+ Assert.AreEqual(1, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.IsTrue(IC.eq(tree, 4));
+ tree.RetainAll(tree2.RangeFromTo(7, 17));
+ Assert.AreEqual(0, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.IsTrue(IC.eq(tree));
+ for (int i = 0; i < 10; i++) tree.Add(i);
+
+ tree.RetainAll(tree2.RangeFromTo(5, 5));
+ Assert.AreEqual(0, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.IsTrue(IC.eq(tree));
+ for (int i = 0; i < 10; i++) tree.Add(i);
+
+ tree.RetainAll(tree2.RangeFromTo(15, 25));
+ Assert.AreEqual(0, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.IsTrue(IC.eq(tree));
+ }
+
+
+ [Test]
+ public void ContainsAll()
+ {
+ Assert.IsFalse(tree.ContainsAll(tree2));
+ Assert.IsTrue(tree.ContainsAll(tree));
+ tree2.Clear();
+ Assert.IsTrue(tree.ContainsAll(tree2));
+ tree.Clear();
+ Assert.IsTrue(tree.ContainsAll(tree2));
+ tree2.Add(8);
+ Assert.IsFalse(tree.ContainsAll(tree2));
+ }
+
+
+ [Test]
+ public void RemoveInterval()
+ {
+ tree.RemoveInterval(3, 4);
+ Assert.IsTrue(tree.Check());
+ Assert.AreEqual(7, tree.Count);
+ Assert.IsTrue(IC.eq(tree, 0, 1, 2, 6, 7, 8, 9));
+ tree.RemoveInterval(2, 3);
+ Assert.IsTrue(tree.Check());
+ Assert.AreEqual(4, tree.Count);
+ Assert.IsTrue(IC.eq(tree, 0, 1, 8, 9));
+ tree.RemoveInterval(0, 4);
+ Assert.IsTrue(tree.Check());
+ Assert.AreEqual(0, tree.Count);
+ Assert.IsTrue(IC.eq(tree));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void RemoveRangeBad1()
+ {
+ tree.RemoveInterval(-3, 8);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void RemoveRangeBad2()
+ {
+ tree.RemoveInterval(3, -8);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void RemoveRangeBad3()
+ {
+ tree.RemoveInterval(3, 9);
+ }
+
+
+ [Test]
+ public void GetRange()
+ {
+ Assert.IsTrue(IC.eq(tree[3, 3]));
+ Assert.IsTrue(IC.eq(tree[3, 4], 3));
+ Assert.IsTrue(IC.eq(tree[3, 5], 3, 4));
+ Assert.IsTrue(IC.eq(tree[3, 6], 3, 4, 4));
+ Assert.IsTrue(IC.eq(tree[3, 7], 3, 4, 4, 5));
+ Assert.IsTrue(IC.eq(tree[4, 4]));
+ Assert.IsTrue(IC.eq(tree[4, 5], 4));
+ Assert.IsTrue(IC.eq(tree[4, 6], 4, 4));
+ Assert.IsTrue(IC.eq(tree[4, 7], 4, 4, 5));
+ Assert.IsTrue(IC.eq(tree[4, 8], 4, 4, 5, 6));
+ Assert.IsTrue(IC.eq(tree[5, 5]));
+ Assert.IsTrue(IC.eq(tree[5, 6], 4));
+ Assert.IsTrue(IC.eq(tree[5, 7], 4, 5));
+ Assert.IsTrue(IC.eq(tree[5, 8], 4, 5, 6));
+ Assert.IsTrue(IC.eq(tree[5, 9], 4, 5, 6, 7));
+ Assert.IsTrue(IC.eq(tree[5, 11], 4, 5, 6, 7, 8, 9));
+ }
+
+
+ [Test]
+ public void GetRangeBackwards()
+ {
+ Assert.IsTrue(IC.eq(tree[3, 3].Backwards()));
+ Assert.IsTrue(IC.eq(tree[3, 4].Backwards(), 3));
+ Assert.IsTrue(IC.eq(tree[3, 5].Backwards(), 4, 3));
+ Assert.IsTrue(IC.eq(tree[3, 6].Backwards(), 4, 4, 3));
+ Assert.IsTrue(IC.eq(tree[3, 7].Backwards(), 5, 4, 4, 3));
+ Assert.IsTrue(IC.eq(tree[4, 4].Backwards()));
+ Assert.IsTrue(IC.eq(tree[4, 5].Backwards(), 4));
+ Assert.IsTrue(IC.eq(tree[4, 6].Backwards(), 4, 4));
+ Assert.IsTrue(IC.eq(tree[4, 7].Backwards(), 5, 4, 4));
+ Assert.IsTrue(IC.eq(tree[4, 8].Backwards(), 6, 5, 4, 4));
+ Assert.IsTrue(IC.eq(tree[5, 5].Backwards()));
+ Assert.IsTrue(IC.eq(tree[5, 6].Backwards(), 4));
+ Assert.IsTrue(IC.eq(tree[5, 7].Backwards(), 5, 4));
+ Assert.IsTrue(IC.eq(tree[5, 8].Backwards(), 6, 5, 4));
+ Assert.IsTrue(IC.eq(tree[5, 9].Backwards(), 7, 6, 5, 4));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void GetRangeBad1()
+ {
+ object foo = tree[-3, 0];
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void GetRangeBad2()
+ {
+ object foo = tree[3, 2];
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void GetRangeBad3()
+ {
+ object foo = tree[3, 12];
+ }
+
+
+ [TearDown]
+ public void Dispose() { tree = null; tree2 = null; }
+ }
+ }
+
+
+ namespace Hashing
+ {
+ [TestFixture]
+ public class ISequenced
+ {
+ private ISequenced<int> dit, dat, dut;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new TreeBag<int>(Comparer<int>.Default, EqualityComparer<int>.Default);
+ dat = new TreeBag<int>(Comparer<int>.Default, EqualityComparer<int>.Default);
+ dut = new TreeBag<int>(new RevIC(), EqualityComparer<int>.Default);
+ }
+
+
+ [Test]
+ public void EmptyEmpty()
+ {
+ Assert.IsTrue(dit.SequencedEquals(dat));
+ }
+
+
+ [Test]
+ public void EmptyNonEmpty()
+ {
+ dit.Add(3);
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ Assert.IsFalse(dat.SequencedEquals(dit));
+ }
+
+ [Test]
+ public void HashVal()
+ {
+ Assert.AreEqual(CHC.sequencedhashcode(), dit.GetSequencedHashCode());
+ dit.Add(3);
+ Assert.AreEqual(CHC.sequencedhashcode(3), dit.GetSequencedHashCode());
+ dit.Add(7);
+ Assert.AreEqual(CHC.sequencedhashcode(3, 7), dit.GetSequencedHashCode());
+ Assert.AreEqual(CHC.sequencedhashcode(), dut.GetSequencedHashCode());
+ dut.Add(3);
+ Assert.AreEqual(CHC.sequencedhashcode(3), dut.GetSequencedHashCode());
+ dut.Add(7);
+ Assert.AreEqual(CHC.sequencedhashcode(7, 3), dut.GetSequencedHashCode());
+ }
+
+
+ [Test]
+ public void Normal()
+ {
+ dit.Add(3);
+ dit.Add(7);
+ dat.Add(3);
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ Assert.IsFalse(dat.SequencedEquals(dit));
+ dat.Add(7);
+ Assert.IsTrue(dit.SequencedEquals(dat));
+ Assert.IsTrue(dat.SequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void WrongOrder()
+ {
+ dit.Add(3);
+ dut.Add(3);
+ Assert.IsTrue(dit.SequencedEquals(dut));
+ Assert.IsTrue(dut.SequencedEquals(dit));
+ dit.Add(7);
+ dut.Add(7);
+ Assert.IsFalse(dit.SequencedEquals(dut));
+ Assert.IsFalse(dut.SequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void Reflexive()
+ {
+ Assert.IsTrue(dit.SequencedEquals(dit));
+ dit.Add(3);
+ Assert.IsTrue(dit.SequencedEquals(dit));
+ dit.Add(7);
+ Assert.IsTrue(dit.SequencedEquals(dit));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = null;
+ dat = null;
+ dut = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class IEditableCollection
+ {
+ private ICollection<int> dit, dat, dut;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new TreeBag<int>(Comparer<int>.Default, EqualityComparer<int>.Default);
+ dat = new TreeBag<int>(Comparer<int>.Default, EqualityComparer<int>.Default);
+ dut = new TreeBag<int>(new RevIC(), EqualityComparer<int>.Default);
+ }
+
+
+ [Test]
+ public void EmptyEmpty()
+ {
+ Assert.IsTrue(dit.UnsequencedEquals(dat));
+ }
+
+
+ [Test]
+ public void EmptyNonEmpty()
+ {
+ dit.Add(3);
+ Assert.IsFalse(dit.UnsequencedEquals(dat));
+ Assert.IsFalse(dat.UnsequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void HashVal()
+ {
+ Assert.AreEqual(CHC.unsequencedhashcode(), dit.GetUnsequencedHashCode());
+ dit.Add(3);
+ Assert.AreEqual(CHC.unsequencedhashcode(3), dit.GetUnsequencedHashCode());
+ dit.Add(7);
+ Assert.AreEqual(CHC.unsequencedhashcode(3, 7), dit.GetUnsequencedHashCode());
+ Assert.AreEqual(CHC.unsequencedhashcode(), dut.GetUnsequencedHashCode());
+ dut.Add(3);
+ Assert.AreEqual(CHC.unsequencedhashcode(3), dut.GetUnsequencedHashCode());
+ dut.Add(7);
+ Assert.AreEqual(CHC.unsequencedhashcode(7, 3), dut.GetUnsequencedHashCode());
+ }
+
+
+ [Test]
+ public void Normal()
+ {
+ dit.Add(3);
+ dit.Add(7);
+ dat.Add(3);
+ Assert.IsFalse(dit.UnsequencedEquals(dat));
+ Assert.IsFalse(dat.UnsequencedEquals(dit));
+ dat.Add(7);
+ Assert.IsTrue(dit.UnsequencedEquals(dat));
+ Assert.IsTrue(dat.UnsequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void WrongOrder()
+ {
+ dit.Add(3);
+ dut.Add(3);
+ Assert.IsTrue(dit.UnsequencedEquals(dut));
+ Assert.IsTrue(dut.UnsequencedEquals(dit));
+ dit.Add(7);
+ dut.Add(7);
+ Assert.IsTrue(dit.UnsequencedEquals(dut));
+ Assert.IsTrue(dut.UnsequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void Reflexive()
+ {
+ Assert.IsTrue(dit.UnsequencedEquals(dit));
+ dit.Add(3);
+ Assert.IsTrue(dit.UnsequencedEquals(dit));
+ dit.Add(7);
+ Assert.IsTrue(dit.UnsequencedEquals(dit));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = null;
+ dat = null;
+ dut = null;
+ }
+ }
+ }
+
+}
diff --git a/mcs/class/Mono.C5/1.0/Test/trees/Dictionary.cs b/mcs/class/Mono.C5/1.0/Test/trees/Dictionary.cs
new file mode 100644
index 00000000000..5380c332d71
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/Test/trees/Dictionary.cs
@@ -0,0 +1,311 @@
+/*
+ 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 C5;
+using NUnit.Framework;
+using SCG=System.Collections.Generic;
+
+
+namespace C5UnitTests.trees.RBDictionary
+{
+ static class Factory
+ {
+ public static IDictionary<K,V> New<K,V>() { return new TreeDictionary<K,V>(); }
+ }
+
+
+ [TestFixture]
+ public class Formatting
+ {
+ IDictionary<int,int> coll;
+ IFormatProvider rad16;
+ [SetUp]
+ public void Init() { coll = Factory.New<int,int>(); rad16 = new RadixFormatProvider(16); }
+ [TearDown]
+ public void Dispose() { coll = null; rad16 = null; }
+ [Test]
+ public void Format()
+ {
+ Assert.AreEqual("[ ]", coll.ToString());
+ coll.Add(23, 67); coll.Add(45, 89);
+ Assert.AreEqual("[ 23 => 67, 45 => 89 ]", coll.ToString());
+ Assert.AreEqual("[ 17 => 43, 2D => 59 ]", coll.ToString(null, rad16));
+ Assert.AreEqual("[ 23 => 67, ... ]", coll.ToString("L14", null));
+ Assert.AreEqual("[ 17 => 43, ... ]", coll.ToString("L14", rad16));
+ }
+ }
+
+ [TestFixture]
+ public class RBDict
+ {
+ private TreeDictionary<string,string> dict;
+
+
+ [SetUp]
+ public void Init() { dict = new TreeDictionary<string,string>(new SC()); }
+
+
+ [TearDown]
+ public void Dispose() { dict = null; }
+
+ [Test]
+ [ExpectedException(typeof(NullReferenceException))]
+ public void NullEqualityComparerinConstructor1()
+ {
+ new TreeDictionary<int,int>(null);
+ }
+
+ [Test]
+ public void Choose()
+ {
+ dict.Add("YES","NO");
+ Assert.AreEqual(new KeyValuePair<string,string>("YES","NO"), dict.Choose());
+ }
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void BadChoose()
+ {
+ dict.Choose();
+ }
+
+ [Test]
+ public void Pred()
+ {
+ dict.Add("A", "1");
+ dict.Add("C", "2");
+ dict.Add("E", "3");
+ Assert.AreEqual("1", dict.Predecessor("B").Value);
+ Assert.AreEqual("1", dict.Predecessor("C").Value);
+ Assert.AreEqual("1", dict.WeakPredecessor("B").Value);
+ Assert.AreEqual("2", dict.WeakPredecessor("C").Value);
+ Assert.AreEqual("2", dict.Successor("B").Value);
+ Assert.AreEqual("3", dict.Successor("C").Value);
+ Assert.AreEqual("2", dict.WeakSuccessor("B").Value);
+ Assert.AreEqual("2", dict.WeakSuccessor("C").Value);
+ }
+
+
+ [Test]
+ public void Initial()
+ {
+ bool res;
+ Assert.IsFalse(dict.IsReadOnly);
+
+ Assert.AreEqual(dict.Count, 0, "new dict should be empty");
+ dict.Add("A", "B");
+ Assert.AreEqual(dict.Count, 1, "bad count");
+ Assert.AreEqual(dict["A"], "B", "Wrong value for dict[A]");
+ dict.Add("C", "D");
+ Assert.AreEqual(dict.Count, 2, "bad count");
+ Assert.AreEqual(dict["A"], "B", "Wrong value");
+ Assert.AreEqual(dict["C"], "D", "Wrong value");
+ res = dict.Remove("A");
+ Assert.IsTrue(res, "bad return value from Remove(A)");
+ Assert.IsTrue(dict.Check());
+ Assert.AreEqual(dict.Count, 1, "bad count");
+ Assert.AreEqual(dict["C"], "D", "Wrong value of dict[C]");
+ res = dict.Remove("Z");
+ Assert.IsFalse(res, "bad return value from Remove(Z)");
+ Assert.AreEqual(dict.Count, 1, "bad count");
+ Assert.AreEqual(dict["C"], "D", "Wrong value of dict[C] (2)");
+ dict.Clear();
+ Assert.AreEqual(dict.Count, 0, "dict should be empty");
+ }
+ [Test]
+ public void Contains()
+ {
+ dict.Add("C", "D");
+ Assert.IsTrue(dict.Contains("C"));
+ Assert.IsFalse(dict.Contains("D"));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(DuplicateNotAllowedException), "Key being added: 'A'")]
+ public void IllegalAdd()
+ {
+ dict.Add("A", "B");
+ dict.Add("A", "B");
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void GettingNonExisting()
+ {
+ Console.WriteLine(dict["R"]);
+ }
+
+
+ [Test]
+ public void Setter()
+ {
+ dict["R"] = "UYGUY";
+ Assert.AreEqual(dict["R"], "UYGUY");
+ dict["R"] = "UIII";
+ Assert.AreEqual(dict["R"], "UIII");
+ dict["S"] = "VVV";
+ Assert.AreEqual(dict["R"], "UIII");
+ Assert.AreEqual(dict["S"], "VVV");
+ //dict.dump();
+ }
+ }
+
+ [TestFixture]
+ public class Enumerators
+ {
+ private TreeDictionary<string,string> dict;
+
+ private SCG.IEnumerator<KeyValuePair<string,string>> dictenum;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dict = new TreeDictionary<string,string>(new SC());
+ dict["S"] = "A";
+ dict["T"] = "B";
+ dict["R"] = "C";
+ dictenum = dict.GetEnumerator();
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dictenum = null;
+ dict = null;
+ }
+
+
+
+ [Test]
+ public void Keys()
+ {
+ SCG.IEnumerator<string> keys = dict.Keys.GetEnumerator();
+ Assert.AreEqual(3, dict.Keys.Count);
+ Assert.IsTrue(keys.MoveNext());
+ Assert.AreEqual("R",keys.Current);
+ Assert.IsTrue(keys.MoveNext());
+ Assert.AreEqual("S",keys.Current);
+ Assert.IsTrue(keys.MoveNext());
+ Assert.AreEqual("T",keys.Current);
+ Assert.IsFalse(keys.MoveNext());
+ }
+
+ [Test]
+ public void Values()
+ {
+ SCG.IEnumerator<string> values = dict.Values.GetEnumerator();
+ Assert.AreEqual(3, dict.Values.Count);
+ Assert.IsTrue(values.MoveNext());
+ Assert.AreEqual("C",values.Current);
+ Assert.IsTrue(values.MoveNext());
+ Assert.AreEqual("A",values.Current);
+ Assert.IsTrue(values.MoveNext());
+ Assert.AreEqual("B",values.Current);
+ Assert.IsFalse(values.MoveNext());
+ }
+
+ [Test]
+ public void Fun()
+ {
+ Assert.AreEqual("B", dict.Fun("T"));
+ }
+
+
+ [Test]
+ public void NormalUse()
+ {
+ Assert.IsTrue(dictenum.MoveNext());
+ Assert.AreEqual(dictenum.Current, new KeyValuePair<string,string>("R", "C"));
+ Assert.IsTrue(dictenum.MoveNext());
+ Assert.AreEqual(dictenum.Current, new KeyValuePair<string,string>("S", "A"));
+ Assert.IsTrue(dictenum.MoveNext());
+ Assert.AreEqual(dictenum.Current, new KeyValuePair<string,string>("T", "B"));
+ Assert.IsFalse(dictenum.MoveNext());
+ }
+ }
+
+
+
+
+ namespace PathCopyPersistence
+ {
+ [TestFixture]
+ public class Simple
+ {
+ private TreeDictionary<string,string> dict;
+
+ private TreeDictionary<string,string> snap;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dict = new TreeDictionary<string,string>(new SC());
+ dict["S"] = "A";
+ dict["T"] = "B";
+ dict["R"] = "C";
+ dict["V"] = "G";
+ snap = (TreeDictionary<string,string>)dict.Snapshot();
+ }
+
+
+ [Test]
+ public void Test()
+ {
+ dict["SS"] = "D";
+ Assert.AreEqual(5, dict.Count);
+ Assert.AreEqual(4, snap.Count);
+ dict["T"] = "bb";
+ Assert.AreEqual(5, dict.Count);
+ Assert.AreEqual(4, snap.Count);
+ Assert.AreEqual("B", snap["T"]);
+ Assert.AreEqual("bb", dict["T"]);
+ Assert.IsFalse(dict.IsReadOnly);
+ Assert.IsTrue(snap.IsReadOnly);
+ //Finally, update of root node:
+ TreeDictionary<string,string> snap2 = (TreeDictionary<string,string>)dict.Snapshot();
+ dict["S"] = "abe";
+ Assert.AreEqual("abe", dict["S"]);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ReadOnlyCollectionException))]
+ public void UpdateSnap()
+ {
+ snap["Y"] = "J";
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dict = null;
+ snap = null;
+ }
+ }
+ }
+}
diff --git a/mcs/class/Mono.C5/1.0/Test/trees/RedBlackTreeSetTests.cs b/mcs/class/Mono.C5/1.0/Test/trees/RedBlackTreeSetTests.cs
new file mode 100644
index 00000000000..09a13182df7
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/Test/trees/RedBlackTreeSetTests.cs
@@ -0,0 +1,2855 @@
+/*
+ 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 C5;
+using NUnit.Framework;
+using SCG = System.Collections.Generic;
+
+namespace C5UnitTests.trees.TreeSet
+{
+ using CollectionOfInt = TreeSet<int>;
+
+ [TestFixture]
+ public class GenericTesters
+ {
+ [Test]
+ public void TestEvents()
+ {
+ Fun<CollectionOfInt> factory = delegate() { return new CollectionOfInt(TenEqualityComparer.Default); };
+ new C5UnitTests.Templates.Events.SortedIndexedTester<CollectionOfInt>().Test(factory);
+ }
+
+ [Test]
+ public void Extensible()
+ {
+ C5UnitTests.Templates.Extensible.Clone.Tester<CollectionOfInt>();
+ C5UnitTests.Templates.Extensible.Serialization.Tester<CollectionOfInt>();
+ }
+ }
+
+ static class Factory
+ {
+ public static ICollection<T> New<T>() { return new TreeSet<T>(); }
+ }
+
+
+ [TestFixture]
+ public class Formatting
+ {
+ ICollection<int> coll;
+ IFormatProvider rad16;
+ [SetUp]
+ public void Init() { coll = Factory.New<int>(); rad16 = new RadixFormatProvider(16); }
+ [TearDown]
+ public void Dispose() { coll = null; rad16 = null; }
+ [Test]
+ public void Format()
+ {
+ Assert.AreEqual("{ }", coll.ToString());
+ coll.AddAll<int>(new int[] { -4, 28, 129, 65530 });
+ Assert.AreEqual("{ -4, 28, 129, 65530 }", coll.ToString());
+ Assert.AreEqual("{ -4, 1C, 81, FFFA }", coll.ToString(null, rad16));
+ Assert.AreEqual("{ -4, 28, 129... }", coll.ToString("L14", null));
+ Assert.AreEqual("{ -4, 1C, 81... }", coll.ToString("L14", rad16));
+ }
+ }
+
+ [TestFixture]
+ public class Combined
+ {
+ private IIndexedSorted<KeyValuePair<int,int>> lst;
+
+
+ [SetUp]
+ public void Init()
+ {
+ lst = new TreeSet<KeyValuePair<int,int>>(new KeyValuePairComparer<int,int>(new IC()));
+ for (int i = 0; i < 10; i++)
+ lst.Add(new KeyValuePair<int,int>(i, i + 30));
+ }
+
+
+ [TearDown]
+ public void Dispose() { lst = null; }
+
+
+ [Test]
+ public void Find()
+ {
+ KeyValuePair<int,int> p = new KeyValuePair<int,int>(3, 78);
+
+ Assert.IsTrue(lst.Find(ref p));
+ Assert.AreEqual(3, p.Key);
+ Assert.AreEqual(33, p.Value);
+ p = new KeyValuePair<int,int>(13, 78);
+ Assert.IsFalse(lst.Find(ref p));
+ }
+
+
+ [Test]
+ public void FindOrAdd()
+ {
+ KeyValuePair<int,int> p = new KeyValuePair<int,int>(3, 78);
+
+ Assert.IsTrue(lst.FindOrAdd(ref p));
+ Assert.AreEqual(3, p.Key);
+ Assert.AreEqual(33, p.Value);
+ p = new KeyValuePair<int,int>(13, 79);
+ Assert.IsFalse(lst.FindOrAdd(ref p));
+ Assert.AreEqual(13, lst[10].Key);
+ Assert.AreEqual(79, lst[10].Value);
+ }
+
+
+ [Test]
+ public void Update()
+ {
+ KeyValuePair<int,int> p = new KeyValuePair<int,int>(3, 78);
+
+ Assert.IsTrue(lst.Update(p));
+ Assert.AreEqual(3, lst[3].Key);
+ Assert.AreEqual(78, lst[3].Value);
+ p = new KeyValuePair<int,int>(13, 78);
+ Assert.IsFalse(lst.Update(p));
+ }
+
+
+ [Test]
+ public void UpdateOrAdd()
+ {
+ KeyValuePair<int,int> p = new KeyValuePair<int,int>(3, 78);
+
+ Assert.IsTrue(lst.UpdateOrAdd(p));
+ Assert.AreEqual(3, lst[3].Key);
+ Assert.AreEqual(78, lst[3].Value);
+ p = new KeyValuePair<int,int>(13, 79);
+ Assert.IsFalse(lst.UpdateOrAdd(p));
+ Assert.AreEqual(13, lst[10].Key);
+ Assert.AreEqual(79, lst[10].Value);
+ }
+
+
+ [Test]
+ public void RemoveWithReturn()
+ {
+ KeyValuePair<int,int> p = new KeyValuePair<int,int>(3, 78);
+
+ Assert.IsTrue(lst.Remove(p, out p));
+ Assert.AreEqual(3, p.Key);
+ Assert.AreEqual(33, p.Value);
+ Assert.AreEqual(4, lst[3].Key);
+ Assert.AreEqual(34, lst[3].Value);
+ p = new KeyValuePair<int,int>(13, 78);
+ Assert.IsFalse(lst.Remove(p, out p));
+ }
+ }
+
+
+ [TestFixture]
+ public class Ranges
+ {
+ private TreeSet<int> tree;
+
+ private SCG.IComparer<int> c;
+
+
+ [SetUp]
+ public void Init()
+ {
+ c = new IC();
+ tree = new TreeSet<int>(c);
+ for (int i = 1; i <= 10; i++)
+ {
+ tree.Add(i * 2);
+ }
+ }
+
+
+ [Test]
+ public void Enumerator()
+ {
+ SCG.IEnumerator<int> e = tree.RangeFromTo(5, 17).GetEnumerator();
+ int i = 3;
+
+ while (e.MoveNext())
+ {
+ Assert.AreEqual(2 * i++, e.Current);
+ }
+
+ Assert.AreEqual(9, i);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(InvalidOperationException))]
+ public void Enumerator2()
+ {
+ SCG.IEnumerator<int> e = tree.RangeFromTo(5, 17).GetEnumerator();
+ int i = e.Current;
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(InvalidOperationException))]
+ public void Enumerator3()
+ {
+ SCG.IEnumerator<int> e = tree.RangeFromTo(5, 17).GetEnumerator();
+
+ while (e.MoveNext());
+
+ int i = e.Current;
+ }
+
+
+ [Test]
+ public void Remove()
+ {
+ int[] all = new int[] { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 };
+
+ tree.RemoveRangeFrom(18);
+ Assert.IsTrue(IC.eq(tree, new int[] { 2, 4, 6, 8, 10, 12, 14, 16 }));
+ tree.RemoveRangeFrom(28);
+ Assert.IsTrue(IC.eq(tree, new int[] { 2, 4, 6, 8, 10, 12, 14, 16 }));
+ tree.RemoveRangeFrom(2);
+ Assert.IsTrue(IC.eq(tree));
+ foreach (int i in all) tree.Add(i);
+
+ tree.RemoveRangeTo(10);
+ Assert.IsTrue(IC.eq(tree, new int[] { 10, 12, 14, 16, 18, 20 }));
+ tree.RemoveRangeTo(2);
+ Assert.IsTrue(IC.eq(tree, new int[] { 10, 12, 14, 16, 18, 20 }));
+ tree.RemoveRangeTo(21);
+ Assert.IsTrue(IC.eq(tree));
+ foreach (int i in all) tree.Add(i);
+
+ tree.RemoveRangeFromTo(4, 8);
+ Assert.IsTrue(IC.eq(tree, 2, 8, 10, 12, 14, 16, 18, 20));
+ tree.RemoveRangeFromTo(14, 28);
+ Assert.IsTrue(IC.eq(tree, 2, 8, 10, 12));
+ tree.RemoveRangeFromTo(0, 9);
+ Assert.IsTrue(IC.eq(tree, 10, 12));
+ tree.RemoveRangeFromTo(0, 81);
+ Assert.IsTrue(IC.eq(tree));
+ }
+
+ [Test]
+ public void Normal()
+ {
+ int[] all = new int[] { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 };
+
+ Assert.IsTrue(IC.eq(tree, all));
+ Assert.IsTrue(IC.eq(tree.RangeAll(), all));
+ Assert.AreEqual(10, tree.RangeAll().Count);
+ Assert.IsTrue(IC.eq(tree.RangeFrom(11), new int[] { 12, 14, 16, 18, 20 }));
+ Assert.AreEqual(5, tree.RangeFrom(11).Count);
+ Assert.IsTrue(IC.eq(tree.RangeFrom(12), new int[] { 12, 14, 16, 18, 20 }));
+ Assert.IsTrue(IC.eq(tree.RangeFrom(2), all));
+ Assert.IsTrue(IC.eq(tree.RangeFrom(1), all));
+ Assert.IsTrue(IC.eq(tree.RangeFrom(21), new int[] { }));
+ Assert.IsTrue(IC.eq(tree.RangeFrom(20), new int[] { 20 }));
+ Assert.IsTrue(IC.eq(tree.RangeTo(8), new int[] { 2, 4, 6 }));
+ Assert.IsTrue(IC.eq(tree.RangeTo(7), new int[] { 2, 4, 6 }));
+ Assert.AreEqual(3, tree.RangeTo(7).Count);
+ Assert.IsTrue(IC.eq(tree.RangeTo(2), new int[] { }));
+ Assert.IsTrue(IC.eq(tree.RangeTo(1), new int[] { }));
+ Assert.IsTrue(IC.eq(tree.RangeTo(3), new int[] { 2 }));
+ Assert.IsTrue(IC.eq(tree.RangeTo(20), new int[] { 2, 4, 6, 8, 10, 12, 14, 16, 18 }));
+ Assert.IsTrue(IC.eq(tree.RangeTo(21), all));
+ Assert.IsTrue(IC.eq(tree.RangeFromTo(7, 12), new int[] { 8, 10 }));
+ Assert.IsTrue(IC.eq(tree.RangeFromTo(6, 11), new int[] { 6, 8, 10 }));
+ Assert.IsTrue(IC.eq(tree.RangeFromTo(1, 12), new int[] { 2, 4, 6, 8, 10 }));
+ Assert.AreEqual(5, tree.RangeFromTo(1, 12).Count);
+ Assert.IsTrue(IC.eq(tree.RangeFromTo(2, 12), new int[] { 2, 4, 6, 8, 10 }));
+ Assert.IsTrue(IC.eq(tree.RangeFromTo(6, 21), new int[] { 6, 8, 10, 12, 14, 16, 18, 20 }));
+ Assert.IsTrue(IC.eq(tree.RangeFromTo(6, 20), new int[] { 6, 8, 10, 12, 14, 16, 18 }));
+ }
+
+
+ [Test]
+ public void Backwards()
+ {
+ int[] all = new int[] { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 };
+ int[] lla = new int[] { 20, 18, 16, 14, 12, 10, 8, 6, 4, 2 };
+
+ Assert.IsTrue(IC.eq(tree, all));
+ Assert.IsTrue(IC.eq(tree.RangeAll().Backwards(), lla));
+ Assert.IsTrue(IC.eq(tree.RangeFrom(11).Backwards(), new int[] { 20, 18, 16, 14, 12 }));
+ Assert.IsTrue(IC.eq(tree.RangeFrom(12).Backwards(), new int[] { 20, 18, 16, 14, 12 }));
+ Assert.IsTrue(IC.eq(tree.RangeFrom(2).Backwards(), lla));
+ Assert.IsTrue(IC.eq(tree.RangeFrom(1).Backwards(), lla));
+ Assert.IsTrue(IC.eq(tree.RangeFrom(21).Backwards(), new int[] { }));
+ Assert.IsTrue(IC.eq(tree.RangeFrom(20).Backwards(), new int[] { 20 }));
+ Assert.IsTrue(IC.eq(tree.RangeTo(8).Backwards(), new int[] { 6, 4, 2 }));
+ Assert.IsTrue(IC.eq(tree.RangeTo(7).Backwards(), new int[] { 6, 4, 2 }));
+ Assert.IsTrue(IC.eq(tree.RangeTo(2).Backwards(), new int[] { }));
+ Assert.IsTrue(IC.eq(tree.RangeTo(1).Backwards(), new int[] { }));
+ Assert.IsTrue(IC.eq(tree.RangeTo(3).Backwards(), new int[] { 2 }));
+ Assert.IsTrue(IC.eq(tree.RangeTo(20).Backwards(), new int[] { 18, 16, 14, 12, 10, 8, 6, 4, 2}));
+ Assert.IsTrue(IC.eq(tree.RangeTo(21).Backwards(), lla));
+ Assert.IsTrue(IC.eq(tree.RangeFromTo(7, 12).Backwards(), new int[] { 10, 8 }));
+ Assert.IsTrue(IC.eq(tree.RangeFromTo(6, 11).Backwards(), new int[] { 10, 8, 6 }));
+ Assert.IsTrue(IC.eq(tree.RangeFromTo(1, 12).Backwards(), new int[] { 10, 8, 6, 4, 2 }));
+ Assert.IsTrue(IC.eq(tree.RangeFromTo(2, 12).Backwards(), new int[] { 10, 8, 6, 4, 2 }));
+ Assert.IsTrue(IC.eq(tree.RangeFromTo(6, 21).Backwards(), new int[] { 20, 18, 16, 14, 12, 10, 8, 6 }));
+ Assert.IsTrue(IC.eq(tree.RangeFromTo(6, 20).Backwards(), new int[] { 18, 16, 14, 12, 10, 8, 6 }));
+ }
+
+ [Test]
+ public void Direction()
+ {
+ Assert.AreEqual(EnumerationDirection.Forwards, tree.Direction);
+ Assert.AreEqual(EnumerationDirection.Forwards, tree.RangeFrom(20).Direction);
+ Assert.AreEqual(EnumerationDirection.Forwards, tree.RangeTo(7).Direction);
+ Assert.AreEqual(EnumerationDirection.Forwards, tree.RangeFromTo(1, 12).Direction);
+ Assert.AreEqual(EnumerationDirection.Forwards, tree.RangeAll().Direction);
+ Assert.AreEqual(EnumerationDirection.Backwards, tree.Backwards().Direction);
+ Assert.AreEqual(EnumerationDirection.Backwards, tree.RangeFrom(20).Backwards().Direction);
+ Assert.AreEqual(EnumerationDirection.Backwards, tree.RangeTo(7).Backwards().Direction);
+ Assert.AreEqual(EnumerationDirection.Backwards, tree.RangeFromTo(1, 12).Backwards().Direction);
+ Assert.AreEqual(EnumerationDirection.Backwards, tree.RangeAll().Backwards().Direction);
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ tree = null;
+ c = null;
+ }
+ }
+
+ [TestFixture]
+ public class BagItf
+ {
+ private TreeSet<int> tree;
+
+
+ [SetUp]
+ public void Init()
+ {
+ tree = new TreeSet<int>(new IC());
+ for (int i = 10; i < 20; i++)
+ {
+ tree.Add(i);
+ tree.Add(i + 10);
+ }
+ }
+
+
+ [Test]
+ public void Both()
+ {
+ Assert.AreEqual(0, tree.ContainsCount(7));
+ Assert.AreEqual(1, tree.ContainsCount(10));
+ tree.RemoveAllCopies(10);
+ Assert.AreEqual(0, tree.ContainsCount(10));
+ tree.RemoveAllCopies(7);
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ tree = null;
+ }
+ }
+
+
+ [TestFixture]
+ public class Div
+ {
+ private TreeSet<int> tree;
+
+
+ [SetUp]
+ public void Init()
+ {
+ tree = new TreeSet<int>(new IC());
+ }
+
+
+ private void loadup()
+ {
+ for (int i = 10; i < 20; i++)
+ {
+ tree.Add(i);
+ tree.Add(i + 10);
+ }
+ }
+
+ [Test]
+ [ExpectedException(typeof(NullReferenceException))]
+ public void NullEqualityComparerinConstructor1()
+ {
+ new TreeSet<int>(null);
+ }
+
+ [Test]
+ [ExpectedException(typeof(NullReferenceException))]
+ public void NullEqualityComparerinConstructor3()
+ {
+ new TreeSet<int>(null, EqualityComparer<int>.Default);
+ }
+
+ [Test]
+ [ExpectedException(typeof(NullReferenceException))]
+ public void NullEqualityComparerinConstructor4()
+ {
+ new TreeSet<int>(Comparer<int>.Default, null);
+ }
+
+ [Test]
+ [ExpectedException(typeof(NullReferenceException))]
+ public void NullEqualityComparerinConstructor5()
+ {
+ new TreeSet<int>(null, null);
+ }
+
+ [Test]
+ public void Choose()
+ {
+ tree.Add(7);
+ Assert.AreEqual(7, tree.Choose());
+ }
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void BadChoose()
+ {
+ tree.Choose();
+ }
+
+
+ [Test]
+ public void NoDuplicates()
+ {
+ Assert.IsFalse(tree.AllowsDuplicates);
+ loadup();
+ Assert.IsFalse(tree.AllowsDuplicates);
+ }
+
+ [Test]
+ public void Add()
+ {
+ Assert.IsTrue(tree.Add(17));
+ Assert.IsFalse(tree.Add(17));
+ Assert.IsTrue(tree.Add(18));
+ Assert.IsFalse(tree.Add(18));
+ Assert.AreEqual(2, tree.Count);
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ tree = null;
+ }
+ }
+
+
+ [TestFixture]
+ public class FindOrAdd
+ {
+ private TreeSet<KeyValuePair<int,string>> bag;
+
+
+ [SetUp]
+ public void Init()
+ {
+ bag = new TreeSet<KeyValuePair<int,string>>(new KeyValuePairComparer<int,string>(new IC()));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ bag = null;
+ }
+
+
+ [Test]
+ public void Test()
+ {
+ KeyValuePair<int,string> p = new KeyValuePair<int,string>(3, "tre");
+
+ Assert.IsFalse(bag.FindOrAdd(ref p));
+ p.Value = "drei";
+ Assert.IsTrue(bag.FindOrAdd(ref p));
+ Assert.AreEqual("tre", p.Value);
+ p.Value = "three";
+ Assert.AreEqual(1, bag.ContainsCount(p));
+ Assert.AreEqual("tre", bag[0].Value);
+ }
+ }
+
+ [TestFixture]
+ public class FindPredicate
+ {
+ private TreeSet<int> list;
+ Fun<int, bool> pred;
+
+ [SetUp]
+ public void Init()
+ {
+ list = new TreeSet<int>(TenEqualityComparer.Default);
+ pred = delegate(int i) { return i % 5 == 0; };
+ }
+
+ [TearDown]
+ public void Dispose() { list = null; }
+
+ [Test]
+ public void Find()
+ {
+ int i;
+ Assert.IsFalse(list.Find(pred, out i));
+ list.AddAll<int>(new int[] { 4, 22, 67, 37 });
+ Assert.IsFalse(list.Find(pred, out i));
+ list.AddAll<int>(new int[] { 45, 122, 675, 137 });
+ Assert.IsTrue(list.Find(pred, out i));
+ Assert.AreEqual(45, i);
+ }
+
+ [Test]
+ public void FindLast()
+ {
+ int i;
+ Assert.IsFalse(list.FindLast(pred, out i));
+ list.AddAll<int>(new int[] { 4, 22, 67, 37 });
+ Assert.IsFalse(list.FindLast(pred, out i));
+ list.AddAll<int>(new int[] { 45, 122, 675, 137 });
+ Assert.IsTrue(list.FindLast(pred, out i));
+ Assert.AreEqual(675, i);
+ }
+
+ [Test]
+ public void FindIndex()
+ {
+ Assert.IsFalse(0 <= list.FindIndex(pred));
+ list.AddAll<int>(new int[] { 4, 22, 67, 37 });
+ Assert.IsFalse(0 <= list.FindIndex(pred));
+ list.AddAll<int>(new int[] { 45, 122, 675, 137 });
+ Assert.AreEqual(3, list.FindIndex(pred));
+ }
+
+ [Test]
+ public void FindLastIndex()
+ {
+ Assert.IsFalse(0 <= list.FindLastIndex(pred));
+ list.AddAll<int>(new int[] { 4, 22, 67, 37 });
+ Assert.IsFalse(0 <= list.FindLastIndex(pred));
+ list.AddAll<int>(new int[] { 45, 122, 675, 137 });
+ Assert.AreEqual(7, list.FindLastIndex(pred));
+ }
+ }
+
+ [TestFixture]
+ public class UniqueItems
+ {
+ private TreeSet<int> list;
+
+ [SetUp]
+ public void Init() { list = new TreeSet<int>(); }
+
+ [TearDown]
+ public void Dispose() { list = null; }
+
+ [Test]
+ public void Test()
+ {
+ Assert.IsTrue(IC.seteq(list.UniqueItems()));
+ Assert.IsTrue(IC.seteq(list.ItemMultiplicities()));
+ list.AddAll<int>(new int[] { 7, 9, 7 });
+ Assert.IsTrue(IC.seteq(list.UniqueItems(), 7, 9));
+ Assert.IsTrue(IC.seteq(list.ItemMultiplicities(), 7, 1, 9, 1));
+ }
+ }
+
+ [TestFixture]
+ public class ArrayTest
+ {
+ private TreeSet<int> tree;
+
+ int[] a;
+
+
+ [SetUp]
+ public void Init()
+ {
+ tree = new TreeSet<int>(new IC());
+ a = new int[10];
+ for (int i = 0; i < 10; i++)
+ a[i] = 1000 + i;
+ }
+
+
+ [TearDown]
+ public void Dispose() { tree = null; }
+
+
+ private string aeq(int[] a, params int[] b)
+ {
+ if (a.Length != b.Length)
+ return "Lengths differ: " + a.Length + " != " + b.Length;
+
+ for (int i = 0; i < a.Length; i++)
+ if (a[i] != b[i])
+ return String.Format("{0}'th elements differ: {1} != {2}", i, a[i], b[i]);
+
+ return "Alles klar";
+ }
+
+
+ [Test]
+ public void ToArray()
+ {
+ Assert.AreEqual("Alles klar", aeq(tree.ToArray()));
+ tree.Add(7);
+ tree.Add(4);
+ Assert.AreEqual("Alles klar", aeq(tree.ToArray(), 4, 7));
+ }
+
+
+ [Test]
+ public void CopyTo()
+ {
+ tree.CopyTo(a, 1);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009));
+ tree.Add(6);
+ tree.CopyTo(a, 2);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 6, 1003, 1004, 1005, 1006, 1007, 1008, 1009));
+ tree.Add(4);
+ tree.Add(9);
+ tree.CopyTo(a, 4);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 6, 1003, 4, 6, 9, 1007, 1008, 1009));
+ tree.Clear();
+ tree.Add(7);
+ tree.CopyTo(a, 9);
+ Assert.AreEqual("Alles klar", aeq(a, 1000, 1001, 6, 1003, 4, 6, 9, 1007, 1008, 7));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void CopyToBad()
+ {
+ tree.CopyTo(a, 11);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void CopyToBad2()
+ {
+ tree.CopyTo(a, -1);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void CopyToTooFar()
+ {
+ tree.Add(3);
+ tree.Add(4);
+ tree.CopyTo(a, 9);
+ }
+ }
+
+
+
+
+ [TestFixture]
+ public class Remove
+ {
+ private TreeSet<int> tree;
+
+
+ [SetUp]
+ public void Init()
+ {
+ tree = new TreeSet<int>(new IC());
+ for (int i = 10; i < 20; i++)
+ {
+ tree.Add(i);
+ tree.Add(i + 10);
+ }
+ }
+
+
+ [Test]
+ public void SmallTrees()
+ {
+ tree.Clear();
+ tree.Add(7);
+ tree.Add(9);
+ Assert.IsTrue(tree.Remove(7));
+ Assert.IsTrue(tree.Check(""));
+ }
+
+
+ [Test]
+ public void ByIndex()
+ {
+ //Remove root!
+ int n = tree.Count;
+ int i = tree[10];
+
+ tree.RemoveAt(10);
+ Assert.IsTrue(tree.Check(""));
+ Assert.IsFalse(tree.Contains(i));
+ Assert.AreEqual(n - 1, tree.Count);
+
+ //Low end
+ i = tree.FindMin();
+ tree.RemoveAt(0);
+ Assert.IsTrue(tree.Check(""));
+ Assert.IsFalse(tree.Contains(i));
+ Assert.AreEqual(n - 2, tree.Count);
+
+ //high end
+ i = tree.FindMax();
+ tree.RemoveAt(tree.Count - 1);
+ Assert.IsTrue(tree.Check(""));
+ Assert.IsFalse(tree.Contains(i));
+ Assert.AreEqual(n - 3, tree.Count);
+
+ //Some leaf
+ i = 18;
+ tree.RemoveAt(7);
+ Assert.IsTrue(tree.Check(""));
+ Assert.IsFalse(tree.Contains(i));
+ Assert.AreEqual(n - 4, tree.Count);
+ }
+
+
+ [Test]
+ public void AlmostEmpty()
+ {
+ //Almost empty
+ tree.Clear();
+ tree.Add(3);
+ tree.RemoveAt(0);
+ Assert.IsTrue(tree.Check(""));
+ Assert.IsFalse(tree.Contains(3));
+ Assert.AreEqual(0, tree.Count);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException), "Index out of range for sequenced collectionvalue")]
+ public void Empty()
+ {
+ tree.Clear();
+ tree.RemoveAt(0);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException), "Index out of range for sequenced collectionvalue")]
+ public void HighIndex()
+ {
+ tree.RemoveAt(tree.Count);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException), "Index out of range for sequenced collectionvalue")]
+ public void LowIndex()
+ {
+ tree.RemoveAt(-1);
+ }
+
+
+ [Test]
+ public void Normal()
+ {
+ Assert.IsFalse(tree.Remove(-20));
+
+ //No demote case, with move_item
+ Assert.IsTrue(tree.Remove(20));
+ Assert.IsTrue(tree.Check("T1"));
+ Assert.IsFalse(tree.Remove(20));
+
+ //plain case 2
+ Assert.IsTrue(tree.Remove(14));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+
+ //case 1b
+ Assert.IsTrue(tree.Remove(25));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+
+ //case 1c
+ Assert.IsTrue(tree.Remove(29));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+
+ //1a (terminating)
+ Assert.IsTrue(tree.Remove(10));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+
+ //2+1b
+ Assert.IsTrue(tree.Remove(12));
+ Assert.IsTrue(tree.Remove(11));
+
+ //1a+1b
+ Assert.IsTrue(tree.Remove(18));
+ Assert.IsTrue(tree.Remove(13));
+ Assert.IsTrue(tree.Remove(15));
+
+ //2+1c
+ for (int i = 0; i < 10; i++)
+ tree.Add(50 - 2 * i);
+
+ Assert.IsTrue(tree.Remove(42));
+ Assert.IsTrue(tree.Remove(38));
+ Assert.IsTrue(tree.Remove(28));
+ Assert.IsTrue(tree.Remove(40));
+
+ //
+ Assert.IsTrue(tree.Remove(16));
+ Assert.IsTrue(tree.Remove(23));
+ Assert.IsTrue(tree.Remove(17));
+ Assert.IsTrue(tree.Remove(19));
+ Assert.IsTrue(tree.Remove(50));
+ Assert.IsTrue(tree.Remove(26));
+ Assert.IsTrue(tree.Remove(21));
+ Assert.IsTrue(tree.Remove(22));
+ Assert.IsTrue(tree.Remove(24));
+ for (int i = 0; i < 48; i++)
+ tree.Remove(i);
+
+ //Almost empty tree:
+ Assert.IsFalse(tree.Remove(26));
+ Assert.IsTrue(tree.Remove(48));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+
+ //Empty tree:
+ Assert.IsFalse(tree.Remove(26));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ tree = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class PredecessorStructure
+ {
+ private TreeSet<int> tree;
+
+
+ [SetUp]
+ public void Init()
+ {
+ tree = new TreeSet<int>(new IC());
+ }
+
+
+ private void loadup()
+ {
+ for (int i = 0; i < 20; i++)
+ tree.Add(2 * i);
+ }
+
+
+ [Test]
+ public void Predecessor()
+ {
+ loadup();
+ Assert.AreEqual(6, tree.Predecessor(7));
+ Assert.AreEqual(6, tree.Predecessor(8));
+
+ //The bottom
+ Assert.AreEqual(0, tree.Predecessor(1));
+
+ //The top
+ Assert.AreEqual(38, tree.Predecessor(39));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void PredecessorTooLow1()
+ {
+ tree.Predecessor(-2);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void PredecessorTooLow2()
+ {
+ tree.Predecessor(0);
+ }
+
+
+ [Test]
+ public void WeakPredecessor()
+ {
+ loadup();
+ Assert.AreEqual(6, tree.WeakPredecessor(7));
+ Assert.AreEqual(8, tree.WeakPredecessor(8));
+
+ //The bottom
+ Assert.AreEqual(0, tree.WeakPredecessor(1));
+ Assert.AreEqual(0, tree.WeakPredecessor(0));
+
+ //The top
+ Assert.AreEqual(38, tree.WeakPredecessor(39));
+ Assert.AreEqual(38, tree.WeakPredecessor(38));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void WeakPredecessorTooLow1()
+ {
+ tree.WeakPredecessor(-2);
+ }
+
+
+ [Test]
+ public void Successor()
+ {
+ loadup();
+ Assert.AreEqual(8, tree.Successor(7));
+ Assert.AreEqual(10, tree.Successor(8));
+
+ //The bottom
+ Assert.AreEqual(2, tree.Successor(0));
+ Assert.AreEqual(0, tree.Successor(-1));
+
+ //The top
+ Assert.AreEqual(38, tree.Successor(37));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void SuccessorTooHigh1()
+ {
+ tree.Successor(38);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void SuccessorTooHigh2()
+ {
+ tree.Successor(39);
+ }
+
+
+ [Test]
+ public void WeakSuccessor()
+ {
+ loadup();
+ Assert.AreEqual(6, tree.WeakSuccessor(6));
+ Assert.AreEqual(8, tree.WeakSuccessor(7));
+
+ //The bottom
+ Assert.AreEqual(0, tree.WeakSuccessor(-1));
+ Assert.AreEqual(0, tree.WeakSuccessor(0));
+
+ //The top
+ Assert.AreEqual(38, tree.WeakSuccessor(37));
+ Assert.AreEqual(38, tree.WeakSuccessor(38));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void WeakSuccessorTooHigh1()
+ {
+ tree.WeakSuccessor(39);
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ tree = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class PriorityQueue
+ {
+ private TreeSet<int> tree;
+
+
+ [SetUp]
+ public void Init()
+ {
+ tree = new TreeSet<int>(new IC());
+ }
+
+
+ private void loadup()
+ {
+ foreach (int i in new int[] { 1, 2, 3, 4 })
+ tree.Add(i);
+ }
+
+
+ [Test]
+ public void Normal()
+ {
+ loadup();
+ Assert.AreEqual(1, tree.FindMin());
+ Assert.AreEqual(4, tree.FindMax());
+ Assert.AreEqual(1, tree.DeleteMin());
+ Assert.AreEqual(4, tree.DeleteMax());
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+ Assert.AreEqual(2, tree.FindMin());
+ Assert.AreEqual(3, tree.FindMax());
+ Assert.AreEqual(2, tree.DeleteMin());
+ Assert.AreEqual(3, tree.DeleteMax());
+ Assert.IsTrue(tree.Check("Normal test 2"), "Bad tree");
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void Empty1()
+ {
+ tree.FindMin();
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void Empty2()
+ {
+ tree.FindMax();
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void Empty3()
+ {
+ tree.DeleteMin();
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NoSuchItemException))]
+ public void Empty4()
+ {
+ tree.DeleteMax();
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ tree = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class IndexingAndCounting
+ {
+ private TreeSet<int> tree;
+
+
+ [SetUp]
+ public void Init()
+ {
+ tree = new TreeSet<int>(new IC());
+ }
+
+
+ private void populate()
+ {
+ tree.Add(30);
+ tree.Add(50);
+ tree.Add(10);
+ tree.Add(70);
+ }
+
+
+ [Test]
+ public void ToArray()
+ {
+ populate();
+
+ int[] a = tree.ToArray();
+
+ Assert.AreEqual(4, a.Length);
+ Assert.AreEqual(10, a[0]);
+ Assert.AreEqual(30, a[1]);
+ Assert.AreEqual(50, a[2]);
+ Assert.AreEqual(70, a[3]);
+ }
+
+
+ [Test]
+ public void GoodIndex()
+ {
+ Assert.AreEqual(-1, tree.IndexOf(20));
+ Assert.AreEqual(-1, tree.LastIndexOf(20));
+ populate();
+ Assert.AreEqual(10, tree[0]);
+ Assert.AreEqual(30, tree[1]);
+ Assert.AreEqual(50, tree[2]);
+ Assert.AreEqual(70, tree[3]);
+ Assert.AreEqual(0, tree.IndexOf(10));
+ Assert.AreEqual(1, tree.IndexOf(30));
+ Assert.AreEqual(2, tree.IndexOf(50));
+ Assert.AreEqual(3, tree.IndexOf(70));
+ Assert.AreEqual(~1, tree.IndexOf(20));
+ Assert.AreEqual(~0, tree.IndexOf(0));
+ Assert.AreEqual(~4, tree.IndexOf(90));
+ Assert.AreEqual(0, tree.LastIndexOf(10));
+ Assert.AreEqual(1, tree.LastIndexOf(30));
+ Assert.AreEqual(2, tree.LastIndexOf(50));
+ Assert.AreEqual(3, tree.LastIndexOf(70));
+ Assert.AreEqual(~1, tree.LastIndexOf(20));
+ Assert.AreEqual(~0, tree.LastIndexOf(0));
+ Assert.AreEqual(~4, tree.LastIndexOf(90));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void IndexTooLarge()
+ {
+ populate();
+ Console.WriteLine(tree[4]);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(IndexOutOfRangeException))]
+ public void IndexTooSmall()
+ {
+ populate();
+ Console.WriteLine(tree[-1]);
+ }
+
+
+ [Test]
+ public void FilledTreeOutsideInput()
+ {
+ populate();
+ Assert.AreEqual(0, tree.CountFrom(90));
+ Assert.AreEqual(0, tree.CountFromTo(-20, 0));
+ Assert.AreEqual(0, tree.CountFromTo(80, 100));
+ Assert.AreEqual(0, tree.CountTo(0));
+ Assert.AreEqual(4, tree.CountTo(90));
+ Assert.AreEqual(4, tree.CountFromTo(-20, 90));
+ Assert.AreEqual(4, tree.CountFrom(0));
+ }
+
+
+ [Test]
+ public void FilledTreeIntermediateInput()
+ {
+ populate();
+ Assert.AreEqual(3, tree.CountFrom(20));
+ Assert.AreEqual(1, tree.CountFromTo(20, 40));
+ Assert.AreEqual(2, tree.CountTo(40));
+ }
+
+
+ [Test]
+ public void FilledTreeMatchingInput()
+ {
+ populate();
+ Assert.AreEqual(3, tree.CountFrom(30));
+ Assert.AreEqual(2, tree.CountFromTo(30, 70));
+ Assert.AreEqual(0, tree.CountFromTo(50, 30));
+ Assert.AreEqual(0, tree.CountFromTo(50, 50));
+ Assert.AreEqual(0, tree.CountTo(10));
+ Assert.AreEqual(2, tree.CountTo(50));
+ }
+
+
+ [Test]
+ public void CountEmptyTree()
+ {
+ Assert.AreEqual(0, tree.CountFrom(20));
+ Assert.AreEqual(0, tree.CountFromTo(20, 40));
+ Assert.AreEqual(0, tree.CountTo(40));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ tree = null;
+ }
+ }
+
+
+
+
+ namespace ModificationCheck
+ {
+ [TestFixture]
+ public class Enumerator
+ {
+ private TreeSet<int> tree;
+
+ private SCG.IEnumerator<int> e;
+
+
+ [SetUp]
+ public void Init()
+ {
+ tree = new TreeSet<int>(new IC());
+ for (int i = 0; i < 10; i++)
+ tree.Add(i);
+
+ e = tree.GetEnumerator();
+ }
+
+
+ [Test]
+ public void CurrentAfterModification()
+ {
+ e.MoveNext();
+ tree.Add(34);
+ Assert.AreEqual(0, e.Current);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void MoveNextAfterAdd()
+ {
+ tree.Add(34);
+ e.MoveNext();
+ }
+
+
+
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void MoveNextAfterRemove()
+ {
+ tree.Remove(34);
+ e.MoveNext();
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void MoveNextAfterClear()
+ {
+ tree.Clear();
+ e.MoveNext();
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ tree = null;
+ e = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class RangeEnumerator
+ {
+ private TreeSet<int> tree;
+
+ private SCG.IEnumerator<int> e;
+
+
+ [SetUp]
+ public void Init()
+ {
+ tree = new TreeSet<int>(new IC());
+ for (int i = 0; i < 10; i++)
+ tree.Add(i);
+
+ e = tree.RangeFromTo(3, 7).GetEnumerator();
+ }
+
+
+ [Test]
+ public void CurrentAfterModification()
+ {
+ e.MoveNext();
+ tree.Add(34);
+ Assert.AreEqual(3, e.Current);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void MoveNextAfterAdd()
+ {
+ tree.Add(34);
+ e.MoveNext();
+ }
+
+
+
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void MoveNextAfterRemove()
+ {
+ tree.Remove(34);
+ e.MoveNext();
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(CollectionModifiedException))]
+ public void MoveNextAfterClear()
+ {
+ tree.Clear();
+ e.MoveNext();
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ tree = null;
+ e = null;
+ }
+ }
+ }
+
+
+
+
+ namespace PathcopyPersistence
+ {
+ [TestFixture]
+ public class Navigation
+ {
+ private TreeSet<int> tree, snap;
+
+ private SCG.IComparer<int> ic;
+
+
+ [SetUp]
+ public void Init()
+ {
+ ic = new IC();
+ tree = new TreeSet<int>(ic);
+ for (int i = 0; i <= 20; i++)
+ tree.Add(2 * i + 1);
+
+ snap = (TreeSet<int>)tree.Snapshot();
+ for (int i = 0; i <= 10; i++)
+ tree.Remove(4 * i + 1);
+ }
+
+
+ private bool twomodeleven(int i)
+ {
+ return i % 11 == 2;
+ }
+
+
+ [Test]
+ public void InternalEnum()
+ {
+ Assert.IsTrue(IC.eq(snap.FindAll(new Fun<int, bool>(twomodeleven)), 13, 35));
+ }
+
+
+ public void MoreCut() { }
+
+ [Test]
+ public void Cut()
+ {
+ int lo, hi;
+ bool lv, hv;
+
+ Assert.IsFalse(snap.Cut(new HigherOrder.CubeRoot(64), out lo, out lv, out hi, out hv));
+ Assert.IsTrue(lv && hv);
+ Assert.AreEqual(5, hi);
+ Assert.AreEqual(3, lo);
+ Assert.IsTrue(snap.Cut(new HigherOrder.CubeRoot(125), out lo, out lv, out hi, out hv));
+ Assert.IsTrue(lv && hv);
+ Assert.AreEqual(7, hi);
+ Assert.AreEqual(3, lo);
+ Assert.IsFalse(snap.Cut(new HigherOrder.CubeRoot(125000), out lo, out lv, out hi, out hv));
+ Assert.IsTrue(lv && !hv);
+ Assert.AreEqual(41, lo);
+ Assert.IsFalse(snap.Cut(new HigherOrder.CubeRoot(-27), out lo, out lv, out hi, out hv));
+ Assert.IsTrue(!lv && hv);
+ Assert.AreEqual(1, hi);
+ }
+
+
+ [Test]
+ public void Range()
+ {
+ Assert.IsTrue(IC.eq(snap.RangeFromTo(5, 16), 5, 7, 9, 11, 13, 15));
+ Assert.IsTrue(IC.eq(snap.RangeFromTo(5, 17), 5, 7, 9, 11, 13, 15));
+ Assert.IsTrue(IC.eq(snap.RangeFromTo(6, 16), 7, 9, 11, 13, 15));
+ //Assert.AreEqual(snap.RangeFromTo(6, 16).Count, 5);
+ }
+
+
+ [Test]
+ public void Contains()
+ {
+ Assert.IsTrue(snap.Contains(5));
+ }
+
+
+ [Test]
+ public void FindMin()
+ {
+ Assert.AreEqual(1, snap.FindMin());
+ }
+
+
+ [Test]
+ public void FindMax()
+ {
+ Assert.AreEqual(41, snap.FindMax());
+ }
+
+
+ [Test]
+ public void Predecessor()
+ {
+ Assert.AreEqual(13, snap.Predecessor(15));
+ Assert.AreEqual(15, snap.Predecessor(16));
+ Assert.AreEqual(15, snap.Predecessor(17));
+ Assert.AreEqual(17, snap.Predecessor(18));
+ }
+
+
+ [Test]
+ public void Successor()
+ {
+ Assert.AreEqual(17, snap.Successor(15));
+ Assert.AreEqual(17, snap.Successor(16));
+ Assert.AreEqual(19, snap.Successor(17));
+ Assert.AreEqual(19, snap.Successor(18));
+ }
+
+
+ [Test]
+ public void WeakPredecessor()
+ {
+ Assert.AreEqual(15, snap.WeakPredecessor(15));
+ Assert.AreEqual(15, snap.WeakPredecessor(16));
+ Assert.AreEqual(17, snap.WeakPredecessor(17));
+ Assert.AreEqual(17, snap.WeakPredecessor(18));
+ }
+
+
+ [Test]
+ public void WeakSuccessor()
+ {
+ Assert.AreEqual(15, snap.WeakSuccessor(15));
+ Assert.AreEqual(17, snap.WeakSuccessor(16));
+ Assert.AreEqual(17, snap.WeakSuccessor(17));
+ Assert.AreEqual(19, snap.WeakSuccessor(18));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NotSupportedException), "Indexing not supported for snapshots")]
+ public void CountTo()
+ {
+ int j = snap.CountTo(15);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NotSupportedException), "Indexing not supported for snapshots")]
+ public void Indexing()
+ {
+ int j = snap[4];
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(NotSupportedException), "Indexing not supported for snapshots")]
+ public void Indexing2()
+ {
+ int j = snap.IndexOf(5);
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ tree = null;
+ ic = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class Single
+ {
+ private TreeSet<int> tree;
+
+ private SCG.IComparer<int> ic;
+
+
+ [SetUp]
+ public void Init()
+ {
+ ic = new IC();
+ tree = new TreeSet<int>(ic);
+ for (int i = 0; i < 10; i++)
+ tree.Add(2 * i + 1);
+ }
+
+
+ [Test]
+ public void EnumerationWithAdd()
+ {
+ int[] orig = new int[] { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 };
+ int i = 0;
+ TreeSet<int> snap = (TreeSet<int>)tree.Snapshot();
+
+ foreach (int j in snap)
+ {
+ Assert.AreEqual(1 + 2 * i++, j);
+ tree.Add(21 - j);
+ Assert.IsTrue(snap.Check("M"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+ Assert.IsTrue(tree.Check("Tree"), "Bad tree!");
+ }
+ }
+
+
+ [Test]
+ public void Remove()
+ {
+ int[] orig = new int[] { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 };
+ TreeSet<int> snap = (TreeSet<int>)tree.Snapshot();
+
+ Assert.IsTrue(snap.Check("Snap"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+ tree.Remove(19);
+ Assert.IsTrue(snap.Check("Snap"), "Bad snap!");
+ Assert.IsTrue(tree.Check("Tree"), "Bad tree!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+ }
+
+
+ [Test]
+ public void RemoveNormal()
+ {
+ tree.Clear();
+ for (int i = 10; i < 20; i++)
+ {
+ tree.Add(i);
+ tree.Add(i + 10);
+ }
+
+ int[] orig = new int[] { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 };
+ TreeSet<int> snap = (TreeSet<int>)tree.Snapshot();
+
+ Assert.IsFalse(tree.Remove(-20));
+ Assert.IsTrue(snap.Check("Snap"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+
+ //No demote case, with move_item
+ Assert.IsTrue(tree.Remove(20));
+ Assert.IsTrue(tree.Check("T1"));
+ Assert.IsTrue(snap.Check("Snap"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+ Assert.IsFalse(tree.Remove(20));
+
+ //plain case 2
+ tree.Snapshot();
+ Assert.IsTrue(tree.Remove(14));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+ Assert.IsTrue(snap.Check("Snap"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+
+ //case 1b
+ Assert.IsTrue(tree.Remove(25));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+ Assert.IsTrue(snap.Check("Snap"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+
+ //case 1c
+ Assert.IsTrue(tree.Remove(29));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+ Assert.IsTrue(snap.Check("Snap"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+
+ //1a (terminating)
+ Assert.IsTrue(tree.Remove(10));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+ Assert.IsTrue(snap.Check("Snap"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+
+ //2+1b
+ Assert.IsTrue(tree.Remove(12));
+ tree.Snapshot();
+ Assert.IsTrue(tree.Remove(11));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+ Assert.IsTrue(snap.Check("Snap"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+
+ //1a+1b
+ Assert.IsTrue(tree.Remove(18));
+ Assert.IsTrue(tree.Remove(13));
+ Assert.IsTrue(tree.Remove(15));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+ Assert.IsTrue(snap.Check("Snap"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+
+ //2+1c
+ for (int i = 0; i < 10; i++)
+ tree.Add(50 - 2 * i);
+
+ Assert.IsTrue(tree.Remove(42));
+ Assert.IsTrue(tree.Remove(38));
+ Assert.IsTrue(tree.Remove(28));
+ Assert.IsTrue(tree.Remove(40));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+ Assert.IsTrue(snap.Check("Snap"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+
+ //
+ Assert.IsTrue(tree.Remove(16));
+ Assert.IsTrue(tree.Remove(23));
+ Assert.IsTrue(tree.Remove(17));
+ Assert.IsTrue(tree.Remove(19));
+ Assert.IsTrue(tree.Remove(50));
+ Assert.IsTrue(tree.Remove(26));
+ Assert.IsTrue(tree.Remove(21));
+ Assert.IsTrue(tree.Remove(22));
+ Assert.IsTrue(tree.Remove(24));
+ for (int i = 0; i < 48; i++)
+ tree.Remove(i);
+
+ //Almost empty tree:
+ Assert.IsFalse(tree.Remove(26));
+ Assert.IsTrue(tree.Remove(48));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+ Assert.IsTrue(snap.Check("Snap"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+
+ //Empty tree:
+ Assert.IsFalse(tree.Remove(26));
+ Assert.IsTrue(tree.Check("Normal test 1"), "Bad tree");
+ Assert.IsTrue(snap.Check("Snap"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+ }
+
+
+ [Test]
+ public void Add()
+ {
+ int[] orig = new int[] { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 };
+ TreeSet<int> snap = (TreeSet<int>)tree.Snapshot();
+
+ Assert.IsTrue(snap.Check("M"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+ Assert.IsTrue(tree.Check("Tree"), "Bad tree!");
+ tree.Add(10);
+ Assert.IsTrue(snap.Check("M"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+ Assert.IsTrue(tree.Check("Tree"), "Bad tree!");
+ tree.Add(16);
+ Assert.IsTrue(snap.Check("M"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+ Assert.IsTrue(tree.Check("Tree"), "Bad tree!");
+
+ //Promote+zigzig
+ tree.Add(40);
+ Assert.IsTrue(snap.Check("M"), "Bad snap!");
+ Assert.IsTrue(tree.Check("Tree"), "Bad tree!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+ for (int i = 1; i < 4; i++)
+ tree.Add(40 - 2 * i);
+
+ Assert.IsTrue(snap.Check("M"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+ Assert.IsTrue(tree.Check("Tree"), "Bad tree!");
+
+ //Zigzag:
+ tree.Add(32);
+ Assert.IsTrue(snap.Check("M"), "Bad snap!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+ Assert.IsTrue(tree.Check("Tree"), "Bad tree!");
+ }
+
+
+ [Test]
+ public void Clear()
+ {
+ int[] orig = new int[] { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 };
+ TreeSet<int> snap = (TreeSet<int>)tree.Snapshot();
+
+ tree.Clear();
+ Assert.IsTrue(snap.Check("Snap"), "Bad snap!");
+ Assert.IsTrue(tree.Check("Tree"), "Bad tree!");
+ Assert.IsTrue(IC.eq(snap, orig), "Snap was changed!");
+ Assert.AreEqual(0, tree.Count);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(InvalidOperationException), "Cannot snapshot a snapshot")]
+ public void SnapSnap()
+ {
+ TreeSet<int> snap = (TreeSet<int>)tree.Snapshot();
+
+ snap.Snapshot();
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ tree = null;
+ ic = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class Multiple
+ {
+ private TreeSet<int> tree;
+
+ private SCG.IComparer<int> ic;
+
+
+ private bool eq(SCG.IEnumerable<int> me, int[] that)
+ {
+ int i = 0, maxind = that.Length - 1;
+
+ foreach (int item in me)
+ if (i > maxind || ic.Compare(item, that[i++]) != 0)
+ return false;
+
+ return true;
+ }
+
+
+ [SetUp]
+ public void Init()
+ {
+ ic = new IC();
+ tree = new TreeSet<int>(ic);
+ for (int i = 0; i < 10; i++)
+ tree.Add(2 * i + 1);
+ }
+
+
+ [Test]
+ public void First()
+ {
+ TreeSet<int>[] snaps = new TreeSet<int>[10];
+
+ for (int i = 0; i < 10; i++)
+ {
+ snaps[i] = (TreeSet<int>)(tree.Snapshot());
+ tree.Add(2 * i);
+ }
+
+ for (int i = 0; i < 10; i++)
+ {
+ Assert.AreEqual(i + 10, snaps[i].Count);
+ }
+
+ snaps[5] = null;
+ snaps[9] = null;
+ GC.Collect();
+ snaps[8].Dispose();
+ tree.Remove(14);
+
+ int[] res = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 19 };
+ int[] snap7 = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 17, 19 };
+ int[] snap3 = new int[] { 0, 1, 2, 3, 4, 5, 7, 9, 11, 13, 15, 17, 19 };
+
+ Assert.IsTrue(IC.eq(snaps[3], snap3), "Snap 3 was changed!");
+ Assert.IsTrue(IC.eq(snaps[7], snap7), "Snap 7 was changed!");
+ Assert.IsTrue(IC.eq(tree, res));
+ Assert.IsTrue(tree.Check("B"));
+ Assert.IsTrue(snaps[3].Check("B"));
+ Assert.IsTrue(snaps[7].Check("B"));
+ }
+
+
+ [Test]
+ public void CollectingTheMaster()
+ {
+ TreeSet<int>[] snaps = new TreeSet<int>[10];
+
+ for (int i = 0; i < 10; i++)
+ {
+ snaps[i] = (TreeSet<int>)(tree.Snapshot());
+ tree.Add(2 * i);
+ }
+
+ tree = null;
+ GC.Collect();
+ for (int i = 0; i < 10; i++)
+ {
+ Assert.AreEqual(i + 10, snaps[i].Count);
+ }
+
+ snaps[5] = null;
+ snaps[9] = null;
+ GC.Collect();
+ snaps[8].Dispose();
+
+ int[] snap7 = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 17, 19 };
+ int[] snap3 = new int[] { 0, 1, 2, 3, 4, 5, 7, 9, 11, 13, 15, 17, 19 };
+
+ Assert.IsTrue(IC.eq(snaps[3], snap3), "Snap 3 was changed!");
+ Assert.IsTrue(IC.eq(snaps[7], snap7), "Snap 7 was changed!");
+ Assert.IsTrue(snaps[3].Check("B"));
+ Assert.IsTrue(snaps[7].Check("B"));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ tree = null;
+ ic = null;
+ }
+ }
+ }
+
+
+
+
+ namespace HigherOrder
+ {
+ internal class CubeRoot: IComparable<int>
+ {
+ private int c;
+
+
+ internal CubeRoot(int c) { this.c = c; }
+
+
+ public int CompareTo(int that) { return c - that * that * that; }
+ public bool Equals(int that) { return c == that * that * that; }
+ }
+
+
+
+ class Interval: IComparable<int>
+ {
+ private int b, t;
+
+
+ internal Interval(int b, int t) { this.b = b; this.t = t; }
+
+
+ public int CompareTo(int that) { return that < b ? 1 : that > t ? -1 : 0; }
+ public bool Equals(int that) { return that >= b && that <= t; }
+ }
+
+
+
+ [TestFixture]
+ public class Simple
+ {
+ private TreeSet<int> tree;
+
+ private SCG.IComparer<int> ic;
+
+
+ [SetUp]
+ public void Init()
+ {
+ ic = new IC();
+ tree = new TreeSet<int>(ic);
+ }
+
+
+ private bool never(int i) { return false; }
+
+
+ private bool always(int i) { return true; }
+
+
+ private bool even(int i) { return i % 2 == 0; }
+
+
+ private string themap(int i) { return String.Format("AA {0,4} BB", i); }
+
+
+ private string badmap(int i) { return String.Format("AA {0} BB", i); }
+
+
+ private int appfield1;
+
+ private int appfield2;
+
+
+ private void apply(int i) { appfield1++; appfield2 += i * i; }
+
+
+ [Test]
+ public void Apply()
+ {
+ Simple simple1 = new Simple();
+
+ tree.Apply(new Act<int>(simple1.apply));
+ Assert.AreEqual(0, simple1.appfield1);
+ Assert.AreEqual(0, simple1.appfield2);
+
+ Simple simple2 = new Simple();
+
+ for (int i = 0; i < 10; i++) tree.Add(i);
+
+ tree.Apply(new Act<int>(simple2.apply));
+ Assert.AreEqual(10, simple2.appfield1);
+ Assert.AreEqual(285, simple2.appfield2);
+ }
+
+
+ [Test]
+ public void All()
+ {
+ Assert.IsTrue(tree.All(new Fun<int, bool>(never)));
+ Assert.IsTrue(tree.All(new Fun<int, bool>(even)));
+ Assert.IsTrue(tree.All(new Fun<int, bool>(always)));
+ for (int i = 0; i < 10; i++) tree.Add(i);
+
+ Assert.IsFalse(tree.All(new Fun<int, bool>(never)));
+ Assert.IsFalse(tree.All(new Fun<int, bool>(even)));
+ Assert.IsTrue(tree.All(new Fun<int, bool>(always)));
+ tree.Clear();
+ for (int i = 0; i < 10; i++) tree.Add(i * 2);
+
+ Assert.IsFalse(tree.All(new Fun<int, bool>(never)));
+ Assert.IsTrue(tree.All(new Fun<int, bool>(even)));
+ Assert.IsTrue(tree.All(new Fun<int, bool>(always)));
+ tree.Clear();
+ for (int i = 0; i < 10; i++) tree.Add(i * 2 + 1);
+
+ Assert.IsFalse(tree.All(new Fun<int, bool>(never)));
+ Assert.IsFalse(tree.All(new Fun<int, bool>(even)));
+ Assert.IsTrue(tree.All(new Fun<int, bool>(always)));
+ }
+
+
+ [Test]
+ public void Exists()
+ {
+ Assert.IsFalse(tree.Exists(new Fun<int, bool>(never)));
+ Assert.IsFalse(tree.Exists(new Fun<int, bool>(even)));
+ Assert.IsFalse(tree.Exists(new Fun<int, bool>(always)));
+ for (int i = 0; i < 10; i++) tree.Add(i);
+
+ Assert.IsFalse(tree.Exists(new Fun<int, bool>(never)));
+ Assert.IsTrue(tree.Exists(new Fun<int, bool>(even)));
+ Assert.IsTrue(tree.Exists(new Fun<int, bool>(always)));
+ tree.Clear();
+ for (int i = 0; i < 10; i++) tree.Add(i * 2);
+
+ Assert.IsFalse(tree.Exists(new Fun<int, bool>(never)));
+ Assert.IsTrue(tree.Exists(new Fun<int, bool>(even)));
+ Assert.IsTrue(tree.Exists(new Fun<int, bool>(always)));
+ tree.Clear();
+ for (int i = 0; i < 10; i++) tree.Add(i * 2 + 1);
+
+ Assert.IsFalse(tree.Exists(new Fun<int, bool>(never)));
+ Assert.IsFalse(tree.Exists(new Fun<int, bool>(even)));
+ Assert.IsTrue(tree.Exists(new Fun<int, bool>(always)));
+ }
+
+
+ [Test]
+ public void FindAll()
+ {
+ Assert.AreEqual(0, tree.FindAll(new Fun<int, bool>(never)).Count);
+ for (int i = 0; i < 10; i++)
+ tree.Add(i);
+
+ Assert.AreEqual(0, tree.FindAll(new Fun<int, bool>(never)).Count);
+ Assert.AreEqual(10, tree.FindAll(new Fun<int, bool>(always)).Count);
+ Assert.AreEqual(5, tree.FindAll(new Fun<int, bool>(even)).Count);
+ Assert.IsTrue(((TreeSet<int>)tree.FindAll(new Fun<int, bool>(even))).Check("R"));
+ }
+
+
+ [Test]
+ public void Map()
+ {
+ Assert.AreEqual(0, tree.Map(new Fun<int,string>(themap), new SC()).Count);
+ for (int i = 0; i < 11; i++)
+ tree.Add(i * i * i);
+
+ IIndexedSorted<string> res = tree.Map(new Fun<int,string>(themap), new SC());
+
+ Assert.IsTrue(((TreeSet<string>)res).Check("R"));
+ Assert.AreEqual(11, res.Count);
+ Assert.AreEqual("AA 0 BB", res[0]);
+ Assert.AreEqual("AA 27 BB", res[3]);
+ Assert.AreEqual("AA 125 BB", res[5]);
+ Assert.AreEqual("AA 1000 BB", res[10]);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentException), "mapper not monotonic")]
+ public void BadMap()
+ {
+ for (int i = 0; i < 11; i++)
+ tree.Add(i * i * i);
+
+ ISorted<string> res = tree.Map(new Fun<int,string>(badmap), new SC());
+ }
+
+
+ [Test]
+ public void Cut()
+ {
+ for (int i = 0; i < 10; i++)
+ tree.Add(i);
+
+ int low, high;
+ bool lval, hval;
+
+ Assert.IsTrue(tree.Cut(new CubeRoot(27), out low, out lval, out high, out hval));
+ Assert.IsTrue(lval && hval);
+ Assert.AreEqual(4, high);
+ Assert.AreEqual(2, low);
+ Assert.IsFalse(tree.Cut(new CubeRoot(30), out low, out lval, out high, out hval));
+ Assert.IsTrue(lval && hval);
+ Assert.AreEqual(4, high);
+ Assert.AreEqual(3, low);
+ }
+
+
+ [Test]
+ public void CutInt()
+ {
+ for (int i = 0; i < 10; i++)
+ tree.Add(2 * i);
+
+ int low, high;
+ bool lval, hval;
+
+ Assert.IsFalse(tree.Cut(new IC(3), out low, out lval, out high, out hval));
+ Assert.IsTrue(lval && hval);
+ Assert.AreEqual(4, high);
+ Assert.AreEqual(2, low);
+ Assert.IsTrue(tree.Cut(new IC(6), out low, out lval, out high, out hval));
+ Assert.IsTrue(lval && hval);
+ Assert.AreEqual(8, high);
+ Assert.AreEqual(4, low);
+ }
+
+
+ [Test]
+ public void CutInterval()
+ {
+ for (int i = 0; i < 10; i++)
+ tree.Add(2 * i);
+
+ int lo, hi;
+ bool lv, hv;
+
+ Assert.IsTrue(tree.Cut(new Interval(5, 9), out lo, out lv, out hi, out hv));
+ Assert.IsTrue(lv && hv);
+ Assert.AreEqual(10, hi);
+ Assert.AreEqual(4, lo);
+ Assert.IsTrue(tree.Cut(new Interval(6, 10), out lo, out lv, out hi, out hv));
+ Assert.IsTrue(lv && hv);
+ Assert.AreEqual(12, hi);
+ Assert.AreEqual(4, lo);
+ for (int i = 0; i < 100; i++)
+ tree.Add(2 * i);
+
+ tree.Cut(new Interval(77, 105), out lo, out lv, out hi, out hv);
+ Assert.IsTrue(lv && hv);
+ Assert.AreEqual(106, hi);
+ Assert.AreEqual(76, lo);
+ tree.Cut(new Interval(5, 7), out lo, out lv, out hi, out hv);
+ Assert.IsTrue(lv && hv);
+ Assert.AreEqual(8, hi);
+ Assert.AreEqual(4, lo);
+ tree.Cut(new Interval(80, 110), out lo, out lv, out hi, out hv);
+ Assert.IsTrue(lv && hv);
+ Assert.AreEqual(112, hi);
+ Assert.AreEqual(78, lo);
+ }
+
+
+ [Test]
+ public void UpperCut()
+ {
+ for (int i = 0; i < 10; i++)
+ tree.Add(i);
+
+ int l, h;
+ bool lv, hv;
+
+ Assert.IsFalse(tree.Cut(new CubeRoot(1000), out l, out lv, out h, out hv));
+ Assert.IsTrue(lv && !hv);
+ Assert.AreEqual(9, l);
+ Assert.IsFalse(tree.Cut(new CubeRoot(-50), out l, out lv, out h, out hv));
+ Assert.IsTrue(!lv && hv);
+ Assert.AreEqual(0, h);
+ }
+
+
+ [TearDown]
+ public void Dispose() { ic = null; tree = null; }
+ }
+ }
+
+
+
+
+ namespace MultiOps
+ {
+ [TestFixture]
+ public class AddAll
+ {
+ private int sqr(int i) { return i * i; }
+
+
+ TreeSet<int> tree;
+
+
+ [SetUp]
+ public void Init() { tree = new TreeSet<int>(new IC()); }
+
+
+ [Test]
+ public void EmptyEmpty()
+ {
+ tree.AddAll(new FunEnumerable(0, new Fun<int,int>(sqr)));
+ Assert.AreEqual(0, tree.Count);
+ Assert.IsTrue(tree.Check());
+ }
+
+
+ [Test]
+ public void SomeEmpty()
+ {
+ for (int i = 4; i < 9; i++) tree.Add(i);
+
+ tree.AddAll(new FunEnumerable(0, new Fun<int,int>(sqr)));
+ Assert.AreEqual(5, tree.Count);
+ Assert.IsTrue(tree.Check());
+ }
+
+
+ [Test]
+ public void EmptySome()
+ {
+ tree.AddAll(new FunEnumerable(4, new Fun<int,int>(sqr)));
+ Assert.AreEqual(4, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.AreEqual(0, tree[0]);
+ Assert.AreEqual(1, tree[1]);
+ Assert.AreEqual(4, tree[2]);
+ Assert.AreEqual(9, tree[3]);
+ }
+
+
+ [Test]
+ public void SomeSome()
+ {
+ for (int i = 5; i < 9; i++) tree.Add(i);
+
+ tree.AddAll(new FunEnumerable(4, new Fun<int,int>(sqr)));
+ Assert.AreEqual(8, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.IsTrue(IC.eq(tree, 0, 1, 4, 5, 6, 7, 8, 9));
+ }
+
+
+ [TearDown]
+ public void Dispose() { tree = null; }
+ }
+
+
+
+ [TestFixture]
+ public class AddSorted
+ {
+ private int sqr(int i) { return i * i; }
+
+
+ private int bad(int i) { return i * (5 - i); }
+
+
+ TreeSet<int> tree;
+
+
+ [SetUp]
+ public void Init() { tree = new TreeSet<int>(new IC()); }
+
+
+ [Test]
+ public void EmptyEmpty()
+ {
+ tree.AddSorted(new FunEnumerable(0, new Fun<int,int>(sqr)));
+ Assert.AreEqual(0, tree.Count);
+ Assert.IsTrue(tree.Check());
+ }
+
+
+
+ [Test]
+ public void SomeEmpty()
+ {
+ for (int i = 4; i < 9; i++) tree.Add(i);
+
+ tree.AddSorted(new FunEnumerable(0, new Fun<int,int>(sqr)));
+ Assert.AreEqual(5, tree.Count);
+ Assert.IsTrue(tree.Check());
+ }
+
+
+
+ [Test]
+ public void EmptySome()
+ {
+ tree.AddSorted(new FunEnumerable(4, new Fun<int,int>(sqr)));
+ Assert.AreEqual(4, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.AreEqual(0, tree[0]);
+ Assert.AreEqual(1, tree[1]);
+ Assert.AreEqual(4, tree[2]);
+ Assert.AreEqual(9, tree[3]);
+ }
+
+
+
+ [Test]
+ public void SomeSome()
+ {
+ for (int i = 5; i < 9; i++) tree.Add(i);
+
+ tree.AddSorted(new FunEnumerable(4, new Fun<int,int>(sqr)));
+ Assert.AreEqual(8, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.IsTrue(IC.eq(tree, 0, 1, 4, 5, 6, 7, 8, 9));
+ }
+
+ [Test]
+ [ExpectedException(typeof(ArgumentException), "Argument not sorted")]
+ public void EmptyBad()
+ {
+ tree.AddSorted(new FunEnumerable(9, new Fun<int,int>(bad)));
+ }
+
+
+ [TearDown]
+ public void Dispose() { tree = null; }
+ }
+
+ [TestFixture]
+ public class Rest
+ {
+ TreeSet<int> tree, tree2;
+
+
+ [SetUp]
+ public void Init()
+ {
+ tree = new TreeSet<int>(new IC());
+ tree2 = new TreeSet<int>(new IC());
+ for (int i = 0; i < 10; i++)
+ tree.Add(i);
+
+ for (int i = 0; i < 10; i++)
+ tree2.Add(2 * i);
+ }
+
+
+ [Test]
+ public void RemoveAll()
+ {
+ tree.RemoveAll(tree2.RangeFromTo(3, 7));
+ Assert.AreEqual(8, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.IsTrue(IC.eq(tree, 0, 1, 2, 3, 5, 7, 8, 9));
+ tree.RemoveAll(tree2.RangeFromTo(3, 7));
+ Assert.AreEqual(8, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.IsTrue(IC.eq(tree, 0, 1, 2, 3, 5, 7, 8, 9));
+ tree.RemoveAll(tree2.RangeFromTo(13, 17));
+ Assert.AreEqual(8, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.IsTrue(IC.eq(tree, 0, 1, 2, 3, 5, 7, 8, 9));
+ tree.RemoveAll(tree2.RangeFromTo(3, 17));
+ Assert.AreEqual(7, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.IsTrue(IC.eq(tree, 0, 1, 2, 3, 5, 7, 9));
+ for (int i = 0; i < 10; i++) tree2.Add(i);
+
+ tree.RemoveAll(tree2.RangeFromTo(-1, 10));
+ Assert.AreEqual(0, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.IsTrue(IC.eq(tree));
+ }
+
+
+ [Test]
+ public void RetainAll()
+ {
+ tree.RetainAll(tree2.RangeFromTo(3, 17));
+ Assert.AreEqual(3, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.IsTrue(IC.eq(tree, 4, 6, 8));
+ tree.RetainAll(tree2.RangeFromTo(1, 17));
+ Assert.AreEqual(3, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.IsTrue(IC.eq(tree, 4, 6, 8));
+ tree.RetainAll(tree2.RangeFromTo(3, 5));
+ Assert.AreEqual(1, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.IsTrue(IC.eq(tree, 4));
+ tree.RetainAll(tree2.RangeFromTo(7, 17));
+ Assert.AreEqual(0, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.IsTrue(IC.eq(tree));
+ for (int i = 0; i < 10; i++) tree.Add(i);
+
+ tree.RetainAll(tree2.RangeFromTo(5, 5));
+ Assert.AreEqual(0, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.IsTrue(IC.eq(tree));
+ for (int i = 0; i < 10; i++) tree.Add(i);
+
+ tree.RetainAll(tree2.RangeFromTo(15, 25));
+ Assert.AreEqual(0, tree.Count);
+ Assert.IsTrue(tree.Check());
+ Assert.IsTrue(IC.eq(tree));
+ }
+
+
+ [Test]
+ public void ContainsAll()
+ {
+ Assert.IsFalse(tree.ContainsAll(tree2));
+ Assert.IsTrue(tree.ContainsAll(tree));
+ tree2.Clear();
+ Assert.IsTrue(tree.ContainsAll(tree2));
+ tree.Clear();
+ Assert.IsTrue(tree.ContainsAll(tree2));
+ tree2.Add(8);
+ Assert.IsFalse(tree.ContainsAll(tree2));
+ }
+
+
+ [Test]
+ public void RemoveInterval()
+ {
+ tree.RemoveInterval(3, 4);
+ Assert.IsTrue(tree.Check());
+ Assert.AreEqual(6, tree.Count);
+ Assert.IsTrue(IC.eq(tree, 0, 1, 2, 7, 8, 9));
+ tree.RemoveInterval(2, 3);
+ Assert.IsTrue(tree.Check());
+ Assert.AreEqual(3, tree.Count);
+ Assert.IsTrue(IC.eq(tree, 0, 1, 9));
+ tree.RemoveInterval(0, 3);
+ Assert.IsTrue(tree.Check());
+ Assert.AreEqual(0, tree.Count);
+ Assert.IsTrue(IC.eq(tree));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void RemoveRangeBad1()
+ {
+ tree.RemoveInterval(-3, 8);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void RemoveRangeBad2()
+ {
+ tree.RemoveInterval(3, -8);
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void RemoveRangeBad3()
+ {
+ tree.RemoveInterval(3, 8);
+ }
+
+
+ [Test]
+ public void GetRange()
+ {
+ SCG.IEnumerable<int> e = tree[3, 6];
+
+ Assert.IsTrue(IC.eq(e, 3, 4, 5));
+ e = tree[3, 3];
+ Assert.IsTrue(IC.eq(e));
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void GetRangeBad1()
+ {
+ object foo = tree[-3, 0];
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void GetRangeBad2()
+ {
+ object foo = tree[3, 2];
+ }
+
+
+ [Test]
+ [ExpectedException(typeof(ArgumentOutOfRangeException))]
+ public void GetRangeBad3()
+ {
+ object foo = tree[3, 11];
+ }
+
+
+ [TearDown]
+ public void Dispose() { tree = null; tree2 = null; }
+ }
+ }
+
+
+
+
+ namespace Sync
+ {
+ [TestFixture]
+ public class SyncRoot
+ {
+ private TreeSet<int> tree;
+
+ int sz = 5000;
+
+
+ [Test]
+ public void Safe()
+ {
+ System.Threading.Thread t1 = new System.Threading.Thread(new System.Threading.ThreadStart(safe1));
+ System.Threading.Thread t2 = new System.Threading.Thread(new System.Threading.ThreadStart(safe2));
+
+ t1.Start();
+ t2.Start();
+ t1.Join();
+ t2.Join();
+ Assert.AreEqual(2 * sz + 1, tree.Count);
+ Assert.IsTrue(tree.Check());
+ }
+
+
+ //[Test]
+ public void UnSafe()
+ {
+ bool bad = false;
+
+ for (int i = 0; i < 10; i++)
+ {
+ System.Threading.Thread t1 = new System.Threading.Thread(new System.Threading.ThreadStart(unsafe1));
+ System.Threading.Thread t2 = new System.Threading.Thread(new System.Threading.ThreadStart(unsafe2));
+
+ t1.Start();
+ t2.Start();
+ t1.Join();
+ t2.Join();
+ if (bad = 2 * sz + 1 != tree.Count)
+ {
+ Console.WriteLine("{0}::Unsafe(): bad at {1}", GetType(), i);
+ break;
+ }
+ }
+
+ Assert.IsTrue(bad, "No sync problems!");
+ }
+
+
+ [Test]
+ public void SafeUnSafe()
+ {
+ System.Threading.Thread t1 = new System.Threading.Thread(new System.Threading.ThreadStart(unsafe1));
+ System.Threading.Thread t2 = new System.Threading.Thread(new System.Threading.ThreadStart(unsafe2));
+
+ t1.Start();
+ t1.Join();
+ t2.Start();
+ t2.Join();
+ Assert.AreEqual(2 * sz + 1, tree.Count);
+ }
+
+
+ [SetUp]
+ public void Init() { tree = new TreeSet<int>(new IC()); }
+
+
+ private void unsafe1()
+ {
+ for (int i = 0; i < 2 * sz; i++)
+ tree.Add(i * 2);
+
+ for (int i = 1; i < sz; i++)
+ tree.Remove(i * 4);
+ }
+
+
+ private void safe1()
+ {
+ for (int i = 0; i < 2 * sz; i++)
+ lock (tree.SyncRoot)
+ tree.Add(i * 2);
+
+ for (int i = 1; i < sz; i++)
+ lock (tree.SyncRoot)
+ tree.Remove(i * 4);
+ }
+
+
+ private void unsafe2()
+ {
+ for (int i = 2 * sz; i > 0; i--)
+ tree.Add(i * 2 + 1);
+
+ for (int i = sz; i > 0; i--)
+ tree.Remove(i * 4 + 1);
+ }
+
+
+ private void safe2()
+ {
+ for (int i = 2 * sz; i > 0; i--)
+ lock (tree.SyncRoot)
+ tree.Add(i * 2 + 1);
+
+ for (int i = sz; i > 0; i--)
+ lock (tree.SyncRoot)
+ tree.Remove(i * 4 + 1);
+ }
+
+
+ [TearDown]
+ public void Dispose() { tree = null; }
+ }
+
+
+
+ //[TestFixture]
+ public class ConcurrentQueries
+ {
+ private TreeSet<int> tree;
+
+ int sz = 500000;
+
+
+ [SetUp]
+ public void Init()
+ {
+ tree = new TreeSet<int>(new IC());
+ for (int i = 0; i < sz; i++)
+ {
+ tree.Add(i);
+ }
+ }
+
+
+
+ class A
+ {
+ public int count = 0;
+
+ TreeSet<int> t;
+
+
+ public A(TreeSet<int> t) { this.t = t; }
+
+
+ public void a(int i) { count++; }
+
+
+ public void traverse() { t.Apply(new Act<int>(a)); }
+ }
+
+
+
+
+ [Test]
+ public void Safe()
+ {
+ A a = new A(tree);
+
+ a.traverse();
+ Assert.AreEqual(sz, a.count);
+ }
+
+
+ [Test]
+ public void RegrettablyUnsafe()
+ {
+ System.Threading.Thread[] t = new System.Threading.Thread[10];
+ A[] a = new A[10];
+ for (int i = 0; i < 10; i++)
+ {
+ a[i] = new A(tree);
+ t[i] = new System.Threading.Thread(new System.Threading.ThreadStart(a[i].traverse));
+ }
+
+ for (int i = 0; i < 10; i++)
+ t[i].Start();
+ for (int i = 0; i < 10; i++)
+ t[i].Join();
+ for (int i = 0; i < 10; i++)
+ Assert.AreEqual(sz,a[i].count);
+
+ }
+
+
+ [TearDown]
+ public void Dispose() { tree = null; }
+ }
+ }
+
+
+
+
+ namespace Hashing
+ {
+ [TestFixture]
+ public class ISequenced
+ {
+ private ISequenced<int> dit, dat, dut;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new TreeSet<int>(Comparer<int>.Default, EqualityComparer<int>.Default);
+ dat = new TreeSet<int>(Comparer<int>.Default, EqualityComparer<int>.Default);
+ dut = new TreeSet<int>(new RevIC(), EqualityComparer<int>.Default);
+ }
+
+
+ [Test]
+ public void EmptyEmpty()
+ {
+ Assert.IsTrue(dit.SequencedEquals(dat));
+ }
+
+
+ [Test]
+ public void EmptyNonEmpty()
+ {
+ dit.Add(3);
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ Assert.IsFalse(dat.SequencedEquals(dit));
+ }
+
+ [Test]
+ public void HashVal()
+ {
+ Assert.AreEqual(CHC.sequencedhashcode(), dit.GetSequencedHashCode());
+ dit.Add(3);
+ Assert.AreEqual(CHC.sequencedhashcode(3), dit.GetSequencedHashCode());
+ dit.Add(7);
+ Assert.AreEqual(CHC.sequencedhashcode(3, 7), dit.GetSequencedHashCode());
+ Assert.AreEqual(CHC.sequencedhashcode(), dut.GetSequencedHashCode());
+ dut.Add(3);
+ Assert.AreEqual(CHC.sequencedhashcode(3), dut.GetSequencedHashCode());
+ dut.Add(7);
+ Assert.AreEqual(CHC.sequencedhashcode(7, 3), dut.GetSequencedHashCode());
+ }
+
+
+ [Test]
+ public void Normal()
+ {
+ dit.Add(3);
+ dit.Add(7);
+ dat.Add(3);
+ Assert.IsFalse(dit.SequencedEquals(dat));
+ Assert.IsFalse(dat.SequencedEquals(dit));
+ dat.Add(7);
+ Assert.IsTrue(dit.SequencedEquals(dat));
+ Assert.IsTrue(dat.SequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void WrongOrder()
+ {
+ dit.Add(3);
+ dut.Add(3);
+ Assert.IsTrue(dit.SequencedEquals(dut));
+ Assert.IsTrue(dut.SequencedEquals(dit));
+ dit.Add(7);
+ dut.Add(7);
+ Assert.IsFalse(dit.SequencedEquals(dut));
+ Assert.IsFalse(dut.SequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void Reflexive()
+ {
+ Assert.IsTrue(dit.SequencedEquals(dit));
+ dit.Add(3);
+ Assert.IsTrue(dit.SequencedEquals(dit));
+ dit.Add(7);
+ Assert.IsTrue(dit.SequencedEquals(dit));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = null;
+ dat = null;
+ dut = null;
+ }
+ }
+
+
+
+ [TestFixture]
+ public class IEditableCollection
+ {
+ private ICollection<int> dit, dat, dut;
+
+
+ [SetUp]
+ public void Init()
+ {
+ dit = new TreeSet<int>(Comparer<int>.Default, EqualityComparer<int>.Default);
+ dat = new TreeSet<int>(Comparer<int>.Default, EqualityComparer<int>.Default);
+ dut = new TreeSet<int>(new RevIC(), EqualityComparer<int>.Default);
+ }
+
+
+ [Test]
+ public void EmptyEmpty()
+ {
+ Assert.IsTrue(dit.UnsequencedEquals(dat));
+ }
+
+
+ [Test]
+ public void EmptyNonEmpty()
+ {
+ dit.Add(3);
+ Assert.IsFalse(dit.UnsequencedEquals(dat));
+ Assert.IsFalse(dat.UnsequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void HashVal()
+ {
+ Assert.AreEqual(CHC.unsequencedhashcode(), dit.GetUnsequencedHashCode());
+ dit.Add(3);
+ Assert.AreEqual(CHC.unsequencedhashcode(3), dit.GetUnsequencedHashCode());
+ dit.Add(7);
+ Assert.AreEqual(CHC.unsequencedhashcode(3, 7), dit.GetUnsequencedHashCode());
+ Assert.AreEqual(CHC.unsequencedhashcode(), dut.GetUnsequencedHashCode());
+ dut.Add(3);
+ Assert.AreEqual(CHC.unsequencedhashcode(3), dut.GetUnsequencedHashCode());
+ dut.Add(7);
+ Assert.AreEqual(CHC.unsequencedhashcode(7, 3), dut.GetUnsequencedHashCode());
+ }
+
+
+ [Test]
+ public void Normal()
+ {
+ dit.Add(3);
+ dit.Add(7);
+ dat.Add(3);
+ Assert.IsFalse(dit.UnsequencedEquals(dat));
+ Assert.IsFalse(dat.UnsequencedEquals(dit));
+ dat.Add(7);
+ Assert.IsTrue(dit.UnsequencedEquals(dat));
+ Assert.IsTrue(dat.UnsequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void WrongOrder()
+ {
+ dit.Add(3);
+ dut.Add(3);
+ Assert.IsTrue(dit.UnsequencedEquals(dut));
+ Assert.IsTrue(dut.UnsequencedEquals(dit));
+ dit.Add(7);
+ dut.Add(7);
+ Assert.IsTrue(dit.UnsequencedEquals(dut));
+ Assert.IsTrue(dut.UnsequencedEquals(dit));
+ }
+
+
+ [Test]
+ public void Reflexive()
+ {
+ Assert.IsTrue(dit.UnsequencedEquals(dit));
+ dit.Add(3);
+ Assert.IsTrue(dit.UnsequencedEquals(dit));
+ dit.Add(7);
+ Assert.IsTrue(dit.UnsequencedEquals(dit));
+ }
+
+
+ [TearDown]
+ public void Dispose()
+ {
+ dit = null;
+ dat = null;
+ dut = null;
+ }
+ }
+
+ }
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/AnagramHashBag.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/AnagramHashBag.cs
new file mode 100644
index 00000000000..cc1ca504d10
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/AnagramHashBag.cs
@@ -0,0 +1,158 @@
+/*
+ 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.
+*/
+
+// C5 example: anagrams 2004-08-08, 2004-11-16
+
+// Compile with
+// csc /r:C5.dll AnagramHashBag.cs
+
+using System;
+using System.IO; // StreamReader, TextReader
+using System.Text; // Encoding
+using System.Text.RegularExpressions; // Regex
+using C5;
+using SCG = System.Collections.Generic;
+
+namespace AnagramHashBag
+{
+ class MyTest
+ {
+ public static void Main(String[] args)
+ {
+ Console.OutputEncoding = Encoding.GetEncoding("iso-8859-1");
+ SCG.IEnumerable<String> ss;
+ if (args.Length == 2)
+ ss = ReadFileWords(args[0], int.Parse(args[1]));
+ else
+ ss = args;
+ // foreach (String s in FirstAnagramOnly(ss))
+ // Console.WriteLine(s);
+ // Console.WriteLine("===");
+ Timer t = new Timer();
+ SCG.IEnumerable<SCG.IEnumerable<String>> classes = AnagramClasses(ss);
+ int count = 0;
+ foreach (SCG.IEnumerable<String> anagramClass in classes)
+ {
+ count++;
+ foreach (String s in anagramClass)
+ Console.Write(s + " ");
+ Console.WriteLine();
+ }
+ Console.WriteLine("{0} non-trivial anagram classes", count);
+ Console.WriteLine(t.Check());
+ }
+
+ // Read words at most n words from a file
+
+ public static SCG.IEnumerable<String> ReadFileWords(String filename, int n)
+ {
+ Regex delim = new Regex("[^a-zæøåA-ZÆØÅ0-9-]+");
+ Encoding enc = Encoding.GetEncoding("iso-8859-1");
+ using (TextReader rd = new StreamReader(filename, enc))
+ {
+ for (String line = rd.ReadLine(); line != null; line = rd.ReadLine()) {
+ foreach (String s in delim.Split(line))
+ if (s != "")
+ yield return s.ToLower();
+ if (--n == 0)
+ yield break;
+ }
+ }
+ }
+
+ // From an anagram point of view, a word is just a bag of
+ // characters. So an anagram class is represented as HashBag<char>
+ // which permits fast equality comparison -- we shall use them as
+ // elements of hash sets or keys in hash maps.
+
+ public static HashBag<char> AnagramClass(String s) {
+ HashBag<char> anagram = new HashBag<char>();
+ foreach (char c in s)
+ anagram.Add(c);
+ return anagram;
+ }
+
+ // Given a sequence of strings, return only the first member of each
+ // anagram class.
+
+ public static SCG.IEnumerable<String> FirstAnagramOnly(SCG.IEnumerable<String> ss)
+ {
+ HashSet<HashBag<char>> anagrams = new HashSet<HashBag<char>>();
+ foreach (String s in ss) {
+ HashBag<char> anagram = AnagramClass(s);
+ if (!anagrams.Contains(anagram)) {
+ anagrams.Add(anagram);
+ yield return s;
+ }
+ }
+ }
+
+ // Given a sequence of strings, return all non-trivial anagram
+ // classes.
+
+ // Using HashBag<char> and an unsequenced equalityComparer, this performs as
+ // follows on 1600 MHz Mobile P4 and .Net 2.0 beta 1 (wall-clock
+ // time):
+ // 50 000 words 2 822 classes 2.0 sec
+ // 100 000 words 5 593 classes 4.3 sec
+ // 200 000 words 11 705 classes 8.8 sec
+ // 300 000 words 20 396 classes 52.0 sec includes swapping
+ // 347 165 words 24 428 classes 146.0 sec includes swapping
+
+ // The maximal memory consumption is less than 180 MB.
+
+ public static SCG.IEnumerable<SCG.IEnumerable<String>>
+ AnagramClasses(SCG.IEnumerable<String> ss)
+ {
+ IDictionary<HashBag<char>, TreeSet<String>> classes
+ = new HashDictionary<HashBag<char>, TreeSet<String>>();
+ foreach (String s in ss) {
+ HashBag<char> anagram = AnagramClass(s);
+ TreeSet<String> anagramClass;
+ if (!classes.Find(anagram, out anagramClass))
+ classes[anagram] = anagramClass = new TreeSet<String>();
+ anagramClass.Add(s);
+ }
+ foreach (TreeSet<String> anagramClass in classes.Values)
+ if (anagramClass.Count > 1)
+ yield return anagramClass;
+ }
+ }
+
+// Crude timing utility ----------------------------------------
+
+ public class Timer
+ {
+ private DateTime start;
+
+ public Timer()
+ {
+ start = DateTime.Now;
+ }
+
+ public double Check()
+ {
+ TimeSpan dur = DateTime.Now - start;
+ return dur.TotalSeconds;
+ }
+ }
+
+}
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/AnagramStrings.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/AnagramStrings.cs
new file mode 100644
index 00000000000..314e7a41111
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/AnagramStrings.cs
@@ -0,0 +1,159 @@
+/*
+ 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.
+*/
+
+// C5 example: anagrams represented as sorted strings 2004-08-26
+
+// To represent an anagram class, use a string containing the sorted
+// characters of a word.
+
+// This is faster than a TreeBag<char> because the words and hence
+// bags are small. Takes 15 CPU seconds and 138 MB RAM to find the
+// 26,058 anagram classes among 347,000 distinct words.
+
+// Compile with
+// csc /r:C5.dll Anagrams.cs
+
+using System;
+using System.IO; // StreamReader, TextReader
+using System.Text; // Encoding
+using System.Text.RegularExpressions; // Regex
+using C5;
+using SCG = System.Collections.Generic;
+
+namespace AnagramStrings
+{
+ class MyTest
+ {
+ public static void Main(String[] args)
+ {
+ Console.OutputEncoding = Encoding.GetEncoding("iso-8859-1");
+ SCG.IEnumerable<String> ss;
+ if (args.Length == 1)
+ ss = ReadFileWords(args[0]);
+ else
+ ss = args;
+
+ Timer t = new Timer();
+ SCG.IEnumerable<SCG.IEnumerable<String>> classes = AnagramClasses(ss);
+ int count = 0;
+ foreach (SCG.IEnumerable<String> anagramClass in classes)
+ {
+ count++;
+ // foreach (String s in anagramClass)
+ // Console.Write(s + " ");
+ // Console.WriteLine();
+ }
+ Console.WriteLine("{0} anagram classes", count);
+ Console.WriteLine(t.Check());
+ }
+
+ // Read words from a file
+
+ public static SCG.IEnumerable<String> ReadFileWords(String filename)
+ {
+ Regex delim = new Regex("[^a-zæøåA-ZÆØÅ0-9-]+");
+ using (TextReader rd = new StreamReader(filename, Encoding.GetEncoding("iso-8859-1")))
+ {
+ for (String line = rd.ReadLine(); line != null; line = rd.ReadLine())
+ foreach (String s in delim.Split(line))
+ if (s != "")
+ yield return s.ToLower();
+ }
+ }
+
+ // From an anagram point of view, a word is just a bag of characters.
+
+ public static CharBag AnagramClass(String s)
+ {
+ return new CharBag(s);
+ }
+
+ // Given a sequence of strings, return all non-trivial anagram classes
+
+ public static SCG.IEnumerable<SCG.IEnumerable<String>> AnagramClasses(SCG.IEnumerable<String> ss)
+ {
+ IDictionary<CharBag, HashSet<String>> classes
+ = new TreeDictionary<CharBag, HashSet<String>>();
+ foreach (String s in ss)
+ {
+ CharBag anagram = AnagramClass(s);
+ HashSet<String> anagramClass;
+ if (!classes.Find(anagram, out anagramClass))
+ classes[anagram] = anagramClass = new HashSet<String>();
+ anagramClass.Add(s);
+ }
+ foreach (HashSet<String> anagramClass in classes.Values)
+ if (anagramClass.Count > 1
+ ) // && anagramClass.Exists(delegate(String s) { return !s.EndsWith("s"); }))
+ yield return anagramClass;
+ }
+ }
+
+// A bag of characters is represented as a sorted string of the
+// characters, with multiplicity. Since natural language words are
+// short, the bags are small, so this is vastly better than
+// representing character bags using HashBag<char> or TreeBag<char>
+
+ class CharBag : IComparable<CharBag>
+ {
+ private readonly String contents; // The bag's characters, sorted, with multiplicity
+
+ public CharBag(String s)
+ {
+ char[] chars = s.ToCharArray();
+ Array.Sort(chars);
+ this.contents = new String(chars);
+ }
+
+ public override int GetHashCode()
+ {
+ return contents.GetHashCode();
+ }
+
+ public bool Equals(CharBag that)
+ {
+ return this.contents.Equals(that.contents);
+ }
+
+ public int CompareTo(CharBag that)
+ {
+ return this.contents.CompareTo(that.contents);
+ }
+ }
+
+// Crude timing utility ----------------------------------------
+
+ public class Timer
+ {
+ private DateTime start;
+
+ public Timer()
+ {
+ start = DateTime.Now;
+ }
+
+ public double Check()
+ {
+ TimeSpan dur = DateTime.Now - start;
+ return dur.TotalSeconds;
+ }
+ }
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/AnagramTreeBag.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/AnagramTreeBag.cs
new file mode 100644
index 00000000000..e8120758ca8
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/AnagramTreeBag.cs
@@ -0,0 +1,163 @@
+/*
+ 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.
+*/
+
+// C5 example: anagrams 2004-08-08, 2004-11-16
+
+// Compile with
+// csc /r:C5.dll AnagramTreeBag.cs
+
+using System;
+using System.IO; // StreamReader, TextReader
+using System.Text; // Encoding
+using System.Text.RegularExpressions; // Regex
+using C5;
+using SCG = System.Collections.Generic;
+
+namespace AnagramTreeBag
+{
+ class MyTest
+ {
+ public static void Main(String[] args)
+ {
+ Console.OutputEncoding = Encoding.GetEncoding("iso-8859-1");
+ SCG.IEnumerable<String> ss;
+ if (args.Length == 2)
+ ss = ReadFileWords(args[0], int.Parse(args[1]));
+ else
+ ss = args;
+ // foreach (String s in FirstAnagramOnly(ss))
+ // Console.WriteLine(s);
+ // Console.WriteLine("===");
+ Timer t = new Timer();
+ SCG.IEnumerable<SCG.IEnumerable<String>> classes = AnagramClasses(ss);
+ int count = 0;
+ foreach (SCG.IEnumerable<String> anagramClass in classes)
+ {
+ count++;
+ // foreach (String s in anagramClass)
+ // Console.Write(s + " ");
+ // Console.WriteLine();
+ }
+ Console.WriteLine("{0} non-trivial anagram classes", count);
+ Console.WriteLine(t.Check());
+ }
+
+ // Read words at most n words from a file
+
+ public static SCG.IEnumerable<String> ReadFileWords(String filename, int n)
+ {
+ Regex delim = new Regex("[^a-zæøåA-ZÆØÅ0-9-]+");
+ Encoding enc = Encoding.GetEncoding("iso-8859-1");
+ using (TextReader rd = new StreamReader(filename, enc))
+ {
+ for (String line = rd.ReadLine(); line != null; line = rd.ReadLine())
+ {
+ foreach (String s in delim.Split(line))
+ if (s != "")
+ yield return s.ToLower();
+ if (--n == 0)
+ yield break;
+ }
+ }
+ }
+
+ // From an anagram point of view, a word is just a bag of
+ // characters. So an anagram class is represented as TreeBag<char>
+ // which permits fast equality comparison -- we shall use them as
+ // elements of hash sets or keys in hash maps.
+
+ public static TreeBag<char> AnagramClass(String s)
+ {
+ TreeBag<char> anagram = new TreeBag<char>(Comparer<char>.Default, EqualityComparer<char>.Default);
+ foreach (char c in s)
+ anagram.Add(c);
+ return anagram;
+ }
+
+ // Given a sequence of strings, return only the first member of each
+ // anagram class.
+
+ public static SCG.IEnumerable<String> FirstAnagramOnly(SCG.IEnumerable<String> ss)
+ {
+ HashSet<TreeBag<char>> anagrams = new HashSet<TreeBag<char>>();
+ foreach (String s in ss)
+ {
+ TreeBag<char> anagram = AnagramClass(s);
+ if (!anagrams.Contains(anagram))
+ {
+ anagrams.Add(anagram);
+ yield return s;
+ }
+ }
+ }
+
+ // Given a sequence of strings, return all non-trivial anagram
+ // classes.
+
+ // Using TreeBag<char> and an unsequenced equalityComparer, this performs as
+ // follows on 1600 MHz Mobile P4 and .Net 2.0 beta 1 (wall-clock
+ // time; number of distinct words):
+
+ // 50 000 words 2 822 classes 2.4 sec
+ // 100 000 words 5 593 classes 4.6 sec
+ // 200 000 words 11 705 classes 9.6 sec
+ // 300 000 words 20 396 classes 88.2 sec (includes swapping)
+ // 347 165 words 24 428 classes 121.3 sec (includes swapping)
+
+ // The maximal memory consumption is around 180 MB.
+
+ public static SCG.IEnumerable<SCG.IEnumerable<String>>
+ AnagramClasses(SCG.IEnumerable<String> ss)
+ {
+ IDictionary<TreeBag<char>, TreeSet<String>> classes;
+ classes = new HashDictionary<TreeBag<char>, TreeSet<String>>();
+ foreach (String s in ss)
+ {
+ TreeBag<char> anagram = AnagramClass(s);
+ TreeSet<String> anagramClass;
+ if (!classes.Find(anagram, out anagramClass))
+ classes[anagram] = anagramClass = new TreeSet<String>();
+ anagramClass.Add(s);
+ }
+ foreach (TreeSet<String> anagramClass in classes.Values)
+ if (anagramClass.Count > 1)
+ yield return anagramClass;
+ }
+ }
+
+// Crude timing utility ----------------------------------------
+
+ public class Timer
+ {
+ private DateTime start;
+
+ public Timer()
+ {
+ start = DateTime.Now;
+ }
+
+ public double Check()
+ {
+ TimeSpan dur = DateTime.Now - start;
+ return dur.TotalSeconds;
+ }
+ }
+}
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/Anagrams.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/Anagrams.cs
new file mode 100644
index 00000000000..64ca20f515f
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/Anagrams.cs
@@ -0,0 +1,177 @@
+/*
+ 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.
+*/
+
+// C5 example: anagrams 2004-08-08, 2004-11-16
+
+// Compile with
+// csc /r:C5.dll Anagrams.cs
+
+using System;
+using System.IO; // StreamReader, TextReader
+using System.Text; // Encoding
+using System.Text.RegularExpressions; // Regex
+using C5;
+using SCG = System.Collections.Generic;
+
+namespace Anagrams
+{
+ class MyTest
+ {
+ public static void Main(String[] args)
+ {
+ Console.OutputEncoding = Encoding.GetEncoding("iso-8859-1");
+ SCG.IEnumerable<String> ss;
+ if (args.Length == 2)
+ ss = ReadFileWords(args[0], int.Parse(args[1]));
+ else
+ ss = args;
+ // foreach (String s in FirstAnagramOnly(ss))
+ // Console.WriteLine(s);
+ // Console.WriteLine("===");
+ Timer t = new Timer();
+ SCG.IEnumerable<SCG.IEnumerable<String>> classes = AnagramClasses(ss);
+ int count = 0;
+ foreach (SCG.IEnumerable<String> anagramClass in classes)
+ {
+ count++;
+ // foreach (String s in anagramClass)
+ // Console.Write(s + " ");
+ // Console.WriteLine();
+ }
+ Console.WriteLine("{0} non-trivial anagram classes", count);
+ Console.WriteLine(t.Check());
+ }
+
+ // Read words at most n words from a file
+
+ public static SCG.IEnumerable<String> ReadFileWords(String filename, int n)
+ {
+ Regex delim = new Regex("[^a-zæøåA-ZÆØÅ0-9-]+");
+ Encoding enc = Encoding.GetEncoding("iso-8859-1");
+ using (TextReader rd = new StreamReader(filename, enc))
+ {
+ for (String line = rd.ReadLine(); line != null; line = rd.ReadLine())
+ {
+ foreach (String s in delim.Split(line))
+ if (s != "")
+ yield return s.ToLower();
+ if (--n == 0)
+ yield break;
+ }
+ }
+ }
+
+ // From an anagram point of view, a word is just a bag of
+ // characters. So an anagram class is represented as TreeBag<char>
+ // which permits fast equality comparison -- we shall use them as
+ // elements of hash sets or keys in hash maps.
+
+ public static TreeBag<char> AnagramClass(String s)
+ {
+ TreeBag<char> anagram = new TreeBag<char>(Comparer<char>.Default, EqualityComparer<char>.Default);
+ foreach (char c in s)
+ anagram.Add(c);
+ return anagram;
+ }
+
+ // Given a sequence of strings, return only the first member of each
+ // anagram class.
+
+ public static SCG.IEnumerable<String> FirstAnagramOnly(SCG.IEnumerable<String> ss)
+ {
+ SCG.IEqualityComparer<TreeBag<char>> tbh
+ = UnsequencedCollectionEqualityComparer<TreeBag<char>, char>.Default;
+ HashSet<TreeBag<char>> anagrams = new HashSet<TreeBag<char>>(tbh);
+ foreach (String s in ss)
+ {
+ TreeBag<char> anagram = AnagramClass(s);
+ if (!anagrams.Contains(anagram))
+ {
+ anagrams.Add(anagram);
+ yield return s;
+ }
+ }
+ }
+
+ // Given a sequence of strings, return all non-trivial anagram
+ // classes. Should use a *sequenced* equalityComparer on a TreeBag<char>,
+ // obviously: after all, characters can be sorted by ASCII code. On
+ // 347 000 distinct Danish words this takes 70 cpu seconds, 180 MB
+ // memory, and 263 wall-clock seconds (due to swapping).
+
+ // Using a TreeBag<char> and a sequenced equalityComparer takes 82 cpu seconds
+ // and 180 MB RAM to find the 26,058 anagram classes among 347,000
+ // distinct words.
+
+ // Using an unsequenced equalityComparer on TreeBag<char> or HashBag<char>
+ // makes it criminally slow: at least 1200 cpu seconds. This must
+ // be because many bags get the same hash code, so that there are
+ // many collisions. But exactly how the unsequenced equalityComparer works is
+ // not clear ... or is it because unsequenced equality is slow?
+
+ public static SCG.IEnumerable<SCG.IEnumerable<String>> AnagramClasses(SCG.IEnumerable<String> ss)
+ {
+ bool unseq = true;
+ IDictionary<TreeBag<char>, TreeSet<String>> classes;
+ if (unseq)
+ {
+ SCG.IEqualityComparer<TreeBag<char>> unsequencedTreeBagEqualityComparer
+ = UnsequencedCollectionEqualityComparer<TreeBag<char>, char>.Default;
+ classes = new HashDictionary<TreeBag<char>, TreeSet<String>>(unsequencedTreeBagEqualityComparer);
+ }
+ else
+ {
+ SCG.IEqualityComparer<TreeBag<char>> sequencedTreeBagEqualityComparer
+ = SequencedCollectionEqualityComparer<TreeBag<char>, char>.Default;
+ classes = new HashDictionary<TreeBag<char>, TreeSet<String>>(sequencedTreeBagEqualityComparer);
+ }
+ foreach (String s in ss)
+ {
+ TreeBag<char> anagram = AnagramClass(s);
+ TreeSet<String> anagramClass;
+ if (!classes.Find(anagram, out anagramClass))
+ classes[anagram] = anagramClass = new TreeSet<String>();
+ anagramClass.Add(s);
+ }
+ foreach (TreeSet<String> anagramClass in classes.Values)
+ if (anagramClass.Count > 1)
+ yield return anagramClass;
+ }
+ }
+
+// Crude timing utility ----------------------------------------
+
+ public class Timer
+ {
+ private DateTime start;
+
+ public Timer()
+ {
+ start = DateTime.Now;
+ }
+
+ public double Check()
+ {
+ TimeSpan dur = DateTime.Now - start;
+ return dur.TotalSeconds;
+ }
+ }
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/Antipatterns.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/Antipatterns.cs
new file mode 100644
index 00000000000..94d373434b8
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/Antipatterns.cs
@@ -0,0 +1,103 @@
+/*
+ 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.
+*/
+
+// C5 example: Antipatterns 2004-12-29
+
+// Compile with
+// csc /r:C5.dll Antipatterns.cs
+
+using System;
+using C5;
+using SCG = System.Collections.Generic;
+
+namespace Antipatterns {
+ class Antipatterns {
+ public static void Main(String[] args) {
+ ModifyInner();
+ DontModifyInner();
+ }
+
+ // Anti-pattern: modifying an inner collection while it is a
+ // member of an outer one may cause it to be lost from the outer
+ // collection.
+
+ private static void ModifyInner() {
+ Console.WriteLine("\nAnti-pattern: Add to outer, modify, lose");
+ ICollection<ISequenced<int>> outer = new HashSet<ISequenced<int>>();
+ for (int i=0; i<100; i++) {
+ ISequenced<int> inner = new TreeSet<int>();
+ inner.Add(i); inner.Add(i+1);
+ outer.Add(inner);
+ }
+ ISequenced<int>
+ inner1 = new TreeSet<int>(),
+ inner2 = new TreeSet<int>(),
+ inner3 = new TreeSet<int>();
+ inner1.AddAll<int>(new int[] { 2, 3, 5, 7, 11 });
+ inner2.AddAll(inner1); inner2.Add(13);
+ inner3.AddAll(inner1);
+ outer.Add(inner1);
+ Console.WriteLine("inner1 in outer: {0}", outer.Contains(inner1));
+ Console.WriteLine("inner2 in outer: {0}", outer.Contains(inner2));
+ Console.WriteLine("inner3 in outer: {0}", outer.Contains(inner3));
+ inner1.Add(13);
+ Console.WriteLine("inner1 equals inner2: {0}",
+ outer.EqualityComparer.Equals(inner1, inner2));
+ Console.WriteLine("inner1 equals inner3: {0}",
+ outer.EqualityComparer.Equals(inner1, inner3));
+ Console.WriteLine("inner1 in outer: {0}", outer.Contains(inner1));
+ Console.WriteLine("inner2 in outer: {0}", outer.Contains(inner2));
+ Console.WriteLine("inner3 in outer: {0}", outer.Contains(inner3));
+ Console.WriteLine("outer.Count: {0}", outer.Count);
+ }
+
+ private static void DontModifyInner() {
+ Console.WriteLine("\nMake a snapshot and add it to outer");
+ ICollection<ISequenced<int>> outer = new HashSet<ISequenced<int>>();
+ for (int i=0; i<100; i++) {
+ ISequenced<int> inner = new TreeSet<int>();
+ inner.Add(i); inner.Add(i+1);
+ outer.Add(inner);
+ }
+ IPersistentSorted<int>
+ inner1 = new TreeSet<int>(),
+ inner2 = new TreeSet<int>(),
+ inner3 = new TreeSet<int>();
+ inner1.AddAll<int>(new int[] { 2, 3, 5, 7, 11 });
+ inner2.AddAll(inner1); inner2.Add(13);
+ inner3.AddAll(inner1);
+ // Take a snapshot and add it to outer:
+ outer.Add(inner1.Snapshot());
+ Console.WriteLine("inner1 in outer: {0}", outer.Contains(inner1));
+ Console.WriteLine("inner2 in outer: {0}", outer.Contains(inner2));
+ Console.WriteLine("inner3 in outer: {0}", outer.Contains(inner3));
+ inner1.Add(13);
+ Console.WriteLine("inner1 equals inner2: {0}",
+ outer.EqualityComparer.Equals(inner1, inner2));
+ Console.WriteLine("inner1 equals inner3: {0}",
+ outer.EqualityComparer.Equals(inner1, inner3));
+ Console.WriteLine("inner1 in outer: {0}", outer.Contains(inner1));
+ Console.WriteLine("inner2 in outer: {0}", outer.Contains(inner2));
+ Console.WriteLine("inner3 in outer: {0}", outer.Contains(inner3));
+ Console.WriteLine("outer.Count: {0}", outer.Count);
+ }
+ }
+}
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/Cloning.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/Cloning.cs
new file mode 100644
index 00000000000..beeea8f0c8a
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/Cloning.cs
@@ -0,0 +1,45 @@
+/*
+ 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.
+*/
+
+// C5 example: anagrams 2004-12-
+
+// Compile with
+// csc /r:C5.dll Cloning.cs
+
+using System;
+using C5;
+using SCG = System.Collections.Generic;
+
+namespace MyCloningTest {
+ class MyTest {
+ public static void Main(String[] args) {
+ IList<int> lst = new ArrayList<int>();
+ lst.AddAll(new int[] { 2, 3, 5, 7, 11, 13 });
+ Console.WriteLine(lst);
+ IList<int> v1 = lst.ViewOf(7);
+ Console.WriteLine(v1);
+ IList<int> v2 = (IList<int>)v1.Clone();
+ v2.Slide(1);
+ Console.WriteLine(v1);
+ Console.WriteLine(v2);
+ }
+ }
+}
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/CollectionCollection.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/CollectionCollection.cs
new file mode 100644
index 00000000000..5e90c1cff72
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/CollectionCollection.cs
@@ -0,0 +1,125 @@
+/*
+ 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.
+*/
+
+// C5 example: collections of collections 2004-11-16
+
+// Compile with
+// csc /r:C5.dll CollectionCollection.cs
+
+using System;
+using C5;
+using SCG = System.Collections.Generic;
+
+namespace CollectionCollection
+{
+ class MyTest
+ {
+ private static IList<int> col1 = new LinkedList<int>(),
+ col2 = new LinkedList<int>(), col3 = new LinkedList<int>();
+
+ public static void Main(String[] args) {
+ ListEqualityComparers();
+ IntSetSet();
+ CharBagSet();
+ }
+
+ public static void ListEqualityComparers() {
+ col1.AddAll<int>(new int[] { 7, 9, 13 });
+ col2.AddAll<int>(new int[] { 7, 9, 13 });
+ col3.AddAll<int>(new int[] { 9, 7, 13 });
+
+ // Default equality and hasher == sequenced equality and hasher
+ HashSet<IList<int>> hs1 = new HashSet<IList<int>>();
+ Equalities("Default equality (sequenced equality)", hs1.EqualityComparer);
+ hs1.Add(col1); hs1.Add(col2); hs1.Add(col3);
+ Console.WriteLine("hs1.Count = {0}", hs1.Count);
+
+ // Sequenced equality and hasher
+ SCG.IEqualityComparer<IList<int>> seqEqualityComparer
+ = SequencedCollectionEqualityComparer<IList<int>, int>.Default;
+ HashSet<IList<int>> hs2 = new HashSet<IList<int>>(seqEqualityComparer);
+ Equalities("Sequenced equality", hs2.EqualityComparer);
+ hs2.Add(col1); hs2.Add(col2); hs2.Add(col3);
+ Console.WriteLine("hs2.Count = {0}", hs2.Count);
+
+ // Unsequenced equality and hasher
+ SCG.IEqualityComparer<IList<int>> unseqEqualityComparer
+ = UnsequencedCollectionEqualityComparer<IList<int>, int>.Default;
+ HashSet<IList<int>> hs3 = new HashSet<IList<int>>(unseqEqualityComparer);
+ Equalities("Unsequenced equality", hs3.EqualityComparer);
+ hs3.Add(col1); hs3.Add(col2); hs3.Add(col3);
+ Console.WriteLine("hs3.Count = {0}", hs3.Count);
+
+ // Reference equality and hasher
+ SCG.IEqualityComparer<IList<int>> refEqEqualityComparer
+ = ReferenceEqualityComparer<IList<int>>.Default;
+ HashSet<IList<int>> hs4 = new HashSet<IList<int>>(refEqEqualityComparer);
+ Equalities("Reference equality", hs4.EqualityComparer);
+ hs4.Add(col1); hs4.Add(col2); hs4.Add(col3);
+ Console.WriteLine("hs4.Count = {0}", hs4.Count);
+ }
+
+ public static void Equalities(String msg, SCG.IEqualityComparer<IList<int>> equalityComparer)
+ {
+ Console.WriteLine("\n{0}:", msg);
+ Console.Write("Equals(col1,col2)={0,-5}; ", equalityComparer.Equals(col1, col2));
+ Console.Write("Equals(col1,col3)={0,-5}; ", equalityComparer.Equals(col1, col3));
+ Console.WriteLine("Equals(col2,col3)={0,-5}", equalityComparer.Equals(col2, col3));
+ }
+
+ public static void IntSetSet() {
+ ICollection<ISequenced<int>> outer = new HashSet<ISequenced<int>>();
+ int[] ss = { 2, 3, 5, 7 };
+ TreeSet<int> inner = new TreeSet<int>();
+ outer.Add(inner.Snapshot());
+ foreach (int i in ss) {
+ inner.Add(i);
+ outer.Add(inner.Snapshot());
+ }
+ foreach (ISequenced<int> s in outer) {
+ int sum = 0;
+ s.Apply(delegate(int x) { sum += x; });
+ Console.WriteLine("Set has {0} elements and sum {1}", s.Count, sum);
+ }
+ }
+
+ public static void CharBagSet() {
+ String text =
+ @"three sorted streams aligned by leading masters are stored
+ there; an integral triangle ends, and stable tables keep;
+ being alert, they later reread the logarithm, peek at the
+ recent center, then begin to send their reader algorithm.";
+ String[] words = text.Split(' ', '\n', '\r', ';', ',', '.');
+ ICollection<ICollection<char>> anagrams
+ = new HashSet<ICollection<char>>();
+ int count = 0;
+ foreach (String word in words) {
+ if (word != "") {
+ count++;
+ HashBag<char> anagram = new HashBag<char>();
+ anagram.AddAll<char>(word.ToCharArray());
+ anagrams.Add(anagram);
+ }
+ }
+ Console.WriteLine("Found {0} anagrams", count - anagrams.Count);
+ }
+ }
+}
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/CollectionSanity.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/CollectionSanity.cs
new file mode 100644
index 00000000000..fa332ee763b
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/CollectionSanity.cs
@@ -0,0 +1,65 @@
+/*
+ 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.
+*/
+
+// C5 example: anagrams 2004-12-08
+
+// Compile with
+// csc /r:C5.dll CollectionSanity.cs
+
+using System;
+using C5;
+using SCG = System.Collections.Generic;
+
+namespace CollectionSanity {
+ class CollectionSanity {
+ public static void Main(String[] args) {
+ IList<int> col1 = new LinkedList<int>(),
+ col2 = new LinkedList<int>(), col3 = new LinkedList<int>();
+ col1.AddAll<int>(new int[] { 7, 9, 13 });
+ col2.AddAll<int>(new int[] { 7, 9, 13 });
+ col3.AddAll<int>(new int[] { 9, 7, 13 });
+
+ HashSet<IList<int>> hs1 = new HashSet<IList<int>>();
+ hs1.Add(col1); hs1.Add(col2); hs1.Add(col3);
+ Console.WriteLine("hs1 is sane: {0}", EqualityComparerSanity<int,IList<int>>(hs1));
+ }
+
+ // When colls is a collection of collections, this method checks
+ // that all `inner' collections use the exact same equalityComparer. Note
+ // that two equalityComparer objects may be functionally (extensionally)
+ // identical, yet be distinct objects. However, if the equalityComparers
+ // were obtained from EqualityComparer<T>.Default, there will be at most one
+ // equalityComparer for each type T.
+
+ public static bool EqualityComparerSanity<T,U>(ICollectionValue<U> colls)
+ where U : IExtensible<T>
+ {
+ SCG.IEqualityComparer<T> equalityComparer = null;
+ foreach (IExtensible<T> coll in colls) {
+ if (equalityComparer == null)
+ equalityComparer = coll.EqualityComparer;
+ if (equalityComparer != coll.EqualityComparer)
+ return false;
+ }
+ return true;
+ }
+ }
+}
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/EventPatterns.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/EventPatterns.cs
new file mode 100644
index 00000000000..36d41a66ef4
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/EventPatterns.cs
@@ -0,0 +1,213 @@
+/*
+ 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.
+*/
+
+// C5 example: EventPatterns.cs for pattern chapter
+
+// Compile with
+// csc /r:C5.dll EventPatterns.cs
+
+using System;
+using C5;
+using SCG = System.Collections.Generic;
+
+namespace EventPatterns {
+ class EventPatterns {
+ public static void Main(String[] args) {
+ UnindexedCollectionEvents();
+ Console.WriteLine("--------------------");
+ IndexedCollectionEvents();
+ Console.WriteLine("--------------------");
+ UpdateEvent();
+ }
+
+ public static void UnindexedCollectionEvents() {
+ ICollection<int> coll = new ArrayList<int>();
+ ICollection<int> bag1 = new HashBag<int>();
+ bag1.AddAll(new int[] { 3, 2, 5, 5, 7, 7, 5, 3, 7, 7 });
+ // Add change handler
+ coll.CollectionChanged
+ += delegate(Object c) {
+ Console.WriteLine("Collection changed");
+ };
+ // Add cleared handler
+ coll.CollectionCleared
+ += delegate(Object c, ClearedEventArgs args) {
+ Console.WriteLine("Collection cleared");
+ };
+ // Add added handler
+ coll.ItemsAdded
+ += delegate(Object c, ItemCountEventArgs<int> args) {
+ Console.WriteLine("Item {0} added", args.Item);
+ };
+ // Add item count handler
+ AddItemsAddedCounter(coll);
+ AddItemsRemovedCounter(coll);
+ coll.AddAll(bag1);
+ coll.RemoveAll(new int[] { 2, 5, 6, 3, 7, 2 });
+ coll.Clear();
+ ICollection<int> bag2 = new HashBag<int>();
+ // Add added handler with multiplicity
+ bag2.ItemsAdded
+ += delegate(Object c, ItemCountEventArgs<int> args) {
+ Console.WriteLine("{0} copies of {1} added",
+ args.Count, args.Item);
+ };
+ bag2.AddAll(bag1);
+ // Add removed handler with multiplicity
+ bag2.ItemsRemoved
+ += delegate(Object c, ItemCountEventArgs<int> args) {
+ Console.WriteLine("{0} copies of {1} removed",
+ args.Count, args.Item);
+ };
+ bag2.RemoveAllCopies(7);
+ }
+
+ // This works for all kinds of collections, also those with bag
+ // semantics and representing duplicates by counting:
+
+ private static void AddItemsAddedCounter<T>(ICollection<T> coll) {
+ int addedCount = 0;
+ coll.ItemsAdded
+ += delegate(Object c, ItemCountEventArgs<T> args) {
+ addedCount += args.Count;
+ };
+ coll.CollectionChanged
+ += delegate(Object c) {
+ if (addedCount > 0)
+ Console.WriteLine("{0} items were added", addedCount);
+ addedCount = 0;
+ };
+ }
+
+ // This works for all kinds of collections, also those with bag
+ // semantics and representing duplicates by counting:
+
+ private static void AddItemsRemovedCounter<T>(ICollection<T> coll) {
+ int removedCount = 0;
+ coll.ItemsRemoved
+ += delegate(Object c, ItemCountEventArgs<T> args) {
+ removedCount += args.Count;
+ };
+ coll.CollectionChanged
+ += delegate(Object c) {
+ if (removedCount > 0)
+ Console.WriteLine("{0} items were removed", removedCount);
+ removedCount = 0;
+ };
+ }
+
+ // Event patterns on indexed collections
+
+ public static void IndexedCollectionEvents() {
+ IList<int> coll = new ArrayList<int>();
+ ICollection<int> bag = new HashBag<int>();
+ bag.AddAll(new int[] { 3, 2, 5, 5, 7, 7, 5, 3, 7, 7 });
+ // Add item inserted handler
+ coll.ItemInserted
+ += delegate(Object c, ItemAtEventArgs<int> args) {
+ Console.WriteLine("Item {0} inserted at {1}",
+ args.Item, args.Index);
+ };
+ coll.InsertAll(0, bag);
+ // Add item removed-at handler
+ coll.ItemRemovedAt
+ += delegate(Object c, ItemAtEventArgs<int> args) {
+ Console.WriteLine("Item {0} removed at {1}",
+ args.Item, args.Index);
+ };
+ coll.RemoveLast();
+ coll.RemoveFirst();
+ coll.RemoveAt(1);
+ }
+
+ // Recognizing Update event as a Removed-Added-Changed sequence
+
+ private enum State { Before, Removed, Updated };
+
+ private static void AddItemUpdatedHandler<T>(ICollection<T> coll) {
+ State state = State.Before;
+ T removed = default(T), added = default(T);
+ coll.ItemsRemoved
+ += delegate(Object c, ItemCountEventArgs<T> args) {
+ if (state==State.Before) {
+ state = State.Removed;
+ removed = args.Item;
+ } else
+ state = State.Before;
+ };
+ coll.ItemsAdded
+ += delegate(Object c, ItemCountEventArgs<T> args) {
+ if (state==State.Removed) {
+ state = State.Updated;
+ added = args.Item;
+ } else
+ state = State.Before;
+ };
+ coll.CollectionChanged
+ += delegate(Object c) {
+ if (state==State.Updated)
+ Console.WriteLine("Item {0} was updated to {1}",
+ removed, added);
+ state = State.Before;
+ };
+ }
+
+ public static void UpdateEvent() {
+ ICollection<Teacher> coll = new HashSet<Teacher>();
+ AddItemUpdatedHandler(coll);
+ Teacher kristian = new Teacher("Kristian", "physics");
+ coll.Add(kristian);
+ coll.Add(new Teacher("Poul Einer", "mathematics"));
+ // This should be caught by the update handler:
+ coll.Update(new Teacher("Thomas", "mathematics"));
+ // This should not be caught by the update handler:
+ coll.Remove(kristian);
+ coll.Add(new Teacher("Jens", "physics"));
+ // The update handler is activated also by indexed updates
+ IList<int> list = new ArrayList<int>();
+ list.AddAll(new int[] { 7, 11, 13 });
+ AddItemUpdatedHandler(list);
+ list[1] = 9;
+ }
+ }
+
+ // Example class where objects may be equal yet display differently
+
+ class Teacher : IEquatable<Teacher> {
+ private readonly String name, subject;
+
+ public Teacher(String name, String subject) {
+ this.name = name; this.subject = subject;
+ }
+
+ public bool Equals(Teacher that) {
+ return this.subject.Equals(that.subject);
+ }
+
+ public override int GetHashCode() {
+ return subject.GetHashCode();
+ }
+
+ public override String ToString() {
+ return name + "[" + subject + "]";
+ }
+ }
+}
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/Fileindex.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/Fileindex.cs
new file mode 100644
index 00000000000..e609031ce87
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/Fileindex.cs
@@ -0,0 +1,82 @@
+/*
+ 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.
+*/
+
+// C5 example: File index: read a text file, build and print a list of
+// words and the line numbers (without duplicates) on which they occur.
+
+// Compile with
+// csc /r:C5.dll Fileindex.cs
+
+using System; // Console
+using System.IO; // StreamReader, TextReader
+using System.Text.RegularExpressions; // Regex
+using C5; // IDictionary, TreeDictionary, TreeSet
+
+namespace FileIndex
+{
+ class Fileindex
+ {
+ static void Main(String[] args)
+ {
+ if (args.Length != 1)
+ Console.WriteLine("Usage: Fileindex <filename>\n");
+ else
+ {
+ IDictionary<String, TreeSet<int>> index = IndexFile(args[0]);
+ PrintIndex(index);
+ }
+ }
+
+ static IDictionary<String, TreeSet<int>> IndexFile(String filename)
+ {
+ IDictionary<String, TreeSet<int>> index = new TreeDictionary<String, TreeSet<int>>();
+ Regex delim = new Regex("[^a-zA-Z0-9]+");
+ using (TextReader rd = new StreamReader(filename))
+ {
+ int lineno = 0;
+ for (String line = rd.ReadLine(); line != null; line = rd.ReadLine())
+ {
+ String[] res = delim.Split(line);
+ lineno++;
+ foreach (String s in res)
+ if (s != "")
+ {
+ if (!index.Contains(s))
+ index[s] = new TreeSet<int>();
+ index[s].Add(lineno);
+ }
+ }
+ }
+ return index;
+ }
+
+ static void PrintIndex(IDictionary<String, TreeSet<int>> index)
+ {
+ foreach (String word in index.Keys)
+ {
+ Console.Write("{0}: ", word);
+ foreach (int ln in index[word])
+ Console.Write("{0} ", ln);
+ Console.WriteLine();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/GCHForm.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/GCHForm.cs
new file mode 100644
index 00000000000..dc37742d2fb
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/GCHForm.cs
@@ -0,0 +1,271 @@
+/*
+ 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.Drawing;
+using System.Collections;
+using System.ComponentModel;
+using System.Windows.Forms;
+using System.Diagnostics;
+using C5;
+
+namespace GConvexHull
+{
+ /// <summary>
+ /// Summary description for Form1.
+ /// </summary>
+ public class TesterForm : System.Windows.Forms.Form
+ {
+ //My data
+
+ //My GUI stuff
+ private System.Windows.Forms.Panel drawarea;
+
+ private Graphics drawg;
+
+ //Std stuff
+ private System.Windows.Forms.Button runButton;
+ private TextBox pointCount;
+
+ /// <summary>
+ /// Required designer variable.
+ /// </summary>
+ private System.ComponentModel.Container components = null;
+
+
+ public TesterForm()
+ {
+ //
+ // Required for Windows Form Designer support
+ //
+ InitializeComponent();
+
+ //
+ // TODO: Add any constructor code after InitializeComponent call
+ //
+ drawg = drawarea.CreateGraphics();
+ reset();
+ }
+
+
+ /// <summary>
+ /// Clean up any resources being used.
+ /// </summary>
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ if (components != null)
+ {
+ components.Dispose();
+ }
+ }
+
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+ /// <summary>
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ /// </summary>
+ private void InitializeComponent()
+ {
+ this.drawarea = new System.Windows.Forms.Panel();
+ this.runButton = new System.Windows.Forms.Button();
+ this.pointCount = new System.Windows.Forms.TextBox();
+ this.SuspendLayout();
+ //
+ // drawarea
+ //
+ this.drawarea.BackColor = System.Drawing.Color.White;
+ this.drawarea.Location = new System.Drawing.Point(8, 9);
+ this.drawarea.Name = "drawarea";
+ this.drawarea.Size = new System.Drawing.Size(500, 500);
+ this.drawarea.TabIndex = 0;
+ this.drawarea.Paint += new System.Windows.Forms.PaintEventHandler(this.drawarea_Paint);
+ this.drawarea.Invalidated += new System.Windows.Forms.InvalidateEventHandler(this.drawarea_Invalidated);
+ this.drawarea.MouseMove += new System.Windows.Forms.MouseEventHandler(this.drawarea_MouseMove);
+ this.drawarea.MouseClick += new System.Windows.Forms.MouseEventHandler(this.drawarea_MouseClick);
+ //
+ // runButton
+ //
+ this.runButton.Location = new System.Drawing.Point(8, 516);
+ this.runButton.Name = "runButton";
+ this.runButton.Size = new System.Drawing.Size(42, 20);
+ this.runButton.TabIndex = 1;
+ this.runButton.Text = "Run";
+ this.runButton.Click += new System.EventHandler(this.runButton_Click);
+ //
+ // pointCount
+ //
+ this.pointCount.Location = new System.Drawing.Point(97, 517);
+ this.pointCount.Name = "pointCount";
+ this.pointCount.Size = new System.Drawing.Size(55, 20);
+ this.pointCount.TabIndex = 5;
+ //
+ // TesterForm
+ //
+ this.ClientSize = new System.Drawing.Size(524, 550);
+ this.Controls.Add(this.pointCount);
+ this.Controls.Add(this.runButton);
+ this.Controls.Add(this.drawarea);
+ this.Name = "TesterForm";
+ this.Text = "C5 Tester";
+ this.Load += new System.EventHandler(this.TesterForm_Load);
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+ #endregion
+
+ /// <summary>
+ /// The main entry point for the application.
+ /// </summary>
+ [STAThread]
+ static void Main()
+ {
+ Application.EnableVisualStyles();
+ Application.Run(new TesterForm());
+ }
+
+ Point[] pts;
+ Point[] chpts;
+
+ private void runButton_Click(object sender, System.EventArgs e)
+ {
+ int N = int.Parse(pointCount.Text);
+ pts = new Point[N];
+ for (int i = 0; i < N; i++)
+ pts[i] = Point.Random(500, 500);
+ chpts = Convexhull.ConvexHull(pts);
+
+ drawarea.Invalidate();
+ }
+
+
+ private void drawarea_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
+ {
+ mydraw();
+ }
+
+
+ private void resetButton_Click(object sender, System.EventArgs e)
+ {
+ reset();
+ }
+
+
+ private void reset()
+ {
+ drawarea.Invalidate();//(new Rectangle(0, 0, 40, 40));
+ }
+
+
+
+ public void mydraw()
+ {
+ if (pts == null)
+ {
+ return;
+ }
+ for (int i = 0; i < pts.Length; i++)
+ {
+ Point p = pts[i];
+ drawg.DrawEllipse(new Pen(Color.Red), transx(p.x) - 2, transy(p.y) - 2, 4, 4);
+ }
+ for (int i = 0; i < chpts.Length; i++)
+ {
+ int j = i + 1 < chpts.Length ? i + 1 : 0;
+ drawg.DrawEllipse(new Pen(Color.Blue), transx(chpts[i].x) - 2, transy(chpts[i].y) - 2, 4, 4);
+ drawg.DrawLine(new Pen(Color.LawnGreen), transx(chpts[i].x), transx(chpts[i].y), transx(chpts[j].x), transx(chpts[j].y));
+ }
+ }
+
+
+
+ private int transx(double x)
+ {
+ return (int)x;
+ }
+
+
+ private int transy(double y)
+ {
+ return (int)y;
+ }
+
+
+ private void dumpButton_Click(object sender, System.EventArgs e)
+ {
+ Debug.WriteLine("###############");
+ Debug.WriteLine("###############");
+ }
+
+
+ private void graphTypeControlArray_Click(object sender, System.EventArgs e)
+ {
+ Debug.WriteLine(e.GetType());
+ Debug.WriteLine(sender.GetType());
+ drawarea.Invalidate();
+ }
+
+
+ private void drawarea_MouseMove(object sender, MouseEventArgs e)
+ {
+ }
+
+
+ private void drawarea_MouseClick(object sender, MouseEventArgs e)
+ {
+ //double x = untransx(e.X), y = untransy(e.Y);
+
+ }
+
+
+ private void drawarea_Invalidated(object sender, InvalidateEventArgs e)
+ {
+ //msg.Text = e.InvalidRect + "";
+ //mydraw();
+ }
+
+
+ private void preparedFigureSelection_SelectedIndexChanged(object sender, System.EventArgs e)
+ {
+ }
+
+ private void voronoiButton_CheckedChanged(object sender, EventArgs e)
+ {
+ graphTypeControlArray_Click(sender, e);
+ }
+
+ private void delaunayButton_CheckedChanged(object sender, EventArgs e)
+ {
+ graphTypeControlArray_Click(sender, e);
+ }
+
+ private void TesterForm_Load(object sender, EventArgs e)
+ {
+
+ }
+
+ }
+}
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/GCHForm.resx b/mcs/class/Mono.C5/1.0/UserGuideExamples/GCHForm.resx
new file mode 100644
index 00000000000..04d94f3d103
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/GCHForm.resx
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+ <value>25</value>
+ </metadata>
+</root> \ No newline at end of file
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/GConvexHull.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/GConvexHull.cs
new file mode 100644
index 00000000000..48675b3bc69
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/GConvexHull.cs
@@ -0,0 +1,178 @@
+/*
+ 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.
+*/
+
+// Compile with
+// csc /r:C5.dll GConvexHull.cs
+
+using System;
+using C5;
+
+namespace GConvexHull
+{
+// Find the convex hull of a point set in the plane
+
+// An implementation of Graham's (1972) point elimination algorithm,
+// as modified by Andrew (1979) to find lower and upper hull separately.
+
+// This implementation correctly handle duplicate points, and
+// multiple points with the same x-coordinate.
+
+// 1. Sort the points lexicographically by increasing (x,y), thus
+// finding also a leftmost point L and a rightmost point R.
+// 2. Partition the point set into two lists, upper and lower, according as
+// point is above or below the segment LR. The upper list begins with
+// L and ends with R; the lower list begins with R and ends with L.
+// 3. Traverse the point lists clockwise, eliminating all but the extreme
+// points (thus eliminating also duplicate points).
+// 4. Join the point lists (in clockwise order) in an array,
+// leaving out L from lower and R from upper.
+
+ public class Convexhull
+ {
+ public static Point[] ConvexHull(Point[] pts)
+ {
+ // 1. Sort points lexicographically by increasing (x, y)
+ int N = pts.Length;
+ Array.Sort(pts);
+ Point left = pts[0], right = pts[N - 1];
+ // 2. Partition into lower hull and upper hull
+ IList<Point> lower = new LinkedList<Point>(),
+ upper = new LinkedList<Point>();
+ lower.InsertFirst(left); upper.InsertLast(left);
+ for (int i = 0; i < N; i++)
+ {
+ double det = Point.Area2(left, right, pts[i]);
+ if (det < 0)
+ lower.InsertFirst(pts[i]);
+ else if (det > 0)
+ upper.InsertLast(pts[i]);
+ }
+ lower.InsertFirst(right);
+ upper.InsertLast(right);
+ // 3. Eliminate points not on the hull
+ Eliminate(lower);
+ Eliminate(upper);
+ // 4. Join the lower and upper hull, leaving out lower.Last and upper.Last
+ Point[] res = new Point[lower.Count + upper.Count - 2];
+ lower[0, lower.Count - 1].CopyTo(res, 0);
+ upper[0, upper.Count - 1].CopyTo(res, lower.Count - 1);
+ return res;
+ }
+
+ // Graham's scan
+ public static void Eliminate(IList<Point> lst)
+ {
+ IList<Point> view = lst.View(0, 0);
+ int slide = 0;
+ while (view.TrySlide(slide, 3))
+ if (Point.Area2(view[0], view[1], view[2]) < 0) // right turn
+ slide = 1;
+ else
+ { // left or straight
+ view.RemoveAt(1);
+ slide = view.Offset != 0 ? -1 : 0;
+ }
+ }
+ }
+
+// ------------------------------------------------------------
+
+// Points in the plane
+
+ public class Point : IComparable<Point>
+ {
+ private static readonly C5Random rnd = new C5Random(42);
+
+ public readonly double x, y;
+
+ public Point(double x, double y)
+ {
+ this.x = x; this.y = y;
+ }
+
+ public override string ToString()
+ {
+ return "(" + x + ", " + y + ")";
+ }
+
+ public static Point Random(int w, int h)
+ {
+ return new Point(rnd.Next(w), rnd.Next(h));
+ }
+
+ public bool Equals(Point p2)
+ {
+ return x == p2.x && y == p2.y;
+ }
+
+ public int CompareTo(Point p2)
+ {
+ int major = x.CompareTo(p2.x);
+ return major != 0 ? major : y.CompareTo(p2.y);
+ }
+
+ // Twice the signed area of the triangle (p0, p1, p2)
+ public static double Area2(Point p0, Point p1, Point p2)
+ {
+ return p0.x * (p1.y - p2.y) + p1.x * (p2.y - p0.y) + p2.x * (p0.y - p1.y);
+ }
+ }
+
+// ------------------------------------------------------------
+
+ class GConvexHull
+ {
+ static void Main(String[] args)
+ {
+ if (args.Length == 1)
+ {
+ string arg = args[0];
+ int N = int.Parse(arg);
+ Point[] pts = new Point[N];
+ for (int i = 0; i < N; i++)
+ pts[i] = Point.Random(500, 500);
+ Point[] chpts = Convexhull.ConvexHull(pts);
+ Console.WriteLine("Area is " + Area(chpts));
+ Print(chpts);
+ }
+ else
+ Console.WriteLine("Usage: GConvexHull <pointcount>\n");
+ }
+
+ // The area of a polygon (represented by an array of ordered vertices)
+ public static double Area(Point[] pts)
+ {
+ int N = pts.Length;
+ Point origo = new Point(0, 0);
+ double area2 = 0;
+ for (int i = 0; i < N; i++)
+ area2 += Point.Area2(origo, pts[i], pts[(i + 1) % N]);
+ return Math.Abs(area2 / 2);
+ }
+
+ public static void Print(Point[] pts)
+ {
+ int N = pts.Length;
+ for (int i = 0; i < N; i++)
+ Console.WriteLine(pts[i]);
+ }
+ }
+}
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/GNfaToDfa.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/GNfaToDfa.cs
new file mode 100644
index 00000000000..86766061162
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/GNfaToDfa.cs
@@ -0,0 +1,666 @@
+/*
+ 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.
+*/
+
+// Compile with
+// csc /r:C5.dll GNfaToDfa.cs
+
+// C5 examples: RegExp -> NFA -> DFA -> Graph
+// Java 2000-10-07, GC# 2001-10-23, C# 2.0 2003-09-03, C# 2.0+C5 2004-08-08
+
+// This file contains, in order:
+// * Helper class Set<T> defined in terms of C5 classes.
+// * A class Nfa for representing an NFA (a nondeterministic finite
+// automaton), and for converting it to a DFA (a deterministic
+// finite automaton). Most complexity is in this class.
+// * A class Dfa for representing a DFA, a deterministic finite
+// automaton, and for writing a dot input file representing the DFA.
+// * Classes for representing regular expressions, and for building an
+// NFA from a regular expression
+// * A test class that creates an NFA, a DFA, and a dot input file
+// for a number of small regular expressions. The DFAs are
+// not minimized.
+
+using System;
+using System.Text;
+using System.IO;
+using C5;
+using SCG = System.Collections.Generic;
+
+namespace GNfaToDfa
+{
+
+ public class Set<T> : HashSet<T> {
+ public Set(SCG.IEnumerable<T> enm) : base() {
+ AddAll(enm);
+ }
+
+ public Set(params T[] elems) : this((SCG.IEnumerable<T>)elems) { }
+
+ // Set union (+), difference (-), and intersection (*):
+
+ public static Set<T> operator +(Set<T> s1, Set<T> s2) {
+ if (s1 == null || s2 == null)
+ throw new ArgumentNullException("Set+Set");
+ else {
+ Set<T> res = new Set<T>(s1);
+ res.AddAll(s2);
+ return res;
+ }
+ }
+
+ public static Set<T> operator -(Set<T> s1, Set<T> s2) {
+ if (s1 == null || s2 == null)
+ throw new ArgumentNullException("Set-Set");
+ else {
+ Set<T> res = new Set<T>(s1);
+ res.RemoveAll(s2);
+ return res;
+ }
+ }
+
+ public static Set<T> operator *(Set<T> s1, Set<T> s2) {
+ if (s1 == null || s2 == null)
+ throw new ArgumentNullException("Set*Set");
+ else {
+ Set<T> res = new Set<T>(s1);
+ res.RetainAll(s2);
+ return res;
+ }
+ }
+
+ // Equality of sets; take care to avoid infinite loops
+
+ public static bool operator ==(Set<T> s1, Set<T> s2) {
+ return EqualityComparer<Set<T>>.Default.Equals(s1, s2);
+ }
+
+ public static bool operator !=(Set<T> s1, Set<T> s2) {
+ return !(s1 == s2);
+ }
+
+ public override bool Equals(Object that) {
+ return this == (that as Set<T>);
+ }
+
+ public override int GetHashCode() {
+ return EqualityComparer<Set<T>>.Default.GetHashCode(this);
+ }
+
+ // Subset (<=) and superset (>=) relation:
+
+ public static bool operator <=(Set<T> s1, Set<T> s2) {
+ if (s1 == null || s2 == null)
+ throw new ArgumentNullException("Set<=Set");
+ else
+ return s1.ContainsAll(s2);
+ }
+
+ public static bool operator >=(Set<T> s1, Set<T> s2) {
+ if (s1 == null || s2 == null)
+ throw new ArgumentNullException("Set>=Set");
+ else
+ return s2.ContainsAll(s1);
+ }
+
+ public override String ToString() {
+ StringBuilder sb = new StringBuilder();
+ sb.Append("{");
+ bool first = true;
+ foreach (T x in this) {
+ if (!first)
+ sb.Append(",");
+ sb.Append(x);
+ first = false;
+ }
+ sb.Append("}");
+ return sb.ToString();
+ }
+ }
+
+// ----------------------------------------------------------------------
+
+// Regular expressions, NFAs, DFAs, and dot graphs
+// sestoft@dina.kvl.dk *
+// Java 2001-07-10 * C# 2001-10-22 * Gen C# 2001-10-23, 2003-09-03
+
+// In the Generic C# 2.0 version we
+// use Queue<int> and Queue<Set<int>> for worklists
+// use Set<int> for pre-DFA states
+// use ArrayList<Transition> for NFA transition relations
+// use HashDictionary<Set<int>, HashDictionary<String, Set<int>>>
+// and HashDictionary<int, HashDictionary<String, int>> for DFA transition relations
+
+/* Class Nfa and conversion from NFA to DFA ---------------------------
+
+ A nondeterministic finite automaton (NFA) is represented as a
+ dictionary mapping a state number (int) to an arraylist of
+ Transitions, a Transition being a pair of a label lab (a string,
+ null meaning epsilon) and a target state (an int).
+
+ A DFA is created from an NFA in two steps:
+
+ (1) Construct a DFA whose each of whose states is composite,
+ namely a set of NFA states (Set of int). This is done by
+ methods CompositeDfaTrans and EpsilonClose.
+
+ (2) Replace composite states (Set of int) by simple states
+ (int). This is done by methods Rename and MkRenamer.
+
+ Method CompositeDfaTrans works as follows:
+
+ Create the epsilon-closure S0 (a Set of ints) of the start state
+ s0, and put it in a worklist (a Queue). Create an empty DFA
+ transition relation, which is a dictionary mapping a composite
+ state (an epsilon-closed set of ints) to a dictionary mapping a
+ label (a non-null string) to a composite state.
+
+ Repeatedly choose a composite state S from the worklist. If it is
+ not already in the keyset of the DFA transition relation, compute
+ for every non-epsilon label lab the set T of states reachable by
+ that label from some state s in S. Compute the epsilon-closure
+ Tclose of every such state T and put it on the worklist. Then add
+ the transition S -lab-> Tclose to the DFA transition relation, for
+ every lab.
+
+ Method EpsilonClose works as follows:
+
+ Given a set S of states. Put the states of S in a worklist.
+ Repeatedly choose a state s from the worklist, and consider all
+ epsilon-transitions s -eps-> s' from s. If s' is in S already,
+ then do nothing; otherwise add s' to S and the worklist. When the
+ worklist is empty, S is epsilon-closed; return S.
+
+ Method MkRenamer works as follows:
+
+ Given a dictionary mapping a set of int to something, create an
+ injective dictionary mapping from set of int to int, by choosing a
+ fresh int for every key in the given dictionary.
+
+ Method Rename works as follows:
+
+ Given a dictionary mapping a set of int to a dictionary mapping a
+ string to set of int, use the result of MkRenamer to replace all
+ sets of ints by ints.
+
+*/
+
+ class Nfa {
+ private readonly int startState;
+ private readonly int exitState; // This is the unique accept state
+ private readonly IDictionary<int, ArrayList<Transition>> trans;
+
+ public Nfa(int startState, int exitState) {
+ this.startState = startState; this.exitState = exitState;
+ trans = new HashDictionary<int, ArrayList<Transition>>();
+ if (!startState.Equals(exitState))
+ trans.Add(exitState, new ArrayList<Transition>());
+ }
+
+ public int Start { get { return startState; } }
+
+ public int Exit { get { return exitState; } }
+
+ public IDictionary<int, ArrayList<Transition>> Trans {
+ get { return trans; }
+ }
+
+ public void AddTrans(int s1, String lab, int s2) {
+ ArrayList<Transition> s1Trans;
+ if (trans.Contains(s1))
+ s1Trans = trans[s1];
+ else {
+ s1Trans = new ArrayList<Transition>();
+ trans.Add(s1, s1Trans);
+ }
+ s1Trans.Add(new Transition(lab, s2));
+ }
+
+ public void AddTrans(KeyValuePair<int, ArrayList<Transition>> tr) {
+ // Assumption: if tr is in trans, it maps to an empty list (end state)
+ trans.Remove(tr.Key);
+ trans.Add(tr.Key, tr.Value);
+ }
+
+ public override String ToString() {
+ return "NFA start=" + startState + " exit=" + exitState;
+ }
+
+ // Construct the transition relation of a composite-state DFA from
+ // an NFA with start state s0 and transition relation trans (a
+ // dictionary mapping int to arraylist of Transition). The start
+ // state of the constructed DFA is the epsilon closure of s0, and
+ // its transition relation is a dictionary mapping a composite state
+ // (a set of ints) to a dictionary mapping a label (a string) to a
+ // composite state (a set of ints).
+
+ static IDictionary<Set<int>, IDictionary<String, Set<int>>>
+ CompositeDfaTrans(int s0, IDictionary<int, ArrayList<Transition>> trans) {
+ Set<int> S0 = EpsilonClose(new Set<int>(s0), trans);
+ IQueue<Set<int>> worklist = new CircularQueue<Set<int>>();
+ worklist.Enqueue(S0);
+ // The transition relation of the DFA
+ IDictionary<Set<int>, IDictionary<String, Set<int>>> res =
+ new HashDictionary<Set<int>, IDictionary<String, Set<int>>>();
+ while (!worklist.IsEmpty) {
+ Set<int> S = worklist.Dequeue();
+ if (!res.Contains(S)) {
+ // The S -lab-> T transition relation being constructed for a given S
+ IDictionary<String, Set<int>> STrans =
+ new HashDictionary<String, Set<int>>();
+ // For all s in S, consider all transitions s -lab-> t
+ foreach (int s in S) {
+ // For all non-epsilon transitions s -lab-> t, add t to T
+ foreach (Transition tr in trans[s]) {
+ if (tr.lab != null) { // Non-epsilon transition
+ Set<int> toState;
+ if (STrans.Contains(tr.lab)) // Already a transition on lab
+ toState = STrans[tr.lab];
+ else { // No transitions on lab yet
+ toState = new Set<int>();
+ STrans.Add(tr.lab, toState);
+ }
+ toState.Add(tr.target);
+ }
+ }
+ }
+ // Epsilon-close all T such that S -lab-> T, and put on worklist
+ IDictionary<String, Set<int>> STransClosed =
+ new HashDictionary<String, Set<int>>();
+ foreach (KeyValuePair<String, Set<int>> entry in STrans) {
+ Set<int> Tclose = EpsilonClose(entry.Value, trans);
+ STransClosed.Add(entry.Key, Tclose);
+ worklist.Enqueue(Tclose);
+ }
+ res.Add(S, STransClosed);
+ }
+ }
+ return res;
+ }
+
+ // Compute epsilon-closure of state set S in transition relation trans.
+
+ static Set<int>
+ EpsilonClose(Set<int> S, IDictionary<int, ArrayList<Transition>> trans) {
+ // The worklist initially contains all S members
+ IQueue<int> worklist = new CircularQueue<int>();
+ S.Apply(worklist.Enqueue);
+ Set<int> res = new Set<int>(S);
+ while (!worklist.IsEmpty) {
+ int s = worklist.Dequeue();
+ foreach (Transition tr in trans[s]) {
+ if (tr.lab == null && !res.Contains(tr.target)) {
+ res.Add(tr.target);
+ worklist.Enqueue(tr.target);
+ }
+ }
+ }
+ return res;
+ }
+
+ // Compute a renamer, which is a dictionary mapping set of int to int
+
+ static IDictionary<Set<int>, int> MkRenamer(ICollectionValue<Set<int>> states)
+ {
+ IDictionary<Set<int>, int> renamer = new HashDictionary<Set<int>, int>();
+ int count = 0;
+ foreach (Set<int> k in states)
+ renamer.Add(k, count++);
+ return renamer;
+ }
+
+ // Using a renamer (a dictionary mapping set of int to int), replace
+ // composite (set of int) states with simple (int) states in the
+ // transition relation trans, which is a dictionary mapping set of
+ // int to a dictionary mapping from string to set of int. The
+ // result is a dictionary mapping from int to a dictionary mapping
+ // from string to int.
+
+ static IDictionary<int, IDictionary<String, int>>
+ Rename(IDictionary<Set<int>, int> renamer,
+ IDictionary<Set<int>, IDictionary<String, Set<int>>> trans)
+ {
+ IDictionary<int, IDictionary<String, int>> newtrans =
+ new HashDictionary<int, IDictionary<String, int>>();
+ foreach (KeyValuePair<Set<int>, IDictionary<String, Set<int>>> entry
+ in trans) {
+ Set<int> k = entry.Key;
+ IDictionary<String, int> newktrans = new HashDictionary<String, int>();
+ foreach (KeyValuePair<String, Set<int>> tr in entry.Value)
+ newktrans.Add(tr.Key, renamer[tr.Value]);
+ newtrans.Add(renamer[k], newktrans);
+ }
+ return newtrans;
+ }
+
+ static Set<int> AcceptStates(ICollectionValue<Set<int>> states,
+ IDictionary<Set<int>, int> renamer,
+ int exit)
+ {
+ Set<int> acceptStates = new Set<int>();
+ foreach (Set<int> state in states)
+ if (state.Contains(exit))
+ acceptStates.Add(renamer[state]);
+ return acceptStates;
+ }
+
+ public Dfa ToDfa() {
+ IDictionary<Set<int>, IDictionary<String, Set<int>>>
+ cDfaTrans = CompositeDfaTrans(startState, trans);
+ Set<int> cDfaStart = EpsilonClose(new Set<int>(startState), trans);
+ ICollectionValue<Set<int>> cDfaStates = cDfaTrans.Keys;
+ IDictionary<Set<int>, int> renamer = MkRenamer(cDfaStates);
+ IDictionary<int, IDictionary<String, int>> simpleDfaTrans =
+ Rename(renamer, cDfaTrans);
+ int simpleDfaStart = renamer[cDfaStart];
+ Set<int> simpleDfaAccept = AcceptStates(cDfaStates, renamer, exitState);
+ return new Dfa(simpleDfaStart, simpleDfaAccept, simpleDfaTrans);
+ }
+
+ // Nested class for creating distinctly named states when constructing NFAs
+
+ public class NameSource {
+ private static int nextName = 0;
+
+ public int next() {
+ return nextName++;
+ }
+ }
+
+ // Write an input file for the dot program. You can find dot at
+ // http://www.research.att.com/sw/tools/graphviz/
+
+ public void WriteDot(String filename) {
+ TextWriter wr =
+ new StreamWriter(new FileStream(filename, FileMode.Create,
+ FileAccess.Write));
+ wr.WriteLine("// Format this file as a Postscript file with ");
+ wr.WriteLine("// dot " + filename + " -Tps -o out.ps\n");
+ wr.WriteLine("digraph nfa {");
+ wr.WriteLine("size=\"11,8.25\";");
+ wr.WriteLine("rotate=90;");
+ wr.WriteLine("rankdir=LR;");
+ wr.WriteLine("start [style=invis];"); // Invisible start node
+ wr.WriteLine("start -> d" + startState); // Edge into start state
+
+ // The accept state has a double circle
+ wr.WriteLine("d" + exitState + " [peripheries=2];");
+
+ // The transitions
+ foreach (KeyValuePair<int, ArrayList<Transition>> entry in trans) {
+ int s1 = entry.Key;
+ foreach (Transition s1Trans in entry.Value) {
+ String lab = s1Trans.lab ?? "eps";
+ int s2 = s1Trans.target;
+ wr.WriteLine("d" + s1 + " -> d" + s2 + " [label=\"" + lab + "\"];");
+ }
+ }
+ wr.WriteLine("}");
+ wr.Close();
+ }
+ }
+
+// Class Transition, a transition from one state to another ----------
+
+ public class Transition {
+ public readonly String lab;
+ public readonly int target;
+
+ public Transition(String lab, int target) {
+ this.lab = lab; this.target = target;
+ }
+
+ public override String ToString() {
+ return "-" + lab + "-> " + target;
+ }
+ }
+
+// Class Dfa, deterministic finite automata --------------------------
+
+/*
+ A deterministic finite automaton (DFA) is represented as a
+ dictionary mapping state number (int) to a dictionary mapping label
+ (a non-null string) to a target state (an int).
+*/
+
+ class Dfa {
+ private readonly int startState;
+ private readonly Set<int> acceptStates;
+ private readonly IDictionary<int, IDictionary<String, int>> trans;
+
+ public Dfa(int startState, Set<int> acceptStates,
+ IDictionary<int, IDictionary<String, int>> trans)
+ {
+ this.startState = startState;
+ this.acceptStates = acceptStates;
+ this.trans = trans;
+ }
+
+ public int Start { get { return startState; } }
+
+ public Set<int> Accept { get { return acceptStates; } }
+
+ public IDictionary<int, IDictionary<String, int>> Trans {
+ get { return trans; }
+ }
+
+ public override String ToString() {
+ return "DFA start=" + startState + "\naccept=" + acceptStates;
+ }
+
+ // Write an input file for the dot program. You can find dot at
+ // http://www.research.att.com/sw/tools/graphviz/
+
+ public void WriteDot(String filename) {
+ TextWriter wr =
+ new StreamWriter(new FileStream(filename, FileMode.Create,
+ FileAccess.Write));
+ wr.WriteLine("// Format this file as a Postscript file with ");
+ wr.WriteLine("// dot " + filename + " -Tps -o out.ps\n");
+ wr.WriteLine("digraph dfa {");
+ wr.WriteLine("size=\"11,8.25\";");
+ wr.WriteLine("rotate=90;");
+ wr.WriteLine("rankdir=LR;");
+ wr.WriteLine("start [style=invis];"); // Invisible start node
+ wr.WriteLine("start -> d" + startState); // Edge into start state
+
+ // Accept states are double circles
+ foreach (int state in trans.Keys)
+ if (acceptStates.Contains(state))
+ wr.WriteLine("d" + state + " [peripheries=2];");
+
+ // The transitions
+ foreach (KeyValuePair<int, IDictionary<String, int>> entry in trans) {
+ int s1 = entry.Key;
+ foreach (KeyValuePair<String, int> s1Trans in entry.Value) {
+ String lab = s1Trans.Key;
+ int s2 = s1Trans.Value;
+ wr.WriteLine("d" + s1 + " -> d" + s2 + " [label=\"" + lab + "\"];");
+ }
+ }
+ wr.WriteLine("}");
+ wr.Close();
+ }
+ }
+
+// Regular expressions ----------------------------------------------
+//
+// Abstract syntax of regular expressions
+// r ::= A | r1 r2 | (r1|r2) | r*
+//
+
+ abstract class Regex {
+ abstract public Nfa MkNfa(Nfa.NameSource names);
+ }
+
+ class Eps : Regex {
+ // The resulting nfa0 has form s0s -eps-> s0e
+
+ public override Nfa MkNfa(Nfa.NameSource names) {
+ int s0s = names.next();
+ int s0e = names.next();
+ Nfa nfa0 = new Nfa(s0s, s0e);
+ nfa0.AddTrans(s0s, null, s0e);
+ return nfa0;
+ }
+ }
+
+ class Sym : Regex {
+ String sym;
+
+ public Sym(String sym) {
+ this.sym = sym;
+ }
+
+ // The resulting nfa0 has form s0s -sym-> s0e
+
+ public override Nfa MkNfa(Nfa.NameSource names) {
+ int s0s = names.next();
+ int s0e = names.next();
+ Nfa nfa0 = new Nfa(s0s, s0e);
+ nfa0.AddTrans(s0s, sym, s0e);
+ return nfa0;
+ }
+ }
+
+ class Seq : Regex {
+ Regex r1, r2;
+
+ public Seq(Regex r1, Regex r2) {
+ this.r1 = r1; this.r2 = r2;
+ }
+
+ // If nfa1 has form s1s ----> s1e
+ // and nfa2 has form s2s ----> s2e
+ // then nfa0 has form s1s ----> s1e -eps-> s2s ----> s2e
+
+ public override Nfa MkNfa(Nfa.NameSource names) {
+ Nfa nfa1 = r1.MkNfa(names);
+ Nfa nfa2 = r2.MkNfa(names);
+ Nfa nfa0 = new Nfa(nfa1.Start, nfa2.Exit);
+ foreach (KeyValuePair<int, ArrayList<Transition>> entry in nfa1.Trans)
+ nfa0.AddTrans(entry);
+ foreach (KeyValuePair<int, ArrayList<Transition>> entry in nfa2.Trans)
+ nfa0.AddTrans(entry);
+ nfa0.AddTrans(nfa1.Exit, null, nfa2.Start);
+ return nfa0;
+ }
+ }
+
+ class Alt : Regex {
+ Regex r1, r2;
+
+ public Alt(Regex r1, Regex r2) {
+ this.r1 = r1; this.r2 = r2;
+ }
+
+ // If nfa1 has form s1s ----> s1e
+ // and nfa2 has form s2s ----> s2e
+ // then nfa0 has form s0s -eps-> s1s ----> s1e -eps-> s0e
+ // s0s -eps-> s2s ----> s2e -eps-> s0e
+
+ public override Nfa MkNfa(Nfa.NameSource names) {
+ Nfa nfa1 = r1.MkNfa(names);
+ Nfa nfa2 = r2.MkNfa(names);
+ int s0s = names.next();
+ int s0e = names.next();
+ Nfa nfa0 = new Nfa(s0s, s0e);
+ foreach (KeyValuePair<int, ArrayList<Transition>> entry in nfa1.Trans)
+ nfa0.AddTrans(entry);
+ foreach (KeyValuePair<int, ArrayList<Transition>> entry in nfa2.Trans)
+ nfa0.AddTrans(entry);
+ nfa0.AddTrans(s0s, null, nfa1.Start);
+ nfa0.AddTrans(s0s, null, nfa2.Start);
+ nfa0.AddTrans(nfa1.Exit, null, s0e);
+ nfa0.AddTrans(nfa2.Exit, null, s0e);
+ return nfa0;
+ }
+ }
+
+ class Star : Regex {
+ Regex r;
+
+ public Star(Regex r) {
+ this.r = r;
+ }
+
+ // If nfa1 has form s1s ----> s1e
+ // then nfa0 has form s0s ----> s0s
+ // s0s -eps-> s1s
+ // s1e -eps-> s0s
+
+ public override Nfa MkNfa(Nfa.NameSource names) {
+ Nfa nfa1 = r.MkNfa(names);
+ int s0s = names.next();
+ Nfa nfa0 = new Nfa(s0s, s0s);
+ foreach (KeyValuePair<int, ArrayList<Transition>> entry in nfa1.Trans)
+ nfa0.AddTrans(entry);
+ nfa0.AddTrans(s0s, null, nfa1.Start);
+ nfa0.AddTrans(nfa1.Exit, null, s0s);
+ return nfa0;
+ }
+ }
+
+// Trying the RE->NFA->DFA translation on three regular expressions
+
+ class TestNFA {
+ public static void Main(String[] args) {
+ Regex a = new Sym("A");
+ Regex b = new Sym("B");
+ Regex c = new Sym("C");
+ Regex abStar = new Star(new Alt(a, b));
+ Regex bb = new Seq(b, b);
+ Regex r = new Seq(abStar, new Seq(a, b));
+ // The regular expression (a|b)*ab
+ BuildAndShow("ex1", r);
+ // The regular expression ((a|b)*ab)*
+ BuildAndShow("ex2", new Star(r));
+ // The regular expression ((a|b)*ab)((a|b)*ab)
+ BuildAndShow("ex3", new Seq(r, r));
+ // The regular expression (a|b)*abb, from ASU 1986 p 136
+ BuildAndShow("ex4", new Seq(abStar, new Seq(a, bb)));
+ // SML reals: sign?((digit+(\.digit+)?))([eE]sign?digit+)?
+ Regex d = new Sym("digit");
+ Regex dPlus = new Seq(d, new Star(d));
+ Regex s = new Sym("sign");
+ Regex sOpt = new Alt(s, new Eps());
+ Regex dot = new Sym(".");
+ Regex dotDigOpt = new Alt(new Eps(), new Seq(dot, dPlus));
+ Regex mant = new Seq(sOpt, new Seq(dPlus, dotDigOpt));
+ Regex e = new Sym("e");
+ Regex exp = new Alt(new Eps(), new Seq(e, new Seq(sOpt, dPlus)));
+ Regex smlReal = new Seq(mant, exp);
+ BuildAndShow("ex5", smlReal);
+ }
+
+ public static void BuildAndShow(String fileprefix, Regex r) {
+ Nfa nfa = r.MkNfa(new Nfa.NameSource());
+ Console.WriteLine(nfa);
+ Console.WriteLine("Writing NFA graph to file");
+ nfa.WriteDot(fileprefix + "nfa.dot");
+ Console.WriteLine("---");
+ Dfa dfa = nfa.ToDfa();
+ Console.WriteLine(dfa);
+ Console.WriteLine("Writing DFA graph to file");
+ dfa.WriteDot(fileprefix + "dfa.dot");
+ Console.WriteLine();
+ }
+ }
+}
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/GettingStarted.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/GettingStarted.cs
new file mode 100644
index 00000000000..8fac0f9d23e
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/GettingStarted.cs
@@ -0,0 +1,50 @@
+/*
+ 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.
+*/
+
+// C5 example: GettingStarted 2005-01-18
+
+// Compile with
+// csc /r:C5.dll GettingStarted.cs
+
+using System;
+using C5;
+using SCG = System.Collections.Generic;
+
+namespace GettingStarted {
+ class GettingStarted {
+ public static void Main(String[] args) {
+ IList<String> names = new ArrayList<String>();
+ names.AddAll(new String[] { "Hoover", "Roosevelt",
+ "Truman", "Eisenhower", "Kennedy" });
+ // Print list:
+ Console.WriteLine(names);
+ // Print item 1 ("Roosevelt") in the list:
+ Console.WriteLine(names[1]);
+ // Create a list view comprising post-WW2 presidents:
+ IList<String> postWWII = names.View(2, 3);
+ // Print item 2 ("Kennedy") in the view:
+ Console.WriteLine(postWWII[2]);
+ // Enumerate and print the list view in reverse chronological order:
+ foreach (String name in postWWII.Backwards())
+ Console.WriteLine(name);
+ }
+ }
+}
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/Graph.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/Graph.cs
new file mode 100644
index 00000000000..6c52f2f125e
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/Graph.cs
@@ -0,0 +1,1679 @@
+/*
+ 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.
+*/
+
+// C5 example: Graph representation with basic algorithms using C5
+
+
+// Compile with
+// csc /r:C5.dll Graph.cs
+
+
+// The code is structured as a rudimentary Graph library, with an interface
+// for (edge)weighted graphs and a single implementation based on an
+// adjacency list representation using hash dictionaries.
+
+
+// The algorithms implemented include:
+//
+// Breadth-First-Search and Depth-First-Search, with an interface based on actions
+// to be taken as edges are traversed. Applications are checking for connectedness,
+// counting components
+//
+// Priority-First-Search, where edges are traversed according to either weight or
+// accumulated weight from the start of the search.
+// An application of the non-accumulating version is the construction of a minimal
+// spanning tree and therefore the following approximation algorithm.
+// Applications of the accumulating version are the construction of a shortest path
+// and the computation of the distance from one vertex to another one.
+//
+// An approximation algorithm for Travelling Salesman Problems,
+// where the weights satisfies the triangle inequality.
+
+
+// Pervasive generic parameters:
+// V: The type of a vertex in a graph. Vertices are identified
+// by the Equals method inherited from object (or overridden).
+// E: The type of additional data associated with edges in a graph.
+// W: The type of values of weights on edges in a weighted graph,
+// in practise usually int or double. Must be comparable and
+// there must be given a compatible way to add values.
+
+// Interfaces:
+// IGraph<V,E,W>: The interface for a graph implementation with
+// vertex type V, edge dat type E and weight values of type W.
+// IWeight<E,W>: The interface of a weight function
+
+// Classes:
+// HashGraph<V,E,W>: An implementation of IWeightedGraph<V,E,W> based on
+// adjacency lists represented as hash dictionaries.
+// HashGraph<V,E,W>.EdgesValue: A helper class for the Edges() method
+// CountWeight<E>: A
+// IntWeight:
+// DoubleWeight:
+
+// Value Types:
+// Edge<V,E>:
+// EdgeAction<V,E,U>:
+
+// Some notes:
+// The code only supports "natural" equality of vertices.
+
+using C5;
+using System;
+using SCG = System.Collections.Generic;
+
+namespace Graph
+{
+ /// <summary>
+ /// (Duer ikke)
+ /// </summary>
+ /// <typeparam name="V"></typeparam>
+ /// <typeparam name="E"></typeparam>
+ interface IGraphVertex<V, E,W> where W : IComparable<W>
+ {
+ V Value { get;}
+ IGraph<V, E, W> Graph { get;}
+ ICollectionValue<KeyValuePair<V, E>> Adjacent { get;}
+
+ }
+
+ class Vertex<V>
+ {
+ //V v;
+ }
+/// <summary>
+///
+/// </summary>
+/// <typeparam name="V"></typeparam>
+/// <typeparam name="E"></typeparam>
+/// <typeparam name="W"></typeparam>
+ interface IGraph<V, E, W> where W : IComparable<W>
+ {
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>The weight object for this graph</value>
+ IWeight<E, W> Weight { get;}
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>The number of vertices in this graph</value>
+ int VertexCount { get;}
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>The number of edges in this graph</value>
+ int EdgeCount { get;}
+
+ /// <summary>
+ /// The collection of vertices of this graph.
+ /// The return value is a snapshot, not a live view onto the graph.
+ /// </summary>
+ /// <returns></returns>
+ ICollectionValue<V> Vertices();
+
+ /// <summary>
+ /// The collection of edges incident to a particular vertex.
+ /// The return value is a snapshot og (endvertex, edgedata) pairs.
+ /// </summary>
+ /// <param name="vertex"></param>
+ /// <returns></returns>
+ ICollectionValue<KeyValuePair<V, E>> Adjacent(V vertex);
+
+ /// <summary>
+ /// The collection of all edges in the graph. The return value is a snapshot
+ /// of Edge values. Each edge is present once for an undefined direction.
+ /// </summary>
+ /// <returns></returns>
+ ICollectionValue<Edge<V, E>> Edges();
+
+ /// <summary>
+ /// Add a(n isolated) vertex to the graph Ignore if vertex is already in the graph.
+ /// </summary>
+ /// <param name="vertex"></param>
+ /// <returns>True if the vertex was added.</returns>
+ bool AddVertex(V vertex);
+
+ /// <summary>
+ /// Add an edge to the graph. If the edge is already in the graph, update the
+ /// edge data. Add vertices as needed.
+ /// </summary>
+ /// <param name="start"></param>
+ /// <param name="end"></param>
+ /// <param name="edgedata"></param>
+ /// <returns>True if the edge was added</returns>
+ bool AddEdge(V start, V end, E edgedata);
+
+ /// <summary>
+ /// Remove a vertex and all its incident edges from the graph.
+ /// </summary>
+ /// <returns>True if the vertex was already in the graph and hence was removed</returns>
+ bool RemoveVertex(V vertex);
+
+ /// <summary>
+ /// Remove an edge from the graph. Do not remove the vertices if they become isolated.
+ /// </summary>
+ /// <param name="start"></param>
+ /// <param name="end"></param>
+ /// <param name="edgedata">On output, the edge data associated with the removed edge.</param>
+ /// <returns>True if </returns>
+ bool RemoveEdge(V start, V end, out E edgedata);
+
+ /// <summary>
+ /// Is there an edge from start to end in this graph, and if so, what is
+ /// the data on that edge.
+ /// </summary>
+ /// <param name="start"></param>
+ /// <param name="end"></param>
+ /// <param name="edge"></param>
+ /// <returns></returns>
+ bool FindEdge(V start, V end, out E edge);
+
+ /// <summary>
+ /// Construct the subgraph corresponding to a set of vertices.
+ /// </summary>
+ /// <param name="vs"></param>
+ /// <returns></returns>
+ IGraph<V, E, W> SubGraph(ICollectionValue<V> vs);
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>True if graph is connected</value>
+ bool IsConnected { get; }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <value>The number of connected components of this graph</value>
+ int ComponentCount { get;}
+
+ /// <summary>
+ /// Compute the connnected components of this graph.
+ /// </summary>
+ /// <returns>A collection of (vertex,component) pairs, where the first part of the
+ /// pair is some vertex in the component.</returns>
+ ICollectionValue<KeyValuePair<V, IGraph<V, E, W>>> Components();
+
+ /// <summary>
+ /// Traverse the connected component containing the <code>start</code> vertex,
+ /// in either BFS or DFS order, beginning at <code>start</code> and performing the action
+ /// <code>act</code> on each edge part of the constructed tree.
+ /// </summary>
+ /// <param name="bfs">True if BFS, false if DFS</param>
+ /// <param name="start">The vertex to start at</param>
+ /// <param name="act">The action to perform at each node</param>
+ void TraverseVertices(bool bfs, V start, Action<Edge<V, E>> act);
+
+ /// <summary>
+ /// Traverse an undirected graph in either BFS or DFS order, performing the action
+ /// <code>act</code> on each vertex.
+ /// The start vertex of each component of the graph is undefinded.
+ /// </summary>
+ /// <param name="bfs">True if BFS, false if DFS</param>
+ /// <param name="act"></param>
+ void TraverseVertices(bool bfs, Action<V> act);
+
+ /// <summary>
+ /// Traverse an undirected graph in either BFS or DFS order, performing the action
+ /// <code>act</code> on each edge in the traversal and beforecomponent/aftercomponent
+ /// at the start and end of each component (with argument: the start vertex of the component).
+ /// </summary>
+ /// <param name="bfs">True if BFS, false if DFS</param>
+ /// <param name="act"></param>
+ /// <param name="beforecomponent"></param>
+ /// <param name="aftercomponent"></param>
+ void TraverseVertices(bool bfs, Action<Edge<V, E>> act, Action<V> beforecomponent, Action<V> aftercomponent);
+
+ /// <summary>
+ /// A more advanced Depth First Search traversal.
+ /// </summary>
+ /// <param name="start">The vertex to start the search at</param>
+ /// <param name="beforevertex">Action to perform when a vertex is first encountered.</param>
+ /// <param name="aftervertex">Action to perform when all edges out of a vertex has been handles.</param>
+ /// <param name="onfollow">Action to perform as an edge is traversed.</param>
+ /// <param name="onfollowed">Action to perform when an edge is travesed back.</param>
+ /// <param name="onnotfollowed">Action to perform when an edge (a backedge)is seen, but not followed.</param>
+ void DepthFirstSearch(V start, Action<V> beforevertex, Action<V> aftervertex,
+ Action<Edge<V, E>> onfollow, Action<Edge<V, E>> onfollowed, Action<Edge<V, E>> onnotfollowed);
+
+ //TODO: perhaps we should avoid exporting this?
+ /// <summary>
+ /// Traverse the part of the graph reachable from start in order of least distance
+ /// from start according to the weight function. Perform act on the edges of the
+ /// traversal as they are recognised.
+ /// </summary>
+ /// <typeparam name="W"></typeparam>
+ /// <param name="weight"></param>
+ /// <param name="start"></param>
+ /// <param name="act"></param>
+ void PriorityFirstTraverse(bool accumulating, V start, EdgeAction<V, E, W> act);
+
+ /// <summary>
+ /// Compute the (a) shortest path from start to end. THrow an exception if end cannot be reached rom start.
+ /// </summary>
+ /// <param name="weight"></param>
+ /// <param name="start"></param>
+ /// <param name="end"></param>
+ /// <returns></returns>
+ ICollectionValue<Edge<V, E>> ShortestPath(V start, V end);
+
+ /// <summary>
+ /// Compute the Distance from start to end, i.e. the total weight of a shortest path from start to end.
+ /// Throw an exception if end cannot be reached rom start.
+ /// </summary>
+ /// <param name="start"></param>
+ /// <param name="end"></param>
+ /// <returns></returns>
+ W Distance(V start, V end);
+
+ /// <summary>
+ /// Compute a minimum spanning tree for the graph.
+ /// Throw an exception if this graph is not connected.
+ /// </summary>
+ /// <param name="root">(The starting point of the PFS, to be removed)</param>
+ /// <returns></returns>
+ IGraph<V, E, W> MinimumSpanningTree(out V root);
+
+ /// <summary>
+ /// Compute a factor 2 approximation to a Minimum Weight
+ /// Perfect Matching in a graph using NNs
+ /// </summary>
+ /// <returns></returns>
+ ICollectionValue<Edge<V, E>> ApproximateMWPM();
+
+ /// <summary>
+ /// Construct a closed Euler tour of this graph if one exists, i.e. if
+ /// the graph is connected and all vertices have even degrees. Throw an
+ /// ArgumentException if no closed Euler tour exists.
+ /// </summary>
+ /// <returns>A list of vertices in an Euler tour of this graph.</returns>
+ IList<V> EulerTour();
+
+ /// <summary>
+ /// This is intended for implementations of the very simple factor 2 approximation
+ /// algorithms for the travelling salesman problem for Euclidic weight/distance
+ /// functions, i.e. distances that satisfy the triangle inequality. (We do not do 3/2)
+ /// </summary>
+ /// <returns></returns>
+ IDirectedCollectionValue<V> ApproximateTSP();
+
+ /// <summary>
+ /// Pretty-print the graph to the console (for debugging purposes).
+ /// </summary>
+ void Print(System.IO.TextWriter output);
+ }
+
+/// <summary>
+/// The type of an edge in a graph. An edge is identified by its pair of
+/// vertices. The pair is considered ordered, and so an Edge really describes
+/// an edge of the graph in a particular traversal direction.
+/// </summary>
+/// <typeparam name="V">The type of a vertex.</typeparam>
+/// <typeparam name="E">The type of data asociated with edges.</typeparam>
+ struct Edge<V, E>
+ {
+ static SCG.IEqualityComparer<V> vequalityComparer = EqualityComparer<V>.Default;
+ public readonly V start, end;
+ public readonly E edgedata;
+ public Edge(V start, V end, E edgedata)
+ {
+ if (vequalityComparer.Equals(start, end))
+ throw new ArgumentException("Illegal: start and end are equal");
+ this.start = start; this.end = end; this.edgedata = edgedata;
+ }
+
+ public Edge<V, E> Reverse()
+ {
+ return new Edge<V, E>(end, start, edgedata);
+ }
+
+ public override string ToString()
+ {
+ return String.Format("(start='{0}', end='{1}', edgedata='{2}')", start, end, edgedata); ;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Edge<V, E>)
+ {
+ Edge<V, E> other = (Edge<V, E>)obj;
+ return vequalityComparer.Equals(start, other.start) && vequalityComparer.Equals(end, other.end);
+ }
+ return false;
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public override int GetHashCode()
+ {
+ //TODO: should we use xor? Or a random factor?
+ return start.GetHashCode() + 148712671 * end.GetHashCode();
+ }
+
+ /// <summary>
+ /// The unordered equalityComparer compares edges independent of the order of the vertices.
+ /// </summary>
+ public class UnorderedEqualityComparer : SCG.IEqualityComparer<Edge<V, E>>
+ {
+ /// <summary>
+ /// Check if two edges have the same vertices irrespective of order.
+ /// </summary>
+ /// <param name="i1"></param>
+ /// <param name="i2"></param>
+ /// <returns></returns>
+ public bool Equals(Edge<V, E> i1, Edge<V, E> i2)
+ {
+ return (vequalityComparer.Equals(i1.start, i2.start) && vequalityComparer.Equals(i1.end, i2.end)) ||
+ (vequalityComparer.Equals(i1.end, i2.start) && vequalityComparer.Equals(i1.start, i2.end));
+ }
+
+ /// <summary>
+ /// Return a hash code compatible with the unordered equals.
+ /// </summary>
+ /// <param name="item"></param>
+ /// <returns></returns>
+ public int GetHashCode(Edge<V, E> item)
+ {
+ return item.start.GetHashCode() ^ item.end.GetHashCode();
+ }
+ }
+ }
+
+/// <summary>
+/// The type of the weight object of a graph. This consists of a function mapping
+/// edge data values to weight values, and an operation to add two weight values.
+/// It is required that weight values are comparable.
+///
+/// The user must assure that the add operation is commutative and fulfills
+/// Add(w1,w2) &le; w1 for all w1 and w2 that can appear as weights or sums of
+/// weights. In practise, W will be int or double, all weight values will be
+/// non-negative and the addition will be the natural addition on W.
+/// </summary>
+/// <typeparam name="E"></typeparam>
+/// <typeparam name="W"></typeparam>
+ interface IWeight<E, W> where W : IComparable<W>
+ {
+ /// <summary>
+ /// Compute the weight value corresponding to specific edge data.
+ /// </summary>
+ /// <param name="edgedata"></param>
+ /// <returns></returns>
+ W Weight(E edgedata);
+
+ /// <summary>
+ /// Add two weight values.
+ /// </summary>
+ /// <param name="w1"></param>
+ /// <param name="w2"></param>
+ /// <returns></returns>
+ W Add(W w1, W w2);
+ }
+
+/// <summary>
+/// An action to perform when an edge is encountered during a traversal of the graph.
+/// The "extra" parameter is for additional information supplied by the traversal
+/// algorithm.
+/// The intention of the bool return value is that returning false is a signal to the
+/// traversal algorithm to abandon the traversl because the user has already found
+/// what he was looking for.
+/// </summary>
+/// <typeparam name="V"></typeparam>
+/// <typeparam name="E"></typeparam>
+/// <typeparam name="U"></typeparam>
+/// <param name="edge"></param>
+/// <param name="extra"></param>
+/// <returns></returns>
+ delegate bool EdgeAction<V, E, U>(Edge<V, E> edge, U extra);
+
+
+/*
+ For a dense graph, we would use data fields:
+
+ E'[,] or E'[][] for the matrix. Possibly E'[][] for a triangular one!
+ Here E' = struct{E edgedata, bool present} or class{E edgedata}, or if E is a class just E.
+ Thus E' is E! for value types. Or we could have two matrices: E[][] and bool[][].
+
+ HashDictionary<V,int> to map vertex ids to indices.
+ ArrayList<V> for the map the other way.
+ Or simply a HashedArrayList<V> to get both?
+
+ PresentList<int>, FreeList<int> or similar, if we do not want to compact the indices in the matrix on each delete.
+ If we compact, we always do a delete on the vertex<->index map by a replace and a removelast:
+ vimap[ind]=vimap[vimap.Count]; vimap.RemoveLast(); //also reorder matrix!
+
+
+*/
+
+/// <summary>
+/// An implementation of IGraph&le;V,E,W&ge; based on an adjacency list representation using hash dictionaries.
+/// As a consequence, this will be most efficient for sparse graphs.
+/// </summary>
+/// <typeparam name="V"></typeparam>
+/// <typeparam name="E"></typeparam>
+/// <typeparam name="W"></typeparam>
+ class HashGraph<V, E, W> : IGraph<V, E, W> where W : IComparable<W>
+ {
+ int edgecount;
+
+ HashDictionary<V, HashDictionary<V, E>> graph;
+
+ IWeight<E, W> weight;
+
+ public IWeight<E, W> Weight { get { return weight; } }
+
+
+ /// <summary>
+ /// Create an initially empty graph.
+ /// </summary>
+ /// <param name="weight"></param>
+ [UsedBy("testTSP")]
+ public HashGraph(IWeight<E, W> weight)
+ {
+ this.weight = weight;
+ edgecount = 0;
+ graph = new HashDictionary<V, HashDictionary<V, E>>();
+ }
+
+ /// <summary>
+ /// Constructing a graph with no isolated vertices given a collection of edges.
+ /// </summary>
+ /// <param name="edges"></param>
+ [UsedBy()]
+ public HashGraph(IWeight<E, W> weight, SCG.IEnumerable<Edge<V, E>> edges) : this(weight)
+ {
+ foreach (Edge<V, E> edge in edges)
+ {
+ if (edge.start.Equals(edge.end))
+ throw new ApplicationException("Edge has equal start and end");
+ {
+ HashDictionary<V, E> edgeset;
+ //TODO: utilize upcoming FindOrAddSome operation
+ if (!graph.Find(edge.start, out edgeset))
+ graph.Add(edge.start, edgeset = new HashDictionary<V, E>());
+ if (!edgeset.UpdateOrAdd(edge.end, edge.edgedata))
+ edgecount++;
+ if (!graph.Find(edge.end, out edgeset))
+ graph.Add(edge.end, edgeset = new HashDictionary<V, E>());
+ edgeset.UpdateOrAdd(edge.start, edge.edgedata);
+ }
+ }
+ }
+
+ /// <summary>
+ /// This constructs a graph with a given set of vertices.
+ /// Will only allow these vertices.
+ /// Duplicate edges are allowed.
+ /// </summary>
+ /// <param name="vertices"></param>
+ /// <param name="edges"></param>
+ public HashGraph(IWeight<E, W> weight, SCG.IEnumerable<V> vertices, SCG.IEnumerable<Edge<V, E>> edges) : this(weight)
+ {
+ foreach (V v in vertices)
+ graph.Add(v, new HashDictionary<V, E>());
+ foreach (Edge<V, E> edge in edges)
+ {
+ HashDictionary<V, E> edgeset;
+ if (edge.start.Equals(edge.end))
+ throw new ApplicationException("Edge has equal start and end");
+ if (!graph.Find(edge.start, out edgeset))
+ throw new ApplicationException("Edge has unknown start");
+ if (!edgeset.UpdateOrAdd(edge.end, edge.edgedata))
+ edgecount++;
+ if (!graph.Find(edge.end, out edgeset))
+ throw new ApplicationException("Edge has unknown end");
+ edgeset.UpdateOrAdd(edge.start, edge.edgedata);
+ }
+ }
+
+ [UsedBy("testCOMP")]
+ public int VertexCount { get { return graph.Count; } }
+
+ [UsedBy("testCOMP")]
+ public int EdgeCount { get { return edgecount; } }
+
+ public ICollectionValue<V> Vertices()
+ {
+ return new GuardedCollectionValue<V>(graph.Keys);
+ }
+
+ public ICollectionValue<KeyValuePair<V, E>> Adjacent(V vertex)
+ {
+ return new GuardedCollectionValue<KeyValuePair<V, E>>(graph[vertex]);
+ }
+
+ class EdgesValue : CollectionValueBase<Edge<V, E>>
+ {
+ HashGraph<V, E, W> graph;
+ internal EdgesValue(HashGraph<V, E, W> g) { graph = g; }
+
+ public override bool IsEmpty { get { return graph.edgecount == 0; } }
+
+ public override int Count { get { return graph.edgecount; } }
+
+ public override Speed CountSpeed { get { return Speed.Constant; } }
+
+
+ public override Edge<V, E> Choose()
+ {
+ KeyValuePair<V, HashDictionary<V, E>> adjacent = graph.graph.Choose();
+ KeyValuePair<V, E> otherend = graph.graph[adjacent.Key].Choose();
+ return new Edge<V, E>(adjacent.Key, otherend.Key, otherend.Value);
+ }
+
+ public override SCG.IEnumerator<Edge<V, E>> GetEnumerator()
+ {
+ HashSet<Edge<V, E>> seen = new HashSet<Edge<V, E>>(new Edge<V, E>.UnorderedEqualityComparer());
+ foreach (V v in graph.graph.Keys)
+ foreach (KeyValuePair<V, E> p in graph.graph[v])
+ {
+ Edge<V, E> edge = new Edge<V, E>(v, p.Key, p.Value);
+ if (!seen.FindOrAdd(ref edge))
+ yield return edge;
+ }
+ }
+ }
+
+ public ICollectionValue<Edge<V, E>> Edges()
+ {
+ return new EdgesValue(this);
+ }
+
+ public bool AddVertex(V v)
+ {
+ if (graph.Contains(v))
+ return false;
+ graph.Add(v, new HashDictionary<V, E>());
+ return true;
+ }
+
+ //Note: no warning on update of edgedata!
+ //TODO: Shouldn´t Update or Add return the old value?
+ //Then it would be easy to check for updates
+ public bool AddEdge(V start, V end, E edgedata)
+ {
+ bool retval = false;
+ HashDictionary<V, E> edgeset;
+ if (graph.Find(start, out edgeset))
+ retval = !edgeset.UpdateOrAdd(end, edgedata);
+ else
+ {
+ graph[start] = edgeset = new HashDictionary<V, E>();
+ edgeset[end] = edgedata;
+ retval = true;
+ }
+ if (graph.Find(end, out edgeset))
+ edgeset.UpdateOrAdd(start, edgedata);
+ else
+ {
+ graph[end] = edgeset = new HashDictionary<V, E>();
+ edgeset[start] = edgedata;
+ }
+ if (retval)
+ edgecount++;
+ return retval;
+ }
+
+ public bool RemoveVertex(V vertex)
+ {
+ HashDictionary<V, E> edgeset;
+ if (!graph.Find(vertex, out edgeset))
+ return false;
+ foreach (V othervertex in edgeset.Keys)
+ graph[othervertex].Remove(vertex); //Assert retval==true
+ edgecount -= edgeset.Count;
+ graph.Remove(vertex);
+ return true;
+ }
+
+ public bool RemoveEdge(V start, V end, out E edgedata)
+ {
+ HashDictionary<V, E> edgeset;
+ if (!graph.Find(start, out edgeset))
+ {
+ edgedata = default(E);
+ return false;
+ }
+ if (!edgeset.Remove(end, out edgedata))
+ return false;
+ graph[end].Remove(start);
+ edgecount--;
+ return true;
+ }
+
+ public bool FindEdge(V start, V end, out E edgedata)
+ {
+ HashDictionary<V, E> edges;
+ if (!graph.Find(start, out edges))
+ {
+ edgedata = default(E);
+ return false;
+ }
+ return edges.Find(end, out edgedata);
+ }
+
+ public IGraph<V, E, W> SubGraph(ICollectionValue<V> vs)
+ {
+ HashSet<V> vertexset = vs as HashSet<V>;
+ if (vertexset == null)
+ {
+ vertexset = new HashSet<V>();
+ vertexset.AddAll(vs);
+ }
+
+ return new HashGraph<V, E, W>(weight,
+ vs,
+ Edges().Filter(delegate(Edge<V, E> e) { return vertexset.Contains(e.start) && vertexset.Contains(e.end); }));
+ }
+
+ public bool IsConnected
+ {
+ //TODO: optimize: needs to change Action<Edge<V,E>> to EdgeAction to be able to break out
+ get { return ComponentCount <= 1; }
+ }
+
+ public int ComponentCount
+ {
+ get
+ {
+ int components = 0;
+ TraverseVertices(false, null, delegate(V v) { components++; }, null);
+ return components;
+ }
+ }
+
+ public ICollectionValue<KeyValuePair<V, IGraph<V, E, W>>> Components()
+ {
+ ArrayList<KeyValuePair<V, IGraph<V, E, W>>> retval = new ArrayList<KeyValuePair<V, IGraph<V, E, W>>>();
+ HashGraph<V, E, W> component;
+ ArrayList<V> vertices = null;
+ Action<Edge<V, E>> edgeaction = delegate(Edge<V, E> e)
+ {
+ vertices.Add(e.end);
+ };
+ Action<V> beforecomponent = delegate(V v)
+ {
+ vertices = new ArrayList<V>();
+ vertices.Add(v);
+ };
+ Action<V> aftercomponent = delegate(V v)
+ {
+ //component = SubGraph(vertices);
+ component = new HashGraph<V, E, W>(weight);
+ foreach (V start in vertices)
+ {
+ //component.graph[start] = graph[start].Clone();
+ HashDictionary<V, E> edgeset = component.graph[start] = new HashDictionary<V, E>();
+ foreach (KeyValuePair<V, E> adjacent in graph[start])
+ edgeset[adjacent.Key] = adjacent.Value;
+ }
+ retval.Add(new KeyValuePair<V, IGraph<V, E, W>>(v, component));
+ };
+ TraverseVertices(false, edgeaction, beforecomponent, aftercomponent);
+ return retval;
+ }
+
+ [UsedBy("test1")]
+ public void TraverseVertices(bool bfs, V start, Action<Edge<V, E>> act)
+ {
+ if (!graph.Contains(start))
+ throw new ArgumentException("start Vertex not in graph");
+ IList<Edge<V, E>> todo = new LinkedList<Edge<V, E>>();
+ todo.FIFO = bfs;
+ HashSet<V> seen = new HashSet<V>();
+ V v;
+ while (!todo.IsEmpty || seen.Count == 0)
+ {
+ if (seen.Count > 1)
+ {
+ Edge<V, E> e = todo.Remove();
+ if (act != null)
+ act(e);
+ v = e.end;
+ }
+ else
+ {
+ seen.Add(start);
+ v = start;
+ }
+
+ HashDictionary<V, E> adjacent;
+ if (graph.Find(v, out adjacent))
+ {
+ foreach (KeyValuePair<V, E> p in adjacent)
+ {
+ V end = p.Key;
+ if (!seen.FindOrAdd(ref end))
+ todo.Add(new Edge<V, E>(v, end, p.Value));
+ }
+ }
+ }
+ }
+
+ public void TraverseVertices(bool bfs, Action<V> act)
+ {
+ TraverseVertices(bfs, delegate(Edge<V, E> e) { act(e.end); }, act, null);
+ }
+
+ //TODO: merge the hash set here with the intra omponent one?
+ public void TraverseVertices(bool bfs, Action<Edge<V, E>> act, Action<V> beforecomponent, Action<V> aftercomponent)
+ {
+ HashSet<V> missing = new HashSet<V>();
+ missing.AddAll(Vertices());
+ Action<Edge<V, E>> myact = act + delegate(Edge<V, E> e) { missing.Remove(e.end); };
+ Action<V> mybeforecomponent = beforecomponent + delegate(V v) { missing.Remove(v); };
+ while (!missing.IsEmpty)
+ {
+ V start = default(V);
+ foreach (V v in missing)
+ { start = v; break; }
+ mybeforecomponent(start);
+ TraverseVertices(bfs, start, myact);
+ if (aftercomponent != null)
+ aftercomponent(start);
+ }
+ }
+
+ delegate void Visitor(V v, V parent, bool atRoot);
+
+ //TODO: allow actions to be null
+ [UsedBy("testDFS")]
+ public void DepthFirstSearch(V start, Action<V> before, Action<V> after,
+ Action<Edge<V, E>> onfollow, Action<Edge<V, E>> onfollowed, Action<Edge<V, E>> onnotfollowed)
+ {
+ HashSet<V> seen = new HashSet<V>();
+ seen.Add(start);
+ //If we do not first set visit = null, the compiler will complain at visit(end)
+ //that visit is uninitialized
+ Visitor visit = null;
+ visit = delegate(V v, V parent, bool atRoot)
+ {
+ before(v);
+ HashDictionary<V, E> adjacent;
+ if (graph.Find(v, out adjacent))
+ foreach (KeyValuePair<V, E> p in adjacent)
+ {
+ V end = p.Key;
+ Edge<V, E> e = new Edge<V, E>(v, end, p.Value);
+ if (!seen.FindOrAdd(ref end))
+ {
+ onfollow(e);
+ visit(end, v, false);
+ onfollowed(e);
+ }
+ else
+ {
+ if (!atRoot && !parent.Equals(end))
+ onnotfollowed(e);
+ }
+ }
+ after(v);
+ };
+ visit(start, default(V), true);
+ }
+
+ public void PriorityFirstTraverse(bool accumulated, V start, EdgeAction<V, E, W> act)
+ {
+ if (!graph.Contains(start))
+ throw new ArgumentException("Graph does not contain start");
+ IPriorityQueue<W> fringe = new IntervalHeap<W>();
+ HashDictionary<V, IPriorityQueueHandle<W>> seen = new HashDictionary<V, IPriorityQueueHandle<W>>();
+ HashDictionary<IPriorityQueueHandle<W>, Edge<V, E>> bestedge = new HashDictionary<IPriorityQueueHandle<W>, Edge<V, E>>();
+
+ IPriorityQueueHandle<W> h = null;
+ V current;
+ W currentdist;
+ while (!fringe.IsEmpty || seen.Count == 0)
+ {
+ if (seen.Count == 0)
+ {
+ seen.Add(start, h);
+ current = start;
+ currentdist = default(W);
+ }
+ else
+ {
+ currentdist = fringe.DeleteMin(out h);
+ Edge<V, E> e = bestedge[h];
+ if (!act(e, currentdist))
+ break;
+ bestedge.Remove(h);
+ current = e.end;
+ }
+ HashDictionary<V, E> adjacentnodes;
+ if (graph.Find(current, out adjacentnodes))
+ foreach (KeyValuePair<V, E> adjacent in adjacentnodes)
+ {
+ V end = adjacent.Key;
+ E edgedata = adjacent.Value;
+ W dist = weight.Weight(edgedata), olddist;
+ if (accumulated && !current.Equals(start)) dist = weight.Add(currentdist, weight.Weight(edgedata));
+ if (!seen.Find(end, out h))
+ {
+ h = null;
+ fringe.Add(ref h, dist);
+ seen[end] = h;
+ bestedge[h] = new Edge<V, E>(current, end, edgedata);
+ }
+ else if (fringe.Find(h, out olddist) && dist.CompareTo(olddist) < 0)
+ {
+ fringe[h] = dist;
+ bestedge[h] = new Edge<V, E>(current, end, edgedata);
+ }
+ }
+ }
+ }
+
+ public W Distance(V start, V end)
+ {
+ W dist = default(W);
+ bool found = false;
+ PriorityFirstTraverse(true, start, delegate(Edge<V, E> e, W w)
+ {
+ if (end.Equals(e.end)) { dist = w; found = true; return false; }
+ else return true;
+ });
+ if (found)
+ return dist;
+ throw new ArgumentException(String.Format("No path from {0} to {1}", start, end));
+ }
+
+
+ public ICollectionValue<Edge<V, E>> ShortestPath(V start, V end)
+ {
+ HashDictionary<V, Edge<V, E>> backtrack = new HashDictionary<V, Edge<V, E>>();
+ PriorityFirstTraverse(true, start, delegate(Edge<V, E> e, W w) { backtrack[e.end] = e; return !end.Equals(e.end); });
+ ArrayList<Edge<V, E>> path = new ArrayList<Edge<V, E>>();
+ Edge<V, E> edge;
+ V v = end;
+ while (backtrack.Find(v, out edge))
+ {
+ path.Add(edge);
+ v = edge.start;
+ }
+ if (path.IsEmpty)
+ throw new ArgumentException(String.Format("No path from {0} to {1}", start, end));
+ path.Reverse();
+ return path;
+ }
+
+ /// <summary>
+ /// NB: assume connected, throw exception if not
+ /// </summary>
+ /// <typeparam name="W"></typeparam>
+ /// <param name="edgeWeight"></param>
+ /// <returns></returns>
+ public IGraph<V, E, W> MinimumSpanningTree(out V start)
+ {
+ ArrayList<Edge<V, E>> edges = new ArrayList<Edge<V, E>>();
+ start = default(V);
+ foreach (V v in graph.Keys)
+ { start = v; break; }
+ PriorityFirstTraverse(false, start, delegate(Edge<V, E> e, W w) { edges.Add(e); return true; });
+ if (edges.Count != graph.Count - 1)
+ throw new ArgumentException("Graph not connected");
+ return new HashGraph<V, E, W>(weight, edges);
+ }
+
+ public ICollectionValue<Edge<V, E>> ApproximateMWPM()
+ {
+ //Assume graph complete and even number of vertices
+ HashGraph<V, E, W> clone = new HashGraph<V, E, W>(weight, Edges());
+ ArrayList<Edge<V, E>> evenpath = new ArrayList<Edge<V, E>>();
+ ArrayList<Edge<V, E>> oddpath = new ArrayList<Edge<V, E>>();
+ V start = default(V);
+ foreach (V v in clone.Vertices()) { start = v; break; }
+ V current = start;
+ W evenweight, oddweight;
+ evenweight = oddweight = default(W);
+ bool even = true;
+ while (clone.VertexCount > 0)
+ {
+ V bestvertex = default(V);
+ E bestedge = default(E);
+ W bestweight = default(W);
+ if (clone.VertexCount == 1)
+ {
+ bestvertex = start;
+ bestedge = graph[current][start];
+ bestweight = weight.Weight(bestedge);
+ }
+ else
+ {
+ bool first = true;
+ foreach (KeyValuePair<V, E> p in clone.graph[current])
+ {
+ W thisweight = weight.Weight(p.Value);
+ if (first || bestweight.CompareTo(thisweight) > 0)
+ {
+ bestvertex = p.Key;
+ bestweight = thisweight;
+ bestedge = p.Value;
+ }
+ first = false;
+ }
+ }
+ clone.RemoveVertex(current);
+ //Console.WriteLine("-* {0} / {1} / {2}", bestvertex, bestweight, tour.Count);
+ if (even)
+ {
+ evenweight = evenpath.Count < 1 ? bestweight : weight.Add(evenweight, bestweight);
+ evenpath.Add(new Edge<V, E>(current, bestvertex, bestedge));
+ }
+ else
+ {
+ oddweight = oddpath.Count < 1 ? bestweight : weight.Add(oddweight, bestweight);
+ oddpath.Add(new Edge<V, E>(current, bestvertex, bestedge));
+ }
+ current = bestvertex;
+ even = !even;
+ }
+ //Console.WriteLine("Totalweights: even: {0} and odd: {1}", evenweight, oddweight);
+ return evenweight.CompareTo(oddweight) < 0 ? evenpath : oddpath;
+ }
+
+ /// <summary>
+ /// The construction is performed as follows:
+ /// Start at some vertex. Greedily construct a path starting there by
+ /// following edges at random until no more unused edges are available
+ /// from the current node, which must be the start node. Then follow
+ /// the path constructed so far and whenever we meet a vertex with
+ /// unused edges, construct a path from there greedily as above,
+ /// inserting into the path in front of us.
+ ///
+ /// The algorithm will use constant time for each vertex added
+ /// to the path and
+ ///
+ /// Illustrates use of views as a safe version of listnode pointers
+ /// and hashed linked lists for choosing some item in constant time combined
+ /// with (expected) constant time remove.
+ /// </summary>
+ /// <returns></returns>
+ public IList<V> EulerTour()
+ {
+ bool debug = false;
+ //Assert connected and all degrees even. (Connected is checked at the end)
+ string fmt = "Graph does not have a closed Euler tour: vertex {0} has odd degree {1}";
+ foreach (KeyValuePair<V, HashDictionary<V, E>> adj in graph)
+ if (adj.Value.Count % 2 != 0)
+ throw new ArgumentException(String.Format(fmt, adj.Key, adj.Value.Count));
+
+ LinkedList<V> path = new LinkedList<V>();
+ //Clone the graph data to keep track of used edges.
+ HashDictionary<V, HashedArrayList<V>> edges = new HashDictionary<V, HashedArrayList<V>>();
+ V start = default(V);
+ HashedArrayList<V> adjacent = null;
+ foreach (KeyValuePair<V, HashDictionary<V, E>> p in graph)
+ {
+ adjacent = new HashedArrayList<V>();
+ adjacent.AddAll(p.Value.Keys);
+ start = p.Key;
+ edges.Add(start, adjacent);
+ }
+
+ path.Add(start);
+ IList<V> view = path.View(0, 1);
+ while (adjacent.Count > 0)
+ {
+ V current = view[0];
+ if (debug) Console.WriteLine("==> {0}", current);
+ //Augment the path (randomly) until we return here and all edges
+ while (adjacent.Count > 0)
+ {
+ if (debug) Console.WriteLine(" => {0}, {1}", current, path.Count);
+ V next = adjacent.RemoveFirst();
+ view.Add(next);
+ if (debug) Console.WriteLine("EDGE: " + current + "->" + next);
+ if (!edges[next].Remove(current))
+ Console.WriteLine("Bad");
+ current = next;
+ adjacent = edges[current];
+ }
+ //When we get here, the view contains a closed path, i.e.
+ //view[view.Count-1] == view[0] and we have followed all edges from view[0]
+ //We slide forward along the rest of the path constructed so far and stop at the
+ //first vertex with still unfollwed edges.
+ while (view.Offset < path.Count - 1 && adjacent.Count == 0)
+ {
+ view.Slide(1, 1);
+ if (debug) Console.WriteLine(" -> {0}, {1}", view[0], path.Count);
+ adjacent = edges[view[0]];
+ }
+ }
+ if (path.Count <= edges.Count)
+ throw new ArgumentException("Graph was not connected");
+ return path;
+ }
+
+ /// <summary>
+ /// The purpose of this struct is to be able to create and add new,
+ /// synthetic vertices to a graph.
+ /// </summary>
+ struct Vplus : IEquatable<Vplus>
+ {
+ internal readonly V vertex; internal readonly int id;
+ static SCG.IEqualityComparer<V> vequalityComparer = EqualityComparer<V>.Default;
+ internal Vplus(V v) { vertex = v; id = 0; }
+ internal Vplus(int i) { vertex = default(V); id = i; }
+ //We should override Equals and GetHashCode
+
+ public override string ToString()
+ { return id == 0 ? String.Format("real({0})", vertex) : String.Format("fake({0})", id); }
+
+ public override bool Equals(object obj) { throw new NotImplementedException(); }
+
+ public bool Equals(Vplus other) { return vequalityComparer.Equals(vertex, other.vertex) && id == other.id; }
+
+ public override int GetHashCode() { return vequalityComparer.GetHashCode(vertex) + id; }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <returns></returns>
+ public IDirectedCollectionValue<V> ApproximateTSP2()
+ {
+ /* Construct a minimum spanning tree for the graph */
+ V root;
+ IGraph<V, E, W> tree = MinimumSpanningTree(out root);
+
+ //Console.WriteLine("========= Matching of odd vertices of mst =========");
+ ArrayList<V> oddvertices = new ArrayList<V>();
+ foreach (V v in tree.Vertices())
+ if (tree.Adjacent(v).Count % 2 != 0)
+ oddvertices.Add(v);
+
+ ICollectionValue<Edge<V, E>> matching = SubGraph(oddvertices).ApproximateMWPM();
+
+ //Console.WriteLine("========= Fuse matching and tree =========");
+ //We must split the edges of the matching with fake temporary vertices
+ //since the matching and the tree may have common edges
+
+ HashGraph<Vplus, E, W> fused = new HashGraph<Vplus, E, W>(weight);
+ foreach (Edge<V, E> e in tree.Edges())
+ fused.AddEdge(new Vplus(e.start), new Vplus(e.end), e.edgedata);
+ int fakeid = 1;
+ foreach (Edge<V, E> e in matching)
+ {
+ Vplus fakevertex = new Vplus(fakeid++);
+ fused.AddEdge(new Vplus(e.start), fakevertex, e.edgedata);
+ fused.AddEdge(fakevertex, new Vplus(e.end), e.edgedata);
+ }
+ fused.Print(Console.Out);
+
+ //Console.WriteLine("========= Remove fake vertices and perform shortcuts =========");
+ IList<Vplus> fusedtour = fused.EulerTour();
+ HashSet<V> seen = new HashSet<V>();
+ IList<V> tour = new ArrayList<V>();
+
+ foreach (Vplus vplus in fused.EulerTour())
+ {
+ V v = vplus.vertex;
+ if (vplus.id == 0 && !seen.FindOrAdd(ref v))
+ tour.Add(v);
+ }
+ return tour;
+ }
+
+ /// <summary>
+ /// (Refer to the litterature, Vazirani)
+ ///
+ /// (Describe: MST+Euler+shortcuts)
+ /// </summary>
+ /// <returns></returns>
+ [UsedBy("testTSP")]
+ public IDirectedCollectionValue<V> ApproximateTSP()
+ {
+ /* Construct a minimum spanning tree for the graph */
+ V root;
+ IGraph<V, E, W> tree = MinimumSpanningTree(out root);
+
+ /* (Virtually) double all edges of MST and construct an Euler tour of the vertices*/
+ LinkedList<V> tour = new LinkedList<V>();
+ tour.Add(root);
+ tour.Add(root);
+ IList<V> view = tour.View(1, 1);
+
+ Action<Edge<V, E>> onfollow = delegate(Edge<V, E> e)
+ {
+ //slide the view until it points to the last copy of e.start
+ while (!view[0].Equals(e.start))
+ view.Slide(1);
+ //then insert two copies of e.end and slide the view one backwards
+ view.InsertFirst(e.end);
+ view.InsertFirst(e.end);
+ view.Slide(1, 1);
+ };
+
+ tree.TraverseVertices(false, root, onfollow);
+
+ /* Finally, slide along the Euler tour and shortcut by removing vertices already seen*/
+ HashSet<V> seen = new HashSet<V>();
+ view = tour.View(0, tour.Count);
+ while (view.Offset < tour.Count - 1)
+ {
+ V v = view[0];
+ if (seen.FindOrAdd(ref v))
+ view.RemoveFirst();
+ else
+ view.Slide(1, view.Count - 1);
+ }
+ return tour;
+ }
+
+ public void Print(System.IO.TextWriter output)
+ {
+ output.WriteLine("Graph has {0} vertices, {1} edges, {2} components", graph.Count, edgecount, ComponentCount);
+ foreach (KeyValuePair<V, HashDictionary<V, E>> p in graph)
+ {
+ output.Write(" {0} -> ", p.Key);
+ foreach (KeyValuePair<V, E> p2 in p.Value)
+ output.Write("{1} (data {2}), ", p.Key, p2.Key, p2.Value);
+ output.WriteLine();
+ }
+ }
+ }
+
+/// <summary>
+/// A weight on a graph that assigns the weight 1 to every edge.
+/// </summary>
+/// <typeparam name="E">(Ignored) type of edgedata</typeparam>
+ class CountWeight<E> : IWeight<E, int>
+ {
+ public int Weight(E edgedata) { return 1; }
+
+ public int Add(int w1, int w2) { return w1 + w2; }
+ }
+
+/// <summary>
+/// A weight on an IGraph&lt;V,int&gt; that uses the value of the edgedata as the weight value.
+/// </summary>
+ class IntWeight : IWeight<int, int>
+ {
+
+ public int Weight(int edgedata) { return edgedata; }
+
+ public int Add(int w1, int w2) { return w1 + w2; }
+
+ }
+
+/// <summary>
+/// A weight on an IGraph&lt;V,double&gt; that uses the value of the edgedata as the weight value.
+/// </summary>
+ class DoubleWeight : IWeight<double, double>
+ {
+
+ public double Weight(double edgedata) { return edgedata; }
+
+ public double Add(double w1, double w2) { return w1 + w2; }
+
+ }
+
+/// <summary>
+/// Attribute used for marking which examples use a particuler graph method
+/// </summary>
+ class UsedByAttribute : Attribute
+ {
+ string[] tests;
+ internal UsedByAttribute(params string[] tests) { this.tests = tests; }
+
+ public override string ToString()
+ {
+ System.Text.StringBuilder sb = new System.Text.StringBuilder();
+ for (int i = 0; i < tests.Length; i++)
+ {
+ if (i > 0)
+ sb.Append(", ");
+ sb.Append(tests[i]);
+ }
+ return sb.ToString();
+ }
+ }
+
+/// <summary>
+/// Attribute for marking example methods with a description
+/// </summary>
+ class ExampleDescriptionAttribute : Attribute
+ {
+ string text;
+ internal ExampleDescriptionAttribute(string text) { this.text = text; }
+
+ public override string ToString() { return text; }
+ }
+
+/// <summary>
+/// A selection of test cases
+/// </summary>
+ class Test
+ {
+ static SCG.IEnumerable<Edge<int, int>> Grid(int n)
+ {
+ Random ran = new Random(1717);
+ for (int i = 1; i <= n; i++)
+ {
+ for (int j = 1; j <= n; j++)
+ {
+ yield return new Edge<int, int>(1000 * i + j, 1000 * (i + 1) + j, ran.Next(1, 100));
+ yield return new Edge<int, int>(1000 * i + j, 1000 * i + j + 1, ran.Next(1, 100));
+ }
+ }
+ }
+
+ static SCG.IEnumerable<Edge<string, int>> Snake(int n)
+ {
+ for (int i = 1; i <= n; i++)
+ {
+ yield return new Edge<string, int>("U" + i, "L" + i, 1);
+ yield return new Edge<string, int>("U" + i, "U" + (i + 1), i % 2 == 0 ? 1 : 10);
+ yield return new Edge<string, int>("L" + i, "L" + (i + 1), i % 2 == 0 ? 10 : 1);
+ }
+ }
+
+ /// <summary>
+ /// Create the edges of a forest of complete binary trees.
+ /// </summary>
+ /// <param name="treeCount">Number of trees</param>
+ /// <param name="height">Height of trees</param>
+ /// <returns></returns>
+ static SCG.IEnumerable<Edge<string, int>> Forest(int treeCount, int height)
+ {
+ for (int i = 0; i < treeCount; i++)
+ {
+ IList<string> q = new ArrayList<string>();
+ string root = String.Format("[{0}]", i);
+ int lmax = height + root.Length;
+ q.Add(root);
+ while (!q.IsEmpty)
+ {
+ string s = q.Remove();
+ string s2 = s + "L";
+ if (s2.Length < lmax)
+ q.Add(s2);
+ yield return new Edge<string, int>(s, s2, 0);
+ s2 = s + "R";
+ if (s2.Length < lmax)
+ q.Add(s2);
+ yield return new Edge<string, int>(s, s2, 0);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Create edges of a graph correspondingto a "wheel" shape: the ecnter and equidistant
+ /// points around the perimeter. The edgedata and edge weights are the euclidean distances.
+ /// </summary>
+ /// <param name="complete">True means the graph will be complete, false that the graph
+ /// will have edges for the spokes and between neighboring perimeter vetices.</param>
+ /// <param name="n">The number of perimeter vertices, must be at least 3.</param>
+ /// <returns>An enumerable with the edges</returns>
+ static SCG.IEnumerable<Edge<string, double>> Wheel(bool complete, int n)
+ {
+ if (n < 3)
+ throw new ArgumentOutOfRangeException("n must be at least 3");
+ string center = "C";
+ string[] perimeter = new string[n];
+ for (int i = 0; i < n; i++)
+ {
+ perimeter[i] = "P" + i;
+ yield return new Edge<string, double>(perimeter[i], center, 1);
+ }
+ if (complete)
+ for (int i = 0; i < n - 1; i++)
+ for (int j = i + 1; j < n; j++)
+ yield return new Edge<string, double>(perimeter[i], perimeter[j], 2 * Math.Sin((j - i) * Math.PI / n));
+ else
+ {
+ for (int i = 0; i < n - 1; i++)
+ yield return new Edge<string, double>(perimeter[i], perimeter[i + 1], 2 * Math.Sin(Math.PI / n));
+ yield return new Edge<string, double>(perimeter[n - 1], perimeter[0], 2 * Math.Sin(Math.PI / n));
+ }
+ }
+
+
+ /// <summary>
+ /// []
+ /// </summary>
+ [ExampleDescription("Basic BFS and DFS using TraverseVertices method")]
+ static void test1()
+ {
+ IGraph<int, int, int> g = new HashGraph<int, int, int>(new CountWeight<int>(), Grid(3));
+ Console.WriteLine("Edge count: {0}", g.Edges().Count);
+ Console.WriteLine("BFS:");
+ g.TraverseVertices(true, 1001, delegate(Edge<int, int> e) { Console.WriteLine(e); });
+ Console.WriteLine("DFS:");
+ g.TraverseVertices(false, 1001, delegate(Edge<int, int> e) { Console.WriteLine(e); });
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ [ExampleDescription("Component methods")]
+ static void testCOMP()
+ {
+ IGraph<string, int, int> g = new HashGraph<string, int, int>(new CountWeight<int>(), Forest(2, 2));
+ Console.WriteLine("Forest has: Vertices: {0}, Edges: {1}, Components: {2}", g.VertexCount, g.EdgeCount, g.ComponentCount);
+ //g.Print(Console.Out);
+ foreach (KeyValuePair<string, IGraph<string, int, int>> comp in g.Components())
+ {
+ Console.WriteLine("Component of {0}:", comp.Key);
+ comp.Value.Print(Console.Out);
+ }
+ }
+
+ //TODO: remove?
+ static void test3()
+ {
+ HashGraph<int, int, int> g = new HashGraph<int, int, int>(new CountWeight<int>(), Grid(5));
+ g.Print(Console.Out);
+ //EdgeWeight<int, IntWeight> weight = delegate(int i) { return i; };
+ Console.WriteLine("========= PFS accum =========");
+ g.PriorityFirstTraverse(
+ true,
+ 2002,
+ delegate(Edge<int, int> e, int d) { Console.WriteLine("Edge: {0}, at distance {1}", e, d); return true; });
+ Console.WriteLine("========= PFS not accum =========");
+ g.PriorityFirstTraverse(
+ false,
+ 2002,
+ delegate(Edge<int, int> e, int d) { Console.WriteLine("Edge: {0}, at distance {1}", e, d); return true; });
+ Console.WriteLine("========= MST =========");
+ int root;
+ g.MinimumSpanningTree(out root).Print(Console.Out);
+ Console.WriteLine("========= SP =========");
+ foreach (Edge<int, int> edge in g.ShortestPath(1001, 5005))
+ Console.WriteLine(edge);
+ }
+
+ static void test4()
+ {
+ IGraph<string, int, int> g = new HashGraph<string, int, int>(new IntWeight(), Snake(5));
+ Console.WriteLine("Edge count: {0}", g.Edges().Count);
+ Console.WriteLine("========= PFS =========");
+ g.PriorityFirstTraverse(false,
+ "U3",
+ delegate(Edge<string, int> e, int d) { Console.WriteLine("Edge: {0}, at distance {1}", e, d); return true; });
+ Console.WriteLine("========= MST =========");
+ string root;
+ IGraph<string, int, int> mst = g.MinimumSpanningTree(out root);
+ mst.Print(Console.Out);
+ Console.WriteLine("DFS:");
+ mst.TraverseVertices(false, root, delegate(Edge<string, int> e) { Console.WriteLine(e); });
+ Console.WriteLine("ATSP:");
+ int first = 0;
+ foreach (string s in g.ApproximateTSP())
+ {
+ Console.Write((first++ == 0 ? "" : " -> ") + s);
+ }
+ }
+
+ /// <summary>
+ /// This example examines the two variants of a priority-first search:
+ /// with accumulated weights, leading to shortest paths from start;
+ /// with non-acumulated weights, leading to a minimum spanning tree.
+ /// </summary>
+ [ExampleDescription("Priority-first-search with and without accumulated weights")]
+ static void testPFS()
+ {
+ IGraph<string, double, double> g = new HashGraph<string, double, double>(new DoubleWeight(), Wheel(false, 10));
+ g.Print(Console.Out);
+ Console.WriteLine("========= PFS non-accumulated weights (-> MST) =========");
+ g.PriorityFirstTraverse(false,
+ "P0",
+ delegate(Edge<string, double> e, double d) { Console.WriteLine("Edge: {0}, at distance {1}", e, d); return true; });
+ Console.WriteLine("========= PFS accumulated weights (-> Shortst paths from start) =========");
+ g.PriorityFirstTraverse(true,
+ "P0",
+ delegate(Edge<string, double> e, double d) { Console.WriteLine("Edge: {0}, at distance {1}", e, d); return true; });
+ }
+
+ /// <summary>
+ ///
+ ///
+ /// (Refer to Vazirani, or do that where ApproximateTSP is implemented)
+ ///
+ /// Note that the tour created is not optimal. [Describe why]
+ /// </summary>
+ [ExampleDescription("Approximate TSP")]
+ static void testTSP()
+ {
+ IGraph<string, double, double> g = new HashGraph<string, double, double>(new DoubleWeight(), Wheel(true, 10));
+ //g.Print(Console.Out);
+ Console.WriteLine("========= MST =========");
+ string root;
+ IGraph<string, double, double> mst = g.MinimumSpanningTree(out root);
+ mst.TraverseVertices(false,
+ root,
+ delegate(Edge<string, double> e) { Console.WriteLine("Edge: {0} -> {1}", e.start, e.end); });
+ Console.WriteLine("========= Approximate TSP =========");
+ int first = 0;
+ foreach (string s in g.ApproximateTSP())
+ {
+ Console.Write((first++ == 0 ? "" : " -> ") + s);
+ }
+ }
+
+ /// <summary>
+ ///
+ ///
+ /// (Refer to Vazirani, or do that where ApproximateTSP is implemented)
+ ///
+ /// Note that the tour created is not optimal. [Describe why]
+ /// </summary>
+ [ExampleDescription("Approximate TSP2")]
+ static void testTSP2()
+ {
+ HashGraph<string, double, double> g = new HashGraph<string, double, double>(new DoubleWeight(), Wheel(true, 20));
+
+ foreach (string s in g.ApproximateTSP2())
+ Console.WriteLine("# " + s);
+ //g.Print(Console.Out);
+ /*
+ Console.WriteLine("========= MST =========");
+ string root;
+ IGraph<string, double, double> mst = g.MinimumSpanningTree(out root);
+ mst.TraverseVertices(false,
+ root,
+ delegate(Edge<string, double> e) { Console.WriteLine("Edge: {0} -> {1}", e.start, e.end); });
+ ArrayList<string> oddvertices = new ArrayList<string>();
+ foreach (string v in mst.Vertices())
+ if (mst.Adjacent(v).Count % 2 != 0)
+ oddvertices.Add(v);
+
+ Console.WriteLine("========= Matching of odd vertices of mst =========");
+ ICollectionValue<Edge<string, double>> matching = g.SubGraph(oddvertices).ApproximateMWPM();
+
+ Console.WriteLine("========= Add matching to mst =========");
+ //We must split the edges of the matchin with fake temporary vertices
+ //(For a general vertex type, we would have to augment it to Pair<V,int>
+ int fake = 0;
+ foreach (Edge<string, double> e in matching)
+ {
+ string fakevertex = "_" + (fake++);
+ mst.AddEdge(e.start, fakevertex, 0);
+ mst.AddEdge(fakevertex, e.end, e.edgedata);
+ }
+ //mst.Print(Console.Out);
+
+ IList<string> tour = mst.EulerTour(), view = tour.View(1, tour.Count - 1);
+
+ //Remove fake vertices
+ while (view.Count > 0)
+ if (view[0].StartsWith("_"))
+ view.RemoveFirst();
+ else
+ view.Slide(1, view.Count - 1);
+
+ Console.WriteLine("========= Approximate TSP 2 =========");
+ //Short cut
+ view = tour.View(1, tour.Count - 1);
+ HashSet<string> seen = new HashSet<string>();
+
+ while (view.Count > 0)
+ {
+ string s = view[0];
+ if (seen.FindOrAdd(ref s))
+ view.RemoveFirst();
+ else
+ view.Slide(1, view.Count - 1);
+ }
+
+ foreach (string s in tour)
+ Console.WriteLine(". " + s);*/
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ static void testEuler()
+ {
+ HashGraph<string, double, double> g = new HashGraph<string, double, double>(new DoubleWeight(), Wheel(true, 6));
+ foreach (string s in g.EulerTour())
+ Console.Write(s + " ");
+ Console.WriteLine();
+ }
+
+ /// <summary>
+ /// An articulation point in a graph is a vertex, whose removal will
+ /// disconnect the graph (or its component). This example uses the
+ /// extended DepthFirstSearch method to compute articulation points
+ /// of a graph.
+ ///
+ /// (Refer to Sedgewick. )
+ ///
+ /// Each vertex is given an index in traversal order.
+ /// For each vertex, we compute the least index reachable by going downwards
+ /// in the DFS tree and then following a single non-dfs edge.
+ ///
+ /// Since we cannot store the DFS indices in the vertices without changing the
+ /// (assumed given) vertex type, V, we remember the indices in a V-&gt;int
+ /// hash dictionary, index. The "least reachable" values are then stored in an
+ /// array keyed by the index.
+ ///
+ /// The root of the search is an articulation point if it has more than one
+ /// outgoing DFS edges. Other articulation points are non-root vertices, va,
+ /// with an outgoing DFS edge, where the the least reachable index of the other
+ /// vertex is greater or equal to the index of va.
+ /// </summary>
+ [ExampleDescription("Using the advanced DFS to compute articulation points")]
+ static void testDFS()
+ {
+ HashGraph<string, int, int> g = new HashGraph<string, int, int>(new IntWeight());
+ g.AddEdge("A", "B", 0);
+ g.AddEdge("A", "E", 0);
+ g.AddEdge("B", "E", 0);
+ g.AddEdge("B", "C", 0);
+ g.AddEdge("B", "H", 0);
+ g.AddEdge("H", "I", 0);
+ g.AddEdge("B", "D", 0);
+ g.AddEdge("C", "D", 0);
+ g.AddEdge("C", "F", 0);
+ g.AddEdge("C", "G", 0);
+ g.AddEdge("F", "G", 0);
+
+ HashDictionary<string, int> index = new HashDictionary<string, int>();
+ int[] leastIndexReachableFrom = new int[g.VertexCount];
+ int nextindex = 0;
+ int outgoingFromRoot = 0;
+ Action<string> beforevertex = delegate(string v)
+ {
+ int i = (index[v] = nextindex++);
+ leastIndexReachableFrom[i] = i;
+ };
+ Action<string> aftervertex = delegate(string v)
+ {
+ int i = index[v];
+ if (i == 0 && outgoingFromRoot > 1)
+ Console.WriteLine("Articulation point: {0} ({1}>1 outgoing DFS edges from start)",
+ v, outgoingFromRoot);
+ };
+ Action<Edge<string, int>> onfollow = delegate(Edge<string, int> e)
+ {
+ };
+ Action<Edge<string, int>> onfollowed = delegate(Edge<string, int> e)
+ {
+ int startind = index[e.start], endind = index[e.end];
+ if (startind == 0)
+ outgoingFromRoot++;
+ else
+ {
+ int leastIndexReachable = leastIndexReachableFrom[endind];
+ if (leastIndexReachable >= startind)
+ Console.WriteLine("Articulation point: {0} (least index reachable via {3} is {1} >= this index {2})",
+ e.start, leastIndexReachable, startind, e);
+ if (leastIndexReachableFrom[startind] > leastIndexReachable)
+ leastIndexReachableFrom[startind] = leastIndexReachable;
+ }
+ };
+ Action<Edge<string, int>> onnotfollowed = delegate(Edge<string, int> e)
+ {
+ int startind = index[e.start], endind = index[e.end];
+ if (leastIndexReachableFrom[startind] > endind)
+ leastIndexReachableFrom[startind] = endind;
+ };
+
+ string root = "C";
+ g.DepthFirstSearch(root, beforevertex, aftervertex, onfollow, onfollowed, onnotfollowed);
+ Console.WriteLine("Edges:");
+ foreach (Edge<string, int> e in g.Edges())
+ Console.WriteLine("/ {0}", e);
+ }
+
+ static void Main(String[] args)
+ {
+ if (args.Length != 1)
+ {
+ Console.WriteLine("Usage: Graph.exe testno");
+ System.Reflection.MethodInfo[] mis = typeof(Test).GetMethods(
+ System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
+ foreach (System.Reflection.MethodInfo mi in mis)
+ {
+ if (mi.GetParameters().Length == 0 && mi.ReturnType == typeof(void) && mi.Name.StartsWith("test"))
+ {
+ object[] attrs = mi.GetCustomAttributes(typeof(ExampleDescriptionAttribute), false);
+ Console.WriteLine(" {0} : {1}", mi.Name.Substring(4), attrs.Length > 0 ? attrs[0] : "");
+ }
+ }
+ }
+ else
+ {
+ string testMethodName = String.Format("test{0}", args[0]);
+
+ System.Reflection.MethodInfo mi = typeof(Test).GetMethod(testMethodName,
+ System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
+
+ if (mi == null)
+ Console.WriteLine("No such testmethod, {0}", testMethodName);
+ else
+ {
+ object[] attrs = mi.GetCustomAttributes(typeof(ExampleDescriptionAttribute), false);
+ Console.WriteLine("============================== {0}() ==================================", testMethodName);
+ Console.WriteLine("Description: {0}", attrs.Length > 0 ? attrs[0] : "None");
+ Console.WriteLine("===========================================================================");
+ mi.Invoke(null, null);
+ }
+ }
+ }
+ }
+}
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/HashCodes.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/HashCodes.cs
new file mode 100644
index 00000000000..40938d3291c
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/HashCodes.cs
@@ -0,0 +1,106 @@
+/*
+ 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.
+*/
+
+// C5 example: hash codes, good and bad 2005-02-28
+
+// Compile with
+// csc /r:C5.dll HashCodes.cs
+
+using System;
+using C5;
+using SCG = System.Collections.Generic;
+
+namespace MyHashCodesTest {
+ class MyTest {
+ public static void Main(String[] args) {
+ int count = int.Parse(args[0]);
+ {
+ Console.Write("Good hash function: ");
+ Timer t = new Timer();
+ HashSet<int> good
+ = MakeRandom(count, new GoodIntegerEqualityComparer());
+ Console.WriteLine("({0} sec, {1} items)", t.Check(), good.Count);
+ ISortedDictionary<int,int> bcd = good.BucketCostDistribution();
+ foreach (KeyValuePair<int,int> entry in bcd)
+ Console.WriteLine("{0,7} bucket(s) with cost {1,5}",
+ entry.Value, entry.Key);
+ }
+ {
+ Console.Write("Bad hash function: ");
+ Timer t = new Timer();
+ HashSet<int> bad = MakeRandom(count, new BadIntegerEqualityComparer());
+ Console.WriteLine("({0} sec, {1} items)", t.Check(), bad.Count);
+ ISortedDictionary<int,int> bcd = bad.BucketCostDistribution();
+ foreach (KeyValuePair<int,int> entry in bcd)
+ Console.WriteLine("{0,7} bucket(s) with cost {1,5}",
+ entry.Value, entry.Key);
+ }
+ }
+
+ private static readonly C5Random rnd = new C5Random();
+
+ public static HashSet<int> MakeRandom(int count,
+ SCG.IEqualityComparer<int> eqc) {
+ HashSet<int> res;
+ if (eqc == null)
+ res = new HashSet<int>();
+ else
+ res = new HashSet<int>(eqc);
+ for (int i=0; i<count; i++)
+ res.Add(rnd.Next(1000000));
+ return res;
+ }
+
+ private class BadIntegerEqualityComparer : SCG.IEqualityComparer<int> {
+ public bool Equals(int i1, int i2) {
+ return i1 == i2;
+ }
+ public int GetHashCode(int i) {
+ return i % 7;
+ }
+ }
+
+ private class GoodIntegerEqualityComparer : SCG.IEqualityComparer<int> {
+ public bool Equals(int i1, int i2) {
+ return i1 == i2;
+ }
+ public int GetHashCode(int i) {
+ return i;
+ }
+ }
+ }
+
+ // Crude timing utility
+
+ public class Timer {
+ private DateTime start;
+
+ public Timer() {
+ start = DateTime.Now;
+ }
+
+ public double Check() {
+ TimeSpan dur = DateTime.Now - start;
+ return dur.TotalSeconds;
+ }
+ }
+}
+
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/Jobqueue.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/Jobqueue.cs
new file mode 100644
index 00000000000..15944f702be
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/Jobqueue.cs
@@ -0,0 +1,147 @@
+/*
+ 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.
+*/
+
+// C5 example: job queue 2004-11-22
+
+// Compile with
+// csc /r:C5.dll Anagrams.cs
+
+using System;
+using C5;
+using SCG = System.Collections.Generic;
+
+class MyJobQueueTest {
+ public static void Main(String[] args) {
+ JobQueue jq = new JobQueue();
+ // One user submits three jobs at time=27
+ Rid rid1 = jq.Submit(new Ip("62.150.83.11"), 27),
+ rid2 = jq.Submit(new Ip("62.150.83.11"), 27),
+ rid3 = jq.Submit(new Ip("62.150.83.11"), 27);
+ // One job is executed
+ jq.ExecuteOne();
+ // Another user submits two jobs at time=55
+ Rid rid4 = jq.Submit(new Ip("130.225.17.5"), 55),
+ rid5 = jq.Submit(new Ip("130.225.17.5"), 55);
+ // One more job is executed
+ jq.ExecuteOne();
+ // The first user tries to cancel his first and last job
+ jq.Cancel(rid1);
+ jq.Cancel(rid3);
+ // The remaining jobs are executed
+ while (jq.ExecuteOne() != null) { }
+ }
+}
+
+class JobQueue {
+ private readonly IPriorityQueue<Job> jobQueue;
+ private readonly IDictionary<Rid,IPriorityQueueHandle<Job>> jobs;
+ private readonly HashBag<Ip> userJobs;
+
+ public JobQueue() {
+ this.jobQueue = new IntervalHeap<Job>();
+ this.jobs = new HashDictionary<Rid,IPriorityQueueHandle<Job>>();
+ this.userJobs = new HashBag<Ip>();
+ }
+
+ public Rid Submit(Ip ip, int time) {
+ int jobCount = userJobs.ContainsCount(ip);
+ Rid rid = new Rid();
+ Job job = new Job(rid, ip, time + 60 * jobCount);
+ IPriorityQueueHandle<Job> h = null;
+ jobQueue.Add(ref h, job);
+ userJobs.Add(ip);
+ jobs.Add(rid, h);
+ Console.WriteLine("Submitted {0}", job);
+ return rid;
+ }
+
+ public Job ExecuteOne() {
+ if (!jobQueue.IsEmpty) {
+ Job job = jobQueue.DeleteMin();
+ userJobs.Remove(job.ip);
+ jobs.Remove(job.rid);
+ Console.WriteLine("Executed {0}", job);
+ return job;
+ } else
+ return null;
+ }
+
+ public void Cancel(Rid rid) {
+ IPriorityQueueHandle<Job> h;
+ if (jobs.Remove(rid, out h)) {
+ Job job = jobQueue.Delete(h);
+ userJobs.Remove(job.ip);
+ Console.WriteLine("Cancelled {0}", job);
+ }
+ }
+}
+
+class Job : IComparable<Job> {
+ public readonly Rid rid;
+ public readonly Ip ip;
+ public readonly int time;
+
+ public Job(Rid rid, Ip ip, int time) {
+ this.rid = rid;
+ this.ip = ip;
+ this.time = time;
+ }
+
+ public int CompareTo(Job that) {
+ return this.time - that.time;
+ }
+
+ public override String ToString() {
+ return rid.ToString();
+ }
+}
+
+class Rid {
+ private readonly int ridNumber;
+ private static int nextRid = 1;
+ public Rid() {
+ ridNumber = nextRid++;
+ }
+ public override String ToString() {
+ return "rid=" + ridNumber;
+ }
+}
+
+class Ip {
+ public readonly String ipString;
+
+ public Ip(String ipString) {
+ this.ipString = ipString;
+ }
+
+ public override int GetHashCode() {
+ return ipString.GetHashCode();
+ }
+
+ public override bool Equals(Object that) {
+ return
+ that != null
+ && that is Ip
+ && this.ipString.Equals(((Ip)that).ipString);
+ }
+}
+
+
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/KeywordRecognition.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/KeywordRecognition.cs
new file mode 100644
index 00000000000..3758383a2f8
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/KeywordRecognition.cs
@@ -0,0 +1,177 @@
+/*
+ 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.
+*/
+
+// C5 example: Keyword recognition 2004-12-20
+
+// Compile with
+// csc /r:C5.dll KeywordRecognition.cs
+
+using System;
+using C5;
+using SCG = System.Collections.Generic;
+
+namespace KeywordRecognition {
+
+class KeywordRecognition {
+ // Array of 77 keywords:
+
+ static readonly String[] keywordArray =
+ { "abstract", "as", "base", "bool", "break", "byte", "case", "catch",
+ "char", "checked", "class", "const", "continue", "decimal", "default",
+ "delegate", "do", "double", "else", "enum", "event", "explicit",
+ "extern", "false", "finally", "fixed", "float", "for", "foreach",
+ "goto", "if", "implicit", "in", "int", "interface", "internal", "is",
+ "lock", "long", "namespace", "new", "null", "object", "operator",
+ "out", "override", "params", "private", "protected", "public",
+ "readonly", "ref", "return", "sbyte", "sealed", "short", "sizeof",
+ "stackalloc", "static", "string", "struct", "switch", "this", "throw",
+ "true", "try", "typeof", "uint", "ulong", "unchecked", "unsafe",
+ "ushort", "using", "virtual", "void", "volatile", "while" };
+
+ private static readonly ICollection<String> kw1;
+
+ private static readonly ICollection<String> kw2;
+
+ private static readonly ICollection<String> kw3;
+
+ private static readonly SCG.IDictionary<String,bool> kw4 =
+ new SCG.Dictionary<String,bool>();
+
+
+ class SC : SCG.IComparer<string>
+ {
+ public int Compare(string a, string b)
+ {
+ return StringComparer.InvariantCulture.Compare(a,b);
+ }
+ }
+
+ class SH : SCG.IEqualityComparer<string>
+ {
+ public int GetHashCode(string item)
+ {
+ return item.GetHashCode();
+ }
+
+ public bool Equals(string i1, string i2)
+ {
+ return i1 == null ? i2 == null : i1.Equals(i2,StringComparison.InvariantCulture);
+ }
+ }
+
+ static KeywordRecognition() {
+ kw1 = new HashSet<String>();
+ kw1.AddAll<string>(keywordArray);
+ kw2 = new TreeSet<String>(new SC());
+ kw2.AddAll<string>(keywordArray);
+ kw3 = new SortedArray<String>(new SC());
+ kw3.AddAll<string>(keywordArray);
+ kw4 = new SCG.Dictionary<String,bool>();
+ foreach (String keyword in keywordArray)
+ kw4.Add(keyword, false);
+ }
+
+ public static bool IsKeyword1(String s) {
+ return kw1.Contains(s);
+ }
+
+ public static bool IsKeyword2(String s) {
+ return kw2.Contains(s);
+ }
+
+ public static bool IsKeyword3(String s) {
+ return kw3.Contains(s);
+ }
+
+ public static bool IsKeyword4(String s) {
+ return kw4.ContainsKey(s);
+ }
+
+ public static bool IsKeyword5(String s) {
+ return Array.BinarySearch(keywordArray, s) >= 0;
+ }
+
+ public static void Main(String[] args) {
+ if (args.Length != 2)
+ Console.WriteLine("Usage: KeywordRecognition <iterations> <word>\n");
+ else {
+ int count = int.Parse(args[0]);
+ String id = args[1];
+
+ {
+ Console.Write("HashSet.Contains ");
+ Timer t = new Timer();
+ for (int i=0; i<count; i++)
+ IsKeyword1(id);
+ Console.WriteLine(t.Check());
+ }
+
+ {
+ Console.Write("TreeSet.Contains ");
+ Timer t = new Timer();
+ for (int i=0; i<count; i++)
+ IsKeyword2(id);
+ Console.WriteLine(t.Check());
+ }
+
+ {
+ Console.Write("SortedArray.Contains ");
+ Timer t = new Timer();
+ for (int i=0; i<count; i++)
+ IsKeyword3(id);
+ Console.WriteLine(t.Check());
+ }
+
+ {
+ Console.Write("SCG.Dictionary.ContainsKey ");
+ Timer t = new Timer();
+ for (int i=0; i<count; i++)
+ IsKeyword4(id);
+ Console.WriteLine(t.Check());
+ }
+
+ {
+ Console.Write("Array.BinarySearch ");
+ Timer t = new Timer();
+ for (int i=0; i<count; i++)
+ IsKeyword5(id);
+ Console.WriteLine(t.Check());
+ }
+ }
+ }
+}
+
+// Crude timing utility ----------------------------------------
+
+public class Timer {
+ private DateTime start;
+
+ public Timer() {
+ start = DateTime.Now;
+ }
+
+ public double Check() {
+ TimeSpan dur = DateTime.Now - start;
+ return dur.TotalSeconds;
+ }
+}
+
+}
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/ListPatterns.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/ListPatterns.cs
new file mode 100644
index 00000000000..f980ce6e55f
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/ListPatterns.cs
@@ -0,0 +1,141 @@
+/*
+ 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.
+*/
+
+// C5 example: ListPatterns.cs for pattern chapter
+
+// Compile with
+// csc /r:C5.dll ListPatterns.cs
+
+using System;
+using C5;
+using SCG = System.Collections.Generic;
+
+namespace ListPatterns {
+ class ListPatterns {
+ public static void Main(String[] args) {
+ IList<int> list = new ArrayList<int>();
+ list.AddAll(new int[] { 23, 29, 31, 37, 41, 43, 47, 53 });
+ // Reversing and swapping
+ Console.WriteLine(list);
+ list.Reverse();
+ Console.WriteLine(list);
+ ReverseInterval(list, 2, 3);
+ Console.WriteLine(list);
+ SwapInitialFinal(list, 2);
+ Console.WriteLine(list);
+ // Clearing all or part of list
+ list.CollectionCleared
+ += delegate(Object c, ClearedEventArgs eargs) {
+ ClearedRangeEventArgs ceargs = eargs as ClearedRangeEventArgs;
+ if (ceargs != null)
+ Console.WriteLine("Cleared [{0}..{1}]",
+ ceargs.Start, ceargs.Start+ceargs.Count-1);
+ };
+ RemoveSublist1(list, 1, 2);
+ Console.WriteLine(list);
+ RemoveSublist2(list, 1, 2);
+ Console.WriteLine(list);
+ RemoveTail1(list, 3);
+ Console.WriteLine(list);
+ RemoveTail2(list, 2);
+ Console.WriteLine(list);
+ }
+
+ // Reverse list[i..i+n-1]
+
+ public static void ReverseInterval<T>(IList<T> list, int i, int n) {
+ list.View(i,n).Reverse();
+ }
+
+ // Swap list[0..i-1] with list[i..Count-1]
+
+ public static void SwapInitialFinal<T>(IList<T> list, int i) {
+ list.View(0,i).Reverse();
+ list.View(i,list.Count-i).Reverse();
+ list.Reverse();
+ }
+
+ // Remove sublist of a list
+
+ public static void RemoveSublist1<T>(IList<T> list, int i, int n) {
+ list.RemoveInterval(i, n);
+ }
+
+ public static void RemoveSublist2<T>(IList<T> list, int i, int n) {
+ list.View(i, n). Clear();
+ }
+
+
+ // Remove tail of a list
+
+ public static void RemoveTail1<T>(IList<T> list, int i) {
+ list.RemoveInterval(i, list.Count-i);
+ }
+
+ public static void RemoveTail2<T>(IList<T> list, int i) {
+ list.View(i, list.Count-i).Clear();
+ }
+
+ // Pattern for finding and using first (leftmost) x in list
+
+ private static void PatFirst<T>(IList<T> list, T x) {
+ int j = list.IndexOf(x);
+ if (j >= 0) {
+ // x is a position j in list
+ } else {
+ // x is not in list
+ }
+ }
+
+ // Pattern for finding and using last (rightmost) x in list
+
+ private static void PatLast<T>(IList<T> list, T x) {
+ int j = list.LastIndexOf(x);
+ if (j >= 0) {
+ // x is at position j in list
+ } else {
+ // x is not in list
+ }
+ }
+
+ // Pattern for finding and using first (leftmost) x in list[i..i+n-1]
+
+ private static void PatFirstSublist<T>(IList<T> list, T x, int i, int n) {
+ int j = list.View(i,n).IndexOf(x);
+ if (j >= 0) {
+ // x is at position j+i in list
+ } else {
+ // x is not in list[i..i+n-1]
+ }
+ }
+
+ // Pattern for finding and using last (rightmost) x in list[i..i+n-1]
+
+ private static void PatLastSublist<T>(IList<T> list, T x, int i, int n) {
+ int j = list.View(i,n).LastIndexOf(x);
+ if (j >= 0) {
+ // x is at position j+i in list
+ } else {
+ // x is not in list[i..i+n-1]
+ }
+ }
+ }
+}
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/Locking.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/Locking.cs
new file mode 100644
index 00000000000..30365596407
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/Locking.cs
@@ -0,0 +1,97 @@
+// C5 example: locking 2005-11-07
+
+// Compile with
+// csc /r:C5.dll Locking.cs
+
+using System;
+using System.Threading;
+using C5;
+using SCG = System.Collections.Generic;
+
+namespace Locking {
+ class Locking {
+ static ArrayList<int> coll = new ArrayList<int>();
+ // static SCG.List<int> coll = new SCG.List<int>();
+ static readonly int count = 1000;
+
+ public static void Main(String[] args) {
+ Console.WriteLine("Adding and removing without locking:");
+ RunTwoThreads(delegate { AddAndRemove(15000); });
+ Console.WriteLine("coll has {0} items, should be 0", coll.Count);
+
+ coll = new ArrayList<int>();
+ Console.WriteLine("Adding and removing with locking:");
+ RunTwoThreads(delegate { SafeAddAndRemove(15000); });
+ Console.WriteLine("coll has {0} items, should be 0", coll.Count);
+
+ Console.WriteLine("Moving items without locking:");
+ ArrayList<int> from, to;
+ from = new ArrayList<int>();
+ to = new ArrayList<int>();
+ for (int i=0; i<count; i++)
+ from.Add(i);
+ RunTwoThreads(delegate { while (!from.IsEmpty) Move(from, to); });
+ Console.WriteLine("coll has {0} items, should be {1}", to.Count, count);
+
+ Console.WriteLine("Moving items with locking:");
+ from = new ArrayList<int>();
+ to = new ArrayList<int>();
+ for (int i=0; i<count; i++)
+ from.Add(i);
+ RunTwoThreads(delegate { while (!from.IsEmpty) SafeMove(from, to); });
+ Console.WriteLine("coll has {0} items, should be {1}", to.Count, count);
+ }
+
+ public static void RunTwoThreads(Act run) {
+ Thread t1 = new Thread(new ThreadStart(run)),
+ t2 = new Thread(new ThreadStart(run));
+ t1.Start(); t2.Start();
+ t1.Join(); t2.Join();
+ }
+
+ // Concurrently adding to and removing from an arraylist
+
+ public static void AddAndRemove(int count) {
+ for (int i=0; i<count; i++)
+ coll.Add(i);
+ for (int i=0; i<count; i++)
+ coll.Remove(i);
+ }
+
+ private static readonly Object sync = new Object();
+
+ public static void SafeAddAndRemove(int count) {
+ for (int i=0; i<count; i++)
+ lock (sync)
+ coll.Add(i);
+ for (int i=0; i<count; i++)
+ lock (sync)
+ coll.Remove(i);
+ }
+
+ public static void SafeAdd<T>(IExtensible<T> coll, T x) {
+ lock (sync) {
+ coll.Add(x);
+ }
+ }
+
+ public static void Move<T>(ICollection<T> from, ICollection<T> to) {
+ if (!from.IsEmpty) {
+ T x = from.Choose();
+ Thread.Sleep(0); // yield processor to other threads
+ from.Remove(x);
+ to.Add(x);
+ }
+ }
+
+ public static void SafeMove<T>(ICollection<T> from, ICollection<T> to) {
+ lock (sync)
+ if (!from.IsEmpty) {
+ T x = from.Choose();
+ Thread.Sleep(0); // yield processor to other threads
+ from.Remove(x);
+ to.Add(x);
+ }
+ }
+ }
+}
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/Makefile b/mcs/class/Mono.C5/1.0/UserGuideExamples/Makefile
new file mode 100644
index 00000000000..a2db8fc60fd
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/Makefile
@@ -0,0 +1,27 @@
+# Makefile for C5 book examples
+
+USERGUIDEFILES= Anagrams.cs Antipatterns.cs CollectionSanity.cs EventPatterns.cs \
+ Fileindex.cs GConvexHull.cs GNfaToDfa.cs GettingStarted.cs \
+ Graph.cs Graphcopy.cs HashCodes.cs Jobqueue.cs \
+ KeywordRecognition.cs ListPatterns.cs ListPatterns.cs \
+ Locking.cs MultiDictionary.cs PointLocation.cs \
+ RandomSelection.cs ReadOnlyPatterns.cs Sets.cs \
+ SortedIterationPatterns.cs SortedIterationPatterns.cs \
+ SortingPermutation.cs Toposort.cs ViewPatterns.cs WrappedArray.cs
+
+all: c5examples.zip
+
+c5examples.zip: ${USERGUIDEFILES}
+ rm -f C5.examples.zip
+ zip C5.examples.zip ${USERGUIDEFILES}
+
+clean:
+ rm -f C5.examples.zip
+ rm -f *.dot
+ rm -f *.exe
+ rm -f *.ps
+ rm -f *.eps
+
+.SUFFIXES :
+.SUFFIXES : .cs
+
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/MultiCollection.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/MultiCollection.cs
new file mode 100644
index 00000000000..32ec13ae7d0
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/MultiCollection.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 System;
+using C5;
+using SCG = System.Collections.Generic;
+
+namespace MultiCollection
+{
+ class BasicCollectionValue<T> : CollectionValueBase<T>, ICollectionValue<T>
+ {
+ SCG.IEnumerable<T> enumerable;
+ Fun<T> chooser;
+ int count;
+ //TODO: add delegate for checking validity!
+
+ public BasicCollectionValue(SCG.IEnumerable<T> e, Fun<T> chooser, int c) { enumerable = e; count = c; this.chooser = chooser; }
+
+ public override int Count { get { return count; } }
+
+ public override Speed CountSpeed { get { return Speed.Constant; } }
+
+ public override bool IsEmpty { get { return count == 0; } }
+
+ public override T Choose() { return chooser(); }
+
+ public override System.Collections.Generic.IEnumerator<T> GetEnumerator()
+ {
+ return enumerable.GetEnumerator();
+ }
+ }
+
+ interface IMultiCollection<K, V>
+ {
+ SCG.IEqualityComparer<K> KeyEqualityComparer { get;}
+ SCG.IEqualityComparer<V> ValueEqualityComparer { get;}
+ bool Add(K k, V v);
+ bool Remove(K k, V v);
+ ICollectionValue<V> this[K k] { get;}
+ ICollectionValue<K> Keys { get;}
+ SCG.IEnumerable<V> Values { get;}
+
+ }
+
+ class BasicMultiCollection<K, V, W, U> : IMultiCollection<K, V>//: IDictionary<K, W>
+ where W : ICollection<V>, new()
+ where U : IDictionary<K, W>, new()
+ {
+ U dict = new U();
+
+ public SCG.IEqualityComparer<K> KeyEqualityComparer { get { return EqualityComparer<K>.Default; } }
+
+ public SCG.IEqualityComparer<V> ValueEqualityComparer { get { return EqualityComparer<V>.Default; } } //TODO: depends on W!
+
+ public bool Add(K k, V v)
+ {
+ W w;
+ if (!dict.Find(k, out w))
+ dict.Add(k,w = new W());
+ return w.Add(v);
+ }
+
+ public bool Remove(K k, V v)
+ {
+ W w;
+ if (dict.Find(k, out w) && w.Remove(v))
+ {
+ if (w.Count == 0)
+ dict.Remove(k);
+ return true;
+ }
+ return false;
+ }
+
+ public ICollectionValue<V> this[K k] { get { return dict[k]; } }
+
+ public ICollectionValue<K> Keys { get { return dict.Keys; } }
+
+ public SCG.IEnumerable<V> Values
+ {
+ get
+ {
+ foreach (W w in dict.Values)
+ foreach (V v in w)
+ yield return v;
+ }
+ }
+ }
+
+ class WordIndex : BasicMultiCollection<string,int,HashSet<int>,HashDictionary<string,HashSet<int>>>
+ {
+ }
+
+ class MyTest
+ {
+ public static void Main(String[] args)
+ {
+ WordIndex wi = new WordIndex();
+ wi.Add("ja", 2);
+ wi.Add("nej", 4);
+ wi.Add("ja", 7);
+ foreach (string s in wi.Keys)
+ {
+ Console.WriteLine(s + " -->");
+ foreach (int line in wi[s])
+ {
+ Console.WriteLine(" " + line);
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/MultiDictionary.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/MultiDictionary.cs
new file mode 100644
index 00000000000..22fad233345
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/MultiDictionary.cs
@@ -0,0 +1,308 @@
+/*
+ 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.
+*/
+
+// C5 example: 2006-01-29
+
+// Compile with
+// csc /r:C5.dll MultiDictionary.cs
+
+using System;
+using C5;
+using SCG = System.Collections.Generic;
+
+namespace MultiDictionaries {
+
+ using MultiDictionary2;
+
+ class MyTest {
+ public static void Main(String[] args) {
+ MultiHashDictionary<int,String> mdict = new MultiHashDictionary<int,String>();
+ mdict.Add(2, "to");
+ mdict.Add(2, "deux");
+ mdict.Add(2, "two");
+ mdict.Add(20, "tyve");
+ mdict.Add(20, "twenty");
+ Console.WriteLine(mdict);
+ Console.WriteLine("mdict.Count is {0}", mdict.Count);
+ Console.WriteLine("mdict.Count (keys) is {0}",
+ ((IDictionary<int,ICollection<String>>)mdict).Count);
+ Console.WriteLine("mdict[2].Count is {0}", mdict[2].Count);
+ mdict.Remove(20, "tyve");
+ mdict.Remove(20, "twenty");
+ Console.WriteLine(mdict);
+ Console.WriteLine("mdict.Count is {0}", mdict.Count);
+ ICollection<String> zwei = new HashSet<String>();
+ zwei.Add("zwei");
+ mdict[2] = zwei;
+ mdict[-2] = zwei;
+ Console.WriteLine(mdict);
+ Console.WriteLine("mdict.Count is {0}", mdict.Count);
+ zwei.Add("kaksi");
+ Console.WriteLine(mdict);
+ Console.WriteLine("mdict.Count is {0}", mdict.Count);
+ ICollection<String> empty = new HashSet<String>();
+ mdict[0] = empty;
+ Console.WriteLine(mdict);
+ Console.WriteLine("mdict.Count is {0}", mdict.Count);
+ Console.WriteLine("mdict contains key 0: {0}", mdict.Contains(0));
+ mdict.Remove(-2);
+ Console.WriteLine(mdict);
+ Console.WriteLine("mdict.Count is {0}", mdict.Count);
+ zwei.Remove("kaksi");
+ Console.WriteLine(mdict);
+ Console.WriteLine("mdict.Count is {0}", mdict.Count);
+ zwei.Clear();
+ Console.WriteLine(mdict);
+ Console.WriteLine("mdict.Count is {0}", mdict.Count);
+ }
+ }
+}
+
+namespace MultiDictionary1 {
+ // Here we implement a multivalued dictionary as a hash dictionary
+ // from keys to value collections. The value collections may have set
+ // or bag semantics.
+
+ // The value collections are externally modifiable (as in Peter
+ // Golde's PowerCollections library), and therefore:
+ //
+ // * A value collection associated with a key may be null or
+ // non-empty. Hence for correct semantics, the Contains(k) method
+ // must check that the value collection associated with a key is
+ // non-null and non-empty.
+ //
+ // * A value collection may be shared between two or more keys.
+ //
+
+ // A C5 hash dictionary each of whose keys map to a collection of values.
+
+ public class MultiHashDictionary<K,V> : HashDictionary<K, ICollection<V>> {
+
+ // Return total count of values associated with keys. This basic
+ // implementation simply sums over all value collections, and so
+ // is a linear-time operation in the total number of values.
+
+ public new virtual int Count {
+ get {
+ int count = 0;
+ foreach (KeyValuePair<K,ICollection<V>> entry in this)
+ if (entry.Value != null)
+ count += entry.Value.Count;
+ return count;
+ }
+ }
+
+ public override Speed CountSpeed {
+ get { return Speed.Linear; }
+ }
+
+ // Add a (key,value) pair
+
+ public virtual void Add(K k, V v) {
+ ICollection<V> values;
+ if (!base.Find(k, out values) || values == null) {
+ values = new HashSet<V>();
+ Add(k, values);
+ }
+ values.Add(v);
+ }
+
+ // Remove a single (key,value) pair, if present; return true if
+ // anything was removed, else false
+
+ public virtual bool Remove(K k, V v) {
+ ICollection<V> values;
+ if (base.Find(k, out values) && values != null) {
+ if (values.Remove(v)) {
+ if (values.IsEmpty)
+ base.Remove(k);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Determine whether key k is associated with a value
+
+ public override bool Contains(K k) {
+ ICollection<V> values;
+ return Find(k, out values) && values != null && !values.IsEmpty;
+ }
+
+ // Determine whether each key in ks is associated with a value
+
+ public override bool ContainsAll<U>(SCG.IEnumerable<U> ks) {
+ foreach (K k in ks)
+ if (!Contains(k))
+ return false;
+ return true;
+ }
+
+ // Get or set the value collection associated with key k
+
+ public override ICollection<V> this[K k] {
+ get {
+ ICollection<V> values;
+ return base.Find(k, out values) && values != null ? values : new HashSet<V>();
+ }
+ set {
+ base[k] = value;
+ }
+ }
+
+ // Inherited from base class HashDictionary<K,ICollection<V>>:
+
+ // Add(K k, ICollection<V> values)
+ // AddAll(IEnumerable<KeyValuePair<K,ICollection<V>>> kvs)
+ // Clear
+ // Clone
+ // Find(K k, out ICollection<V> values)
+ // Find(ref K k, out ICollection<V> values)
+ // FindOrAdd(K k, ref ICollection<V> values)
+ // Remove(K k)
+ // Remove(K k, out ICollection<V> values)
+ // Update(K k, ICollection<V> values)
+ // Update(K k, ICollection<V> values, out ICollection<V> oldValues)
+ // UpdateOrAdd(K k, ICollection<V> values)
+ // UpdateOrAdd(K k, ICollection<V> values, out ICollection<V> oldValues)
+ }
+}
+
+
+namespace MultiDictionary2 {
+ // Here we implement a multivalued dictionary as a hash dictionary
+ // from keys to value collections. The value collections may have
+ // set or bag semantics. This version uses event listeners to make
+ // the Count operation constant time.
+
+ // * To avoid recomputing the total number of values for the Count
+ // property, one may cache it and then use event listeners on the
+ // value collections to keep the cached count updated. In turn, this
+ // requires such event listeners on the dictionary also.
+
+ // A C5 hash dictionary each of whose keys map to a collection of values.
+
+ public class MultiHashDictionary<K,V> : HashDictionary<K, ICollection<V>> {
+ private int count = 0; // Cached value count, updated by events only
+
+ private void IncrementCount(Object sender, ItemCountEventArgs<V> args) {
+ count += args.Count;
+ }
+
+ private void DecrementCount(Object sender, ItemCountEventArgs<V> args) {
+ count -= args.Count;
+ }
+
+ private void ClearedCount(Object sender, ClearedEventArgs args) {
+ count -= args.Count;
+ }
+
+ public MultiHashDictionary() {
+ ItemsAdded +=
+ delegate(Object sender, ItemCountEventArgs<KeyValuePair<K,ICollection<V>>> args) {
+ ICollection<V> values = args.Item.Value;
+ if (values != null) {
+ count += values.Count;
+ values.ItemsAdded += IncrementCount;
+ values.ItemsRemoved += DecrementCount;
+ values.CollectionCleared += ClearedCount;
+ }
+ };
+ ItemsRemoved +=
+ delegate(Object sender, ItemCountEventArgs<KeyValuePair<K,ICollection<V>>> args) {
+ ICollection<V> values = args.Item.Value;
+ if (values != null) {
+ count -= values.Count;
+ values.ItemsAdded -= IncrementCount;
+ values.ItemsRemoved -= DecrementCount;
+ values.CollectionCleared -= ClearedCount;
+ }
+ };
+ }
+
+ // Return total count of values associated with keys.
+
+ public new virtual int Count {
+ get {
+ return count;
+ }
+ }
+
+ public override Speed CountSpeed {
+ get { return Speed.Constant; }
+ }
+
+ // Add a (key,value) pair
+
+ public virtual void Add(K k, V v) {
+ ICollection<V> values;
+ if (!base.Find(k, out values) || values == null) {
+ values = new HashSet<V>();
+ Add(k, values);
+ }
+ values.Add(v);
+ }
+
+ // Remove a single (key,value) pair, if present; return true if
+ // anything was removed, else false
+
+ public virtual bool Remove(K k, V v) {
+ ICollection<V> values;
+ if (base.Find(k, out values) && values != null) {
+ if (values.Remove(v)) {
+ if (values.IsEmpty)
+ base.Remove(k);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Determine whether key k is associated with a value
+
+ public override bool Contains(K k) {
+ ICollection<V> values;
+ return Find(k, out values) && values != null && !values.IsEmpty;
+ }
+
+ // Determine whether each key in ks is associated with a value
+
+ public override bool ContainsAll<U>(SCG.IEnumerable<U> ks) {
+ foreach (K k in ks)
+ if (!Contains(k))
+ return false;
+ return true;
+ }
+
+ // Get or set the value collection associated with key k
+
+ public override ICollection<V> this[K k] {
+ get {
+ ICollection<V> values;
+ return base.Find(k, out values) && values != null ? values : new HashSet<V>();
+ }
+ set {
+ base[k] = value;
+ }
+ }
+ }
+}
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/PointLocation.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/PointLocation.cs
new file mode 100644
index 00000000000..88f24aa91db
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/PointLocation.cs
@@ -0,0 +1,774 @@
+/*
+ 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 C5;
+using SCG = System.Collections.Generic;
+
+namespace PointLocation
+{
+ //public enum Site { Cell,Edge,Outside}
+ /// <summary>
+ /// A line segment with associated data of type T for the cell
+ /// to its right respectively left.
+ /// </summary>
+ public struct Edge<T>
+ {
+ public double xs, ys, xe, ye;
+
+ public T right, left;
+
+ public Edge(double xs, double ys, double xe, double ye, T right, T left)
+ {
+ this.xs = xs;
+ this.ys = ys;
+ this.xe = xe;
+ this.ye = ye;
+ this.right = right;
+ this.left = left;
+ }
+
+
+ public T Cell(bool upper)
+ {
+ return (DoubleComparer.StaticCompare(xs, xe) < 0) == upper ? left : right;
+ }
+
+
+ public override string ToString()
+ {
+ return String.Format("[({0:G5};{1:G5})->({2:G5};{3:G5})/R:{4} L:{5}]", xs, ys, xe, ye, right, left);
+ }
+ }
+
+
+
+ /// <summary>
+ /// A data structure for point location in a plane divided into
+ /// cells by edges. This is the classical use of persistent trees
+ /// by Sarnak and Tarjan [?]. See de Berg et al for alternatives.
+ ///
+ /// The internal data is an outer sorted dictionary that maps each
+ /// x coordinate of an endpoint of some edge to an inner sorted set
+ /// of the edges crossing or touching the vertical line at that x
+ /// coordinate, the edges being ordered by their y coordinates
+ /// to the immediate right of x. Lookup of a point (x,y) is done by
+ /// finding the predecessor of x cell the outer dictionary and then locating
+ /// the edges above and below (x,y) by searching in the inner sorted set.
+ ///
+ /// The creation of the inner sorted sets is done by maintaining a
+ /// (persistent) tree of edges, inserting and deleting edges according
+ /// to a horzontal sweep of the edges while saving a snapshot of the
+ /// inner tree in the outer dictionary at each new x coordinate.
+ ///
+ /// If there are n edges, there will be 2n updates to the inner tree,
+ /// and in the worst case, the inner tree will have size Omega(n) for
+ /// Omega(n) snapshots. We will use O(n*logn) time and O(n) space for
+ /// sorting the endpoints. If we use a nodecopying persistent inner tree,
+ /// we will use O(n) space and time for building the data structure proper.
+ /// If we use a pathcopy persistent tree, we will use O(n*logn) time and
+ /// space for the data struicture. Finally, if we use a non-persistent
+ /// tree with a full copy for snapshot, we may use up to O(n^2) space and
+ /// time for building the datastructure.
+ ///
+ /// Lookup will take O(logn) time in any case, but taking the memory
+ /// hierarchy into consideration, a low space use is very beneficial
+ /// for large problems.
+ ///
+ /// The code assumes that the given set of edges is correct, in particular
+ /// that they do not touch at interior points (e.g. cross or coincide).
+ /// </summary>
+
+ public class PointLocator<T>
+ {
+ private TreeDictionary<double,ISorted<Edge<T>>> htree;
+
+ private EdgeComparer<T> lc = new EdgeComparer<T>();
+
+ private SCG.IComparer<EndPoint> epc = new EndPoint(0, 0, true, 0);
+
+ private DoubleComparer dc = new DoubleComparer();
+
+ private TreeDictionary<EndPoint,Edge<T>> endpoints;
+
+ private int count;
+
+ private bool built = false;
+
+ public PointLocator()
+ {
+ //htree = new TreeDictionary<double,TreeSet<Edge<T>>>(dc);
+ endpoints = new TreeDictionary<EndPoint,Edge<T>>(epc);
+ }
+
+ public PointLocator(SCG.IEnumerable<Edge<T>> edges)
+ {
+ //htree = new TreeDictionary<double,TreeSet<Edge<T>>>(dc);
+ endpoints = new TreeDictionary<EndPoint,Edge<T>>(epc);
+ foreach (Edge<T> edge in edges)
+ add(edge);
+ }
+
+ private void add(Edge<T> edge)
+ {
+ int c = DoubleComparer.StaticCompare(edge.xs, edge.xe);
+
+ if (c == 0)
+ return;
+
+ endpoints.Add(new EndPoint(edge.xs, edge.ys, c < 0, count), edge);
+ endpoints.Add(new EndPoint(edge.xe, edge.ye, c > 0, count++), edge);
+ }
+
+ public void Add(Edge<T> edge)
+ {
+ if (built)
+ throw new InvalidOperationException("PointLocator static when built");
+ add(edge);
+ }
+
+ public void AddAll(SCG.IEnumerable<Edge<T>> edges)
+ {
+ if (built)
+ throw new InvalidOperationException("PointLocator static when built");
+
+ foreach (Edge<T> edge in edges)
+ add(edge);
+ }
+
+ public void Build()
+ {
+ //htree.Clear();
+ htree = new TreeDictionary<double,ISorted<Edge<T>>>(dc);
+
+ TreeSet<Edge<T>> vtree = new TreeSet<Edge<T>>(lc);
+ double lastx = Double.NegativeInfinity;
+
+ foreach (KeyValuePair<EndPoint,Edge<T>> p in endpoints)
+ {
+ if (dc.Compare(p.Key.x,lastx)>0)
+ {
+ //Put an empty snapshot at -infinity!
+ htree[lastx] = (ISorted<Edge<T>>)(vtree.Snapshot());
+ lc.X = lastx = p.Key.x;
+ lc.compareToRight = false;
+ }
+
+ if (p.Key.start)
+ {
+ if (!lc.compareToRight)
+ lc.compareToRight = true;
+ Debug.Assert(vtree.Check());
+ bool chk = vtree.Add(p.Value);
+ Debug.Assert(vtree.Check());
+
+ Debug.Assert(chk,"edge was not added!",""+p.Value);
+ }
+ else
+ {
+ Debug.Assert(!lc.compareToRight);
+
+ Debug.Assert(vtree.Check("C"));
+
+ bool chk = vtree.Remove(p.Value);
+ Debug.Assert(vtree.Check("D"));
+
+ Debug.Assert(chk,"edge was not removed!",""+p.Value);
+ }
+ }
+ lc.compareToRight = true;
+
+ htree[lastx] = (TreeSet<Edge<T>>)(vtree.Snapshot());
+ built = true;
+ }
+
+
+ /*public void Clear()
+ {
+ endpoints.Clear();
+ htree.Clear();
+ }*/
+ /// <summary>
+ /// Find the cell, if any, containing (x,y).
+ /// </summary>
+ /// <param name="x">x coordinate of point</param>
+ /// <param name="y">y coordinate of point</param>
+ /// <param name="below">Associate data of cell according to edge below</param>
+ /// <param name="above">Associate data of cell according to edge above</param>
+ /// <returns>True if point is inside some cell</returns>
+ public bool Place(double x, double y, out T cell)
+ {
+ if (!built)
+ throw new InvalidOperationException("PointLocator must be built first");
+
+ KeyValuePair<double,ISorted<Edge<T>>> p = htree.WeakPredecessor(x);
+
+ //if (DoubleComparer.StaticCompare(cell.key,x)==0)
+ //Just note it, we have thrown away the vertical edges!
+ Edge<T> low, high;
+ bool lval, hval;
+ PointComparer<T> c = new PointComparer<T>(x, y);
+
+ //Return value true here means we are at an edge.
+ //But note that if x is in htree.Keys, we may be at a
+ //vertical edge even if the return value is false here.
+ //Therefore we do not attempt to sort out completely the case
+ //where (x,y) is on an edge or even on several edges,
+ //and just deliver some cell it is in.
+ p.Value.Cut(c, out low, out lval, out high, out hval);
+ if (!lval || !hval)
+ {
+ cell = default(T);
+ return false;
+ }
+ else
+ {
+ cell = low.Cell(true);//high.Cell(false);
+ return true;
+ }
+ }
+
+ public void Place(double x, double y, out T upper, out bool hval, out T lower, out bool lval)
+ {
+ if (!built)
+ throw new InvalidOperationException("PointLocator must be built first");
+
+ KeyValuePair<double,ISorted<Edge<T>>> p = htree.WeakPredecessor(x);
+
+ //if (DoubleComparer.StaticCompare(cell.key,x)==0)
+ //Just note it, we have thrown away the vertical edges!
+ Edge<T> low, high;
+ PointComparer<T> c = new PointComparer<T>(x, y);
+
+ //Return value true here means we are at an edge.
+ //But note that if x is in htree.Keys, we may be at a
+ //vertical edge even if the return value is false here.
+ //Therefore we do not attempt to sort out completely the case
+ //where (x,y) is on an edge or even on several edges,
+ //and just deliver some cell it is in.
+ p.Value.Cut(c, out low, out lval, out high, out hval);
+ upper = hval ? high.Cell(false) : default(T);
+ lower = lval ? low.Cell(true) : default(T);
+ return;
+ }
+
+ public void Test(double x, double y)
+ {
+ T cell;
+
+ if (Place(x, y, out cell))
+ Console.WriteLine("({0}; {1}): <- {2} ", x, y, cell);
+ else
+ Console.WriteLine("({0}; {1}): -", x, y);
+ }
+
+ /// <summary>
+ /// Endpoint of an edge with ordering/comparison according to x
+ /// coordinates with arbitration by the id field.
+ /// The client is assumed to keep the ids unique.
+ /// </summary>
+ public /*private*/ struct EndPoint: SCG.IComparer<EndPoint>
+ {
+ public double x, y;
+
+ public bool start;
+
+ private int id;
+
+
+ public EndPoint(double x, double y, bool left, int id)
+ {
+ this.x = x;this.y = y;this.start = left;this.id = id;
+ }
+
+
+ public int Compare(EndPoint a, EndPoint b)
+ {
+ int c = DoubleComparer.StaticCompare(a.x, b.x);
+
+ return c != 0 ? c : (a.start && !b.start) ? 1 : (!a.start && b.start) ? -1 : a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Compare two doubles with tolerance.
+ /// </summary>
+ class DoubleComparer: SCG.IComparer<double>
+ {
+ private const double eps = 1E-10;
+
+ public int Compare(double a, double b)
+ {
+ return a > b + eps ? 1 : a < b - eps ? -1 : 0;
+ }
+
+ public static int StaticCompare(double a, double b)
+ {
+ return a > b + eps ? 1 : a < b - eps ? -1 : 0;
+ }
+ }
+
+ /// <summary>
+ /// Compare a given point (x,y) to edges: is the point above, at or below
+ /// the edge. Assumes edges not vertical.
+ /// </summary>
+ class PointComparer<T>: IComparable<Edge<T>>
+ {
+ private double x, y;
+
+ public PointComparer(double x, double y)
+ {
+ this.x = x; this.y = y;
+ }
+
+ public int CompareTo(Edge<T> a)
+ {
+ double ya = (a.ye - a.ys) / (a.xe - a.xs) * (x - a.xs) + a.ys;
+
+ return DoubleComparer.StaticCompare(y, ya);
+ }
+
+ public bool Equals(Edge<T> a) { return CompareTo(a) == 0; }
+ }
+
+ /// <summary>
+ /// Compare two edges at a given x coordinate:
+ /// Compares the y-coordinate to the immediate right of x of the two edges.
+ /// Assumes edges to be compared are not vertical.
+ /// </summary>
+ class EdgeComparer<T>: SCG.IComparer<Edge<T>>
+ {
+ private double x;
+
+ public bool compareToRight = true;
+
+ public double X { get { return x; } set { x = value; } }
+
+ public int Compare(Edge<T> line1, Edge<T> line2)
+ {
+ double a1 = (line1.ye - line1.ys) / (line1.xe - line1.xs);
+ double a2 = (line2.ye - line2.ys) / (line2.xe - line2.xs);
+ double ya = a1 * (x - line1.xs) + line1.ys;
+ double yb = a2 * (x - line2.xs) + line2.ys;
+ int c = DoubleComparer.StaticCompare(ya, yb);
+
+ return c != 0 ? c : (compareToRight ? 1 : -1) * DoubleComparer.StaticCompare(a1, a2);
+ }
+ }
+
+ namespace Test
+ {
+ public class Ugly : EnumerableBase<Edge<int>>, SCG.IEnumerable<Edge<int>>, SCG.IEnumerator<Edge<int>>
+ {
+ private int level = -1, maxlevel;
+
+ private bool leftend = false;
+
+ public Ugly(int maxlevel)
+ {
+ this.maxlevel = maxlevel;
+ }
+
+ public override SCG.IEnumerator<Edge<int>> GetEnumerator()
+ {
+ return (SCG.IEnumerator<Edge<int>>)MemberwiseClone();
+ }
+
+ public void Reset()
+ {
+ level = -1;
+ leftend = false;
+ }
+
+ public bool MoveNext()
+ {
+ if (level > maxlevel)
+ throw new InvalidOperationException();
+
+ if (leftend)
+ {
+ leftend = false;
+ return true;
+ }
+ else
+ {
+ leftend = true;
+ return ++level <= maxlevel;
+ }
+ }
+
+ public Edge<int> Current
+ {
+ get
+ {
+ if (level < 0 || level > maxlevel)
+ throw new InvalidOperationException();
+
+ double y = (level * 37) % maxlevel;
+ double deltax = leftend ? 1 : maxlevel;
+
+ if (leftend)
+ return new Edge<int>(0, y, level, y - 0.5, 0, 0);
+ else
+ return new Edge<int>(level, y - 0.5, level, y, 0, 0);
+ }
+ }
+
+
+ public void Dispose() { }
+
+#region IEnumerable Members
+
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+ {
+ throw new Exception("The method or operation is not implemented.");
+ }
+
+#endregion
+
+#region IEnumerator Members
+
+ object System.Collections.IEnumerator.Current
+ {
+ get { throw new Exception("The method or operation is not implemented."); }
+ }
+
+ void System.Collections.IEnumerator.Reset()
+ {
+ throw new Exception("The method or operation is not implemented.");
+ }
+
+#endregion
+ }
+
+ public class TestUgly
+ {
+ private Ugly ugly;
+
+ private int d;
+
+ private PointLocator<int> pointlocator;
+
+
+ public TestUgly(int d)
+ {
+ this.d = d;
+ ugly = new Ugly(d);
+ }
+
+
+ public double Traverse()
+ {
+ double xsum = 0;
+
+ foreach (Edge<int> e in ugly) xsum += e.xe;
+
+ return xsum;
+ }
+
+ public bool LookUp(int count, int seed)
+ {
+ Random random = new Random(seed);
+ bool res = false;
+
+ for (int i = 0; i < count; i++)
+ {
+ int cell;
+
+ res ^= pointlocator.Place(random.NextDouble() * d, random.NextDouble() * d, out cell);
+ }
+
+ return res;
+ }
+
+ public static void Run(string[] args)
+ {
+ int d = args.Length >= 2 ? int.Parse(args[1]) : 400;//00;
+ int repeats = args.Length >= 3 ? int.Parse(args[2]) : 10;
+ int lookups = args.Length >= 4 ? int.Parse(args[3]) : 500;//00;
+
+ new TestUgly(d).run(lookups);
+ }
+
+
+ public void run(int lookups)
+ {
+ double s = 0;
+
+ s += Traverse();
+
+ pointlocator = new PointLocator<int>(ugly);
+ pointlocator.Build();
+
+ LookUp(lookups, 567);
+ }
+ }
+
+ public class Lattice : EnumerableBase<Edge<string>>, SCG.IEnumerable<Edge<string>>, SCG.IEnumerator<Edge<string>>, System.Collections.IEnumerator
+ {
+ private int currenti = -1, currentj = 0, currentid = 0;
+
+ private bool currenthoriz = true;
+
+ private int maxi, maxj;
+
+ private double a11 = 1, a21 = -1, a12 = 1, a22 = 1;
+
+ public Lattice(int maxi, int maxj, double a11, double a21, double a12, double a22)
+ {
+ this.maxi = maxi;
+ this.maxj = maxj;
+ this.a11 = a11;
+ this.a12 = a12;
+ this.a21 = a21;
+ this.a22 = a22;
+ }
+
+ public Lattice(int maxi, int maxj)
+ {
+ this.maxi = maxi;
+ this.maxj = maxj;
+ }
+
+ public override SCG.IEnumerator<Edge<string>> GetEnumerator()
+ {
+ return (SCG.IEnumerator<Edge<string>>)MemberwiseClone();
+ }
+
+ public void Reset()
+ {
+ currenti = -1;
+ currentj = 0;
+ currentid = -1;
+ currenthoriz = true;
+ }
+
+ public bool MoveNext()
+ {
+ currentid++;
+ if (currenthoriz)
+ {
+ if (++currenti >= maxi)
+ {
+ if (currentj >= maxj)
+ return false;
+
+ currenti = 0;
+ currenthoriz = false;
+ }
+
+ return true;
+ }
+ else
+ {
+ if (++currenti > maxi)
+ {
+ currenti = 0;
+ currenthoriz = true;
+ if (++currentj > maxj)
+ return false;
+ }
+
+ return true;
+ }
+ }
+
+
+ private string i2l(int i)
+ {
+ int ls = 0, j = i;
+
+ do { ls++; j = j / 26 - 1; } while (j >= 0);
+
+ char[] res = new char[ls];
+
+ while (ls > 0) { res[--ls] = (char)(65 + i % 26); i = i / 26 - 1; }
+
+ //res[0]--;
+ return new String(res);
+ }
+
+
+ private string fmtid(int i, int j)
+ {
+ return "";//cell + ";" + cell;
+ /*if (cell < 0 || cell < 0 || cell >= maxi || cell >= maxj)
+ return "Outside";
+
+ return String.Format("{0}{1}", i2l(cell), cell);*/
+ }
+
+
+ public Edge<string> Current
+ {
+ get
+ {
+ if (currenti >= maxi && currentj >= maxj)
+ throw new InvalidOperationException();
+
+ double xs = currenti * a11 + currentj * a12;
+ double ys = currenti * a21 + currentj * a22;
+ double deltax = currenthoriz ? a11 : a12;
+ double deltay = currenthoriz ? a21 : a22;
+ string r = fmtid(currenti, currenthoriz ? currentj - 1 : currentj);
+ string l = fmtid(currenthoriz ? currenti : currenti - 1, currentj);
+
+ return new Edge<string>(xs, ys, xs + deltax, ys + deltay, r, l);
+ }
+ }
+
+
+ public void Dispose() { }
+
+#region IEnumerable Members
+
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+ {
+ throw new Exception("The method or operation is not implemented.");
+ }
+
+#endregion
+
+#region IEnumerator Members
+
+ object System.Collections.IEnumerator.Current
+ {
+ get { throw new Exception("The method or operation is not implemented."); }
+ }
+
+ bool System.Collections.IEnumerator.MoveNext()
+ {
+ throw new Exception("The method or operation is not implemented.");
+ }
+
+ void System.Collections.IEnumerator.Reset()
+ {
+ throw new Exception("The method or operation is not implemented.");
+ }
+
+#endregion
+ }
+
+ public class TestLattice
+ {
+ private Lattice lattice;
+
+ private int d;
+
+ private PointLocator<string> pointlocator;
+
+
+ public TestLattice(int d)
+ {
+ this.d = d;
+ lattice = new Lattice(d, d, 1, 0, 0, 1);
+ }
+
+ public TestLattice(int d, double shear)
+ {
+ this.d = d;
+ lattice = new Lattice(d, d, 1, 0, shear, 1);
+ }
+
+ public double Traverse()
+ {
+ double xsum = 0;
+
+ foreach (Edge<string> e in lattice) xsum += e.xe;
+
+ return xsum;
+ }
+
+
+ public bool LookUp(int count, int seed)
+ {
+ Random random = new Random(seed);
+ bool res = false;
+
+ for (int i = 0; i < count; i++)
+ {
+ string cell;
+
+ res ^= pointlocator.Place(random.NextDouble() * d, random.NextDouble() * d, out cell);
+ }
+
+ return res;
+ }
+
+
+ public static void Run()
+ {
+ int d = 200;
+ int repeats = 2;
+ int lookups = 50000;
+ TestLattice tl = null;
+
+ Console.WriteLine("TestLattice Run({0}), means over {1} repeats:", d, repeats);
+ tl = new TestLattice(d, 0.000001);
+
+ tl.Traverse();
+
+ tl.pointlocator = new PointLocator<string>();
+
+ tl.pointlocator.AddAll(tl.lattice);
+
+ tl.pointlocator.Build();
+
+ tl.LookUp(lookups, 567);
+ }
+
+
+ public void BasicRun()
+ {
+ pointlocator.Test(-0.5, -0.5);
+ pointlocator.Test(-0.5, 0.5);
+ pointlocator.Test(-0.5, 1.5);
+ pointlocator.Test(0.5, -0.5);
+ pointlocator.Test(0.5, 0.5);
+ pointlocator.Test(0.5, 1.5);
+ pointlocator.Test(1.5, -0.5);
+ pointlocator.Test(1.5, 0.5);
+ pointlocator.Test(1.5, 1.5);
+ pointlocator.Test(1.5, 4.99);
+ pointlocator.Test(1.5, 5);
+ pointlocator.Test(1.5, 5.01);
+ pointlocator.Test(1.99, 4.99);
+ pointlocator.Test(1.99, 5);
+ pointlocator.Test(1.99, 5.01);
+ pointlocator.Test(2, 4.99);
+ pointlocator.Test(2, 5);
+ pointlocator.Test(2, 5.01);
+ pointlocator.Test(2.01, 4.99);
+ pointlocator.Test(2.01, 5);
+ pointlocator.Test(2.01, 5.01);
+ }
+ }
+ }
+
+ public class TestPointLocation {
+ public static void Main(String[] args) {
+ Test.TestUgly.Run(new String[0]);
+ }
+ }
+}
+
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/RandomSelection.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/RandomSelection.cs
new file mode 100644
index 00000000000..8049758ad67
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/RandomSelection.cs
@@ -0,0 +1,86 @@
+/*
+ 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.
+*/
+
+// C5 example: RandomSelection.cs for pattern chapter
+
+// Compile with
+// csc /r:C5.dll RandomSelection.cs
+
+using System;
+using C5;
+using SCG = System.Collections.Generic;
+
+namespace RandomSelection {
+ class RandomSelection {
+ public static void Main(String[] args) {
+ ArrayList<int> list = new ArrayList<int>(), copy1, copy2;
+ list.AddAll(new int[] { 2, 3, 5, 7, 11, 13, 17, 19 });
+ copy1 = (ArrayList<int>)list.Clone();
+ copy2 = (ArrayList<int>)list.Clone();
+ const int N = 7;
+ Console.WriteLine("-- With replacement:");
+ foreach (int x in RandomWith(list, N))
+ Console.Write("{0} ", x);
+ Console.WriteLine("\n-- Without replacement:");
+ foreach (int x in RandomWithout1(copy1, N))
+ Console.Write("{0} ", x);
+ Console.WriteLine("\n-- Without replacement:");
+ foreach (int x in RandomWithout2(copy2, N))
+ Console.Write("{0} ", x);
+ Console.WriteLine();
+ }
+
+ private static readonly C5Random rnd = new C5Random();
+
+ // Select N random items from coll, with replacement.
+ // Does not modify the given list.
+
+ public static SCG.IEnumerable<T> RandomWith<T>(IIndexed<T> coll, int N) {
+ for (int i=N; i>0; i--) {
+ T x = coll[rnd.Next(coll.Count)];
+ yield return x;
+ }
+ }
+
+ // Select N random items from list, without replacement.
+ // Modifies the given list.
+
+ public static SCG.IEnumerable<T> RandomWithout1<T>(IList<T> list, int N) {
+ list.Shuffle(rnd);
+ foreach (T x in list.View(0, N))
+ yield return x;
+ }
+
+ // Select N random items from list, without replacement.
+ // Faster when list is efficiently indexable and modifiable.
+ // Modifies the given list.
+
+ public static SCG.IEnumerable<T> RandomWithout2<T>(ArrayList<T> list, int N) {
+ for (int i=N; i>0; i--) {
+ int j = rnd.Next(list.Count);
+ T x = list[j], replacement = list.RemoveLast();
+ if (j < list.Count)
+ list[j] = replacement;
+ yield return x;
+ }
+ }
+ }
+}
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/ReadOnlyPatterns.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/ReadOnlyPatterns.cs
new file mode 100644
index 00000000000..feb3cf12ec8
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/ReadOnlyPatterns.cs
@@ -0,0 +1,96 @@
+/*
+ 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.
+*/
+
+// C5 example: ReadOnlyPatterns.cs for pattern chapter
+
+// Compile with
+// csc /r:C5.dll ReadOnlyPatterns.cs
+
+using System;
+using C5;
+using SCG = System.Collections.Generic;
+
+namespace ReadOnlyPatterns {
+ class ReadOnlyPatterns {
+ public static void Main(String[] args) {
+ GuardHashSet<int>();
+ GuardTreeSet<int>();
+ GuardList<int>();
+ GuardHashDictionary<int,int>();
+ GuardSortedDictionary<int,int>();
+ }
+
+ // Read-only access to a hash-based collection
+
+ static void GuardHashSet<T>() {
+ ICollection<T> coll = new HashSet<T>();
+ DoWork(new GuardedCollection<T>(coll));
+ }
+
+ static void DoWork<T>(ICollection<T> gcoll) {
+ // Use gcoll ...
+ }
+
+ // Read-only access to an indexed sorted collection
+
+ static void GuardTreeSet<T>() {
+ IIndexedSorted<T> coll = new TreeSet<T>();
+ DoWork(new GuardedIndexedSorted<T>(coll));
+ }
+
+ static void DoWork<T>(IIndexedSorted<T> gcoll) {
+ // Use gcoll ...
+ }
+
+ // Read-only access to a list
+
+ static void GuardList<T>() {
+ IList<T> coll = new ArrayList<T>();
+ DoWork(new GuardedList<T>(coll));
+ }
+
+ static void DoWork<T>(IList<T> gcoll) {
+ // Use gcoll ...
+ }
+
+ // Read-only access to a dictionary
+
+ static void GuardHashDictionary<K,V>() {
+ IDictionary<K,V> dict = new HashDictionary<K,V>();
+ DoWork(new GuardedDictionary<K,V>(dict));
+ }
+
+ static void DoWork<K,V>(IDictionary<K,V> gdict) {
+ // Use gdict ...
+ }
+
+ // Read-only access to a sorted dictionary
+
+ static void GuardSortedDictionary<K,V>() {
+ ISortedDictionary<K,V> dict = new TreeDictionary<K,V>();
+ DoWork(new GuardedSortedDictionary<K,V>(dict));
+ }
+
+ static void DoWork<K,V>(ISortedDictionary<K,V> gdict) {
+ // Use gdict ...
+ }
+ }
+}
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/Sets.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/Sets.cs
new file mode 100644
index 00000000000..0ddbeef7a06
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/Sets.cs
@@ -0,0 +1,175 @@
+/*
+ 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.
+*/
+
+// C5 example: functional sets 2004-12-21
+
+// Compile with
+// csc /r:C5.dll Sets.cs
+
+using System;
+using System.Text;
+using C5;
+using SCG = System.Collections.Generic;
+
+namespace Sets {
+ // The class of sets with item type T, implemented as a subclass of
+ // HashSet<T> but with functional infix operators * + - that compute
+ // intersection, union and difference functionally. That is, they
+ // create a new set object instead of modifying an existing one.
+ // The hasher is automatically created so that it is appropriate for
+ // T. In particular, this is true when T has the form Set<W> for
+ // some W, since Set<W> implements ICollectionValue<W>.
+
+ public class Set<T> : HashSet<T> {
+ public Set(SCG.IEnumerable<T> enm) : base() {
+ AddAll(enm);
+ }
+
+ public Set(params T[] elems) : this((SCG.IEnumerable<T>)elems) { }
+
+ // Set union (+), difference (-), and intersection (*):
+
+ public static Set<T> operator +(Set<T> s1, Set<T> s2) {
+ if (s1 == null || s2 == null)
+ throw new ArgumentNullException("Set+Set");
+ else {
+ Set<T> res = new Set<T>(s1);
+ res.AddAll(s2);
+ return res;
+ }
+ }
+
+ public static Set<T> operator -(Set<T> s1, Set<T> s2) {
+ if (s1 == null || s2 == null)
+ throw new ArgumentNullException("Set-Set");
+ else {
+ Set<T> res = new Set<T>(s1);
+ res.RemoveAll(s2);
+ return res;
+ }
+ }
+
+ public static Set<T> operator *(Set<T> s1, Set<T> s2) {
+ if (s1 == null || s2 == null)
+ throw new ArgumentNullException("Set*Set");
+ else {
+ Set<T> res = new Set<T>(s1);
+ res.RetainAll(s2);
+ return res;
+ }
+ }
+
+ // Equality of sets; take care to avoid infinite loops
+
+ public static bool operator ==(Set<T> s1, Set<T> s2) {
+ return EqualityComparer<Set<T>>.Default.Equals(s1, s2);
+ }
+
+ public static bool operator !=(Set<T> s1, Set<T> s2) {
+ return !(s1 == s2);
+ }
+
+ public override bool Equals(Object that) {
+ return this == (that as Set<T>);
+ }
+
+ public override int GetHashCode() {
+ return EqualityComparer<Set<T>>.Default.GetHashCode(this);
+ }
+
+ // Subset (<=) and superset (>=) relation:
+
+ public static bool operator <=(Set<T> s1, Set<T> s2) {
+ if (s1 == null || s2 == null)
+ throw new ArgumentNullException("Set<=Set");
+ else
+ return s1.ContainsAll(s2);
+ }
+
+ public static bool operator >=(Set<T> s1, Set<T> s2) {
+ if (s1 == null || s2 == null)
+ throw new ArgumentNullException("Set>=Set");
+ else
+ return s2.ContainsAll(s1);
+ }
+
+ public override String ToString() {
+ StringBuilder sb = new StringBuilder();
+ sb.Append("{");
+ bool first = true;
+ foreach (T x in this) {
+ if (!first)
+ sb.Append(",");
+ sb.Append(x);
+ first = false;
+ }
+ sb.Append("}");
+ return sb.ToString();
+ }
+ }
+
+ class MyTest {
+ public static void Main(String[] args) {
+ Set<int> s1 = new Set<int>(2, 3, 5, 7, 11);
+ Set<int> s2 = new Set<int>(2, 4, 6, 8, 10);
+ Console.WriteLine("s1 + s2 = {0}", s1 + s2);
+ Console.WriteLine("s1 * s2 = {0}", s1 * s2);
+ Console.WriteLine("s1 - s2 = {0}", s1 - s2);
+ Console.WriteLine("s1 - s1 = {0}", s1 - s1);
+ Console.WriteLine("s1 + s1 == s1 is {0}", s1 + s1 == s1);
+ Console.WriteLine("s1 * s1 == s1 is {0}", s1 * s1 == s1);
+ Set<Set<int>> ss1 = new Set<Set<int>>(s1, s2, s1 + s2);
+ Console.WriteLine("ss1 = {0}", ss1);
+ Console.WriteLine("IntersectionClose(ss1) = {0}", IntersectionClose(ss1));
+ Set<Set<int>> ss2 =
+ new Set<Set<int>>(new Set<int>(2, 3), new Set<int>(1, 3), new Set<int>(1, 2));
+ Console.WriteLine("ss2 = {0}", ss2);
+ Console.WriteLine("IntersectionClose(ss2) = {0}", IntersectionClose(ss2));
+ }
+
+ // Given a set SS of sets of Integers, compute its intersection
+ // closure, that is, the least set TT such that SS is a subset of TT
+ // and such that for any two sets t1 and t2 in TT, their
+ // intersection is also in TT.
+
+ // For instance, if SS is {{2,3}, {1,3}, {1,2}},
+ // then TT is {{2,3}, {1,3}, {1,2}, {3}, {2}, {1}, {}}.
+
+ // Both the argument and the result is a Set<Set<int>>
+
+ static Set<Set<T>> IntersectionClose<T>(Set<Set<T>> ss) {
+ IQueue<Set<T>> worklist = new CircularQueue<Set<T>>();
+ foreach (Set<T> s in ss)
+ worklist.Enqueue(s);
+ HashSet<Set<T>> tt = new HashSet<Set<T>>();
+ while (worklist.Count != 0) {
+ Set<T> s = worklist.Dequeue();
+ foreach (Set<T> t in tt) {
+ Set<T> ts = t * s;
+ if (!tt.Contains(ts))
+ worklist.Enqueue(ts);
+ }
+ tt.Add(s);
+ }
+ return new Set<Set<T>>((SCG.IEnumerable<Set<T>>)tt);
+ }
+ }
+}
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/SortedIterationPatterns.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/SortedIterationPatterns.cs
new file mode 100644
index 00000000000..5bfe072e3a5
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/SortedIterationPatterns.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.
+*/
+
+// C5 example: SortedIterationPatterns.cs for pattern chapter
+
+// Compile with
+// csc /r:C5.dll SortedIterationPatterns.cs
+
+using System;
+using C5;
+using SCG = System.Collections.Generic;
+
+namespace SortedIterationPatterns {
+ class SortedIterationPatterns {
+ public static void Main(String[] args) {
+ ISorted<int> sorted = new TreeSet<int>();
+ sorted.AddAll(new int[] { 23, 29, 31, 37, 41, 43, 47, 53 });
+ Console.WriteLine(sorted);
+ if (args.Length == 1) {
+ int n = int.Parse(args[0]);
+ int res;
+ if (Predecessor(sorted, n, out res))
+ Console.WriteLine("{0} has predecessor {1}", n, res);
+ if (WeakPredecessor(sorted, n, out res))
+ Console.WriteLine("{0} has weak predecessor {1}", n, res);
+ if (Successor(sorted, n, out res))
+ Console.WriteLine("{0} has successor {1}", n, res);
+ if (WeakSuccessor(sorted, n, out res))
+ Console.WriteLine("{0} has weak successor {1}", n, res);
+ }
+ IterBeginEnd(sorted);
+ IterBeginEndBackwards(sorted);
+ IterIncExc(sorted, 29, 47);
+ IterIncExcBackwards(sorted, 29, 47);
+ IterIncEnd(sorted, 29);
+ IterBeginExc(sorted, 47);
+ IterIncInc(sorted, 29, 47);
+ IterBeginInc(sorted, 47);
+ IterExcExc(sorted, 29, 47);
+ IterExcEnd(sorted, 29);
+ IterExcInc(sorted, 29, 47);
+ }
+
+ // --- Predecessor and successor patterns --------------------
+
+ // Find weak successor of y in coll, or return false
+
+ public static bool WeakSuccessor<T>(ISorted<T> coll, T y, out T ySucc)
+ where T : IComparable<T>
+ {
+ T yPred;
+ bool hasPred, hasSucc,
+ hasY = coll.Cut(y, out yPred, out hasPred, out ySucc, out hasSucc);
+ if (hasY)
+ ySucc = y;
+ return hasY || hasSucc;
+ }
+
+ // Find weak predecessor of y in coll, or return false
+
+ public static bool WeakPredecessor<T>(ISorted<T> coll, T y, out T yPred)
+ where T : IComparable<T>
+ {
+ T ySucc;
+ bool hasPred, hasSucc,
+ hasY = coll.Cut(y, out yPred, out hasPred, out ySucc, out hasSucc);
+ if (hasY)
+ yPred = y;
+ return hasY || hasPred;
+ }
+
+ // Find (strict) successor of y in coll, or return false
+
+ public static bool Successor<T>(ISorted<T> coll, T y, out T ySucc)
+ where T : IComparable<T>
+ {
+ bool hasPred, hasSucc;
+ T yPred;
+ coll.Cut(y, out yPred, out hasPred, out ySucc, out hasSucc);
+ return hasSucc;
+ }
+
+ // Find (strict) predecessor of y in coll, or return false
+
+ public static bool Predecessor<T>(ISorted<T> coll, T y, out T yPred)
+ where T : IComparable<T>
+ {
+ bool hasPred, hasSucc;
+ T ySucc;
+ coll.Cut(y, out yPred, out hasPred, out ySucc, out hasSucc);
+ return hasPred;
+ }
+
+ // --- Sorted iteration patterns -----------------------------
+
+ // Iterate over all items
+
+ public static void IterBeginEnd<T>(ISorted<T> coll) {
+ foreach (T x in coll) {
+ Console.Write("{0} ", x);
+ }
+ Console.WriteLine();
+ }
+
+ // Iterate over all items, backwards
+
+ public static void IterBeginEndBackwards<T>(ISorted<T> coll) {
+ foreach (T x in coll.Backwards()) {
+ Console.Write("{0} ", x);
+ }
+ Console.WriteLine();
+ }
+
+ // Iterate over [x1,x2[
+
+ public static void IterIncExc<T>(ISorted<T> coll, T x1, T x2) {
+ foreach (T x in coll.RangeFromTo(x1, x2)) {
+ Console.Write("{0} ", x);
+ }
+ Console.WriteLine();
+ }
+
+ // Iterate over [x1,x2[, backwards
+
+ public static void IterIncExcBackwards<T>(ISorted<T> coll, T x1, T x2) {
+ foreach (T x in coll.RangeFromTo(x1, x2).Backwards()) {
+ Console.Write("{0} ", x);
+ }
+ Console.WriteLine();
+ }
+
+ // Iterate over [x1...]
+
+ public static void IterIncEnd<T>(ISorted<T> coll, T x1) {
+ foreach (T x in coll.RangeFrom(x1)) {
+ Console.Write("{0} ", x);
+ }
+ Console.WriteLine();
+ }
+
+ // Iterate over [...x2[
+
+ public static void IterBeginExc<T>(ISorted<T> coll, T x2) {
+ foreach (T x in coll.RangeTo(x2)) {
+ Console.Write("{0} ", x);
+ }
+ Console.WriteLine();
+ }
+
+ // Iterate over [x1...x2]
+
+ public static void IterIncInc<T>(ISorted<T> coll, T x1, T x2)
+ where T : IComparable<T>
+ {
+ T x2Succ;
+ bool x2HasSucc = Successor(coll, x2, out x2Succ);
+ IDirectedEnumerable<T> range =
+ x2HasSucc ? coll.RangeFromTo(x1, x2Succ) : coll.RangeFrom(x1);
+ foreach (T x in range) {
+ Console.Write("{0} ", x);
+ }
+ Console.WriteLine();
+ }
+
+ // Iterate over [...x2]
+
+ public static void IterBeginInc<T>(ISorted<T> coll, T x2)
+ where T : IComparable<T>
+ {
+ T x2Succ;
+ bool x2HasSucc = Successor(coll, x2, out x2Succ);
+ IDirectedEnumerable<T> range =
+ x2HasSucc ? coll.RangeTo(x2Succ) : coll.RangeAll();
+ foreach (T x in range) {
+ Console.Write("{0} ", x);
+ }
+ Console.WriteLine();
+ }
+
+ // Iterate over ]x1...x2[
+
+ public static void IterExcExc<T>(ISorted<T> coll, T x1, T x2)
+ where T : IComparable<T>
+ {
+ T x1Succ;
+ bool x1HasSucc = Successor(coll, x1, out x1Succ);
+ IDirectedEnumerable<T> range =
+ x1HasSucc ? coll.RangeFromTo(x1Succ, x2) : new ArrayList<T>();
+ foreach (T x in range) {
+ Console.Write("{0} ", x);
+ }
+ Console.WriteLine();
+ }
+
+ // Iterate over ]x1...]
+
+ public static void IterExcEnd<T>(ISorted<T> coll, T x1)
+ where T : IComparable<T>
+ {
+ T x1Succ;
+ bool x1HasSucc = Successor(coll, x1, out x1Succ);
+ IDirectedEnumerable<T> range =
+ x1HasSucc ? coll.RangeFrom(x1Succ) : new ArrayList<T>();
+ foreach (T x in range) {
+ Console.Write("{0} ", x);
+ }
+ Console.WriteLine();
+ }
+
+ // Iterate over ]x1...x2]
+
+ public static void IterExcInc<T>(ISorted<T> coll, T x1, T x2)
+ where T : IComparable<T>
+ {
+ T x1Succ, x2Succ;
+ bool x1HasSucc = Successor(coll, x1, out x1Succ),
+ x2HasSucc = Successor(coll, x2, out x2Succ);
+ IDirectedEnumerable<T> range =
+ x1HasSucc ? (x2HasSucc ? coll.RangeFromTo(x1Succ, x2Succ)
+ : coll.RangeFrom(x1Succ))
+ : new ArrayList<T>();
+ foreach (T x in range) {
+ Console.Write("{0} ", x);
+ }
+ Console.WriteLine();
+ }
+
+ }
+}
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/SortingPermutation.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/SortingPermutation.cs
new file mode 100644
index 00000000000..83c135012b7
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/SortingPermutation.cs
@@ -0,0 +1,80 @@
+// C5 example
+// 2004-11
+
+using System;
+using C5;
+using SCG = System.Collections.Generic;
+
+namespace SortingPermutation
+{
+ class MyTest
+ {
+ public static void Main(String[] args)
+ {
+ String[] cities =
+ { "Tokyo", "Beijing", "Hangzhou", "Kyoto", "Beijing", "Copenhagen", "Seattle" };
+ IList<String> alst = new ArrayList<String>();
+ alst.AddAll<String>(cities);
+ foreach (int i in MySort.GetPermutation1(alst))
+ Console.Write("{0} ", i);
+ Console.WriteLine();
+ IList<String> llst = new LinkedList<String>();
+ llst.AddAll<String>(cities);
+ foreach (int i in MySort.GetPermutation2(llst))
+ Console.Write("{0} ", i);
+ Console.WriteLine();
+ Console.WriteLine("The rank of the cities:");
+ ArrayList<int> res = MySort.GetPermutation1(MySort.GetPermutation2(llst));
+ foreach (int i in res)
+ Console.Write("{0} ", i);
+ Console.WriteLine();
+ }
+ }
+
+ class MySort
+ {
+ // Fast for array lists and similar, but not stable; slow for linked lists
+
+ public static ArrayList<int> GetPermutation1<T>(IList<T> lst)
+ where T : IComparable<T>
+ {
+ ArrayList<int> res = new ArrayList<int>(lst.Count);
+ for (int i = 0; i < lst.Count; i++)
+ res.Add(i);
+ res.Sort(new DelegateComparer<int>
+ (delegate(int i, int j) { return lst[i].CompareTo(lst[j]); }));
+ return res;
+ }
+
+ // Stable and fairly fast both for array lists and linked lists,
+ // but does copy the collection's items.
+
+ public static ArrayList<int> GetPermutation2<T>(IList<T> lst)
+ where T : IComparable<T>
+ {
+ int i = 0;
+ IList<KeyValuePair<T, int>> zipList =
+ lst.Map<KeyValuePair<T, int>>
+ (delegate(T x) { return new KeyValuePair<T, int>(x, i++); });
+ zipList.Sort(new KeyValueComparer<T>(lst));
+ ArrayList<int> res = new ArrayList<int>(lst.Count);
+ foreach (KeyValuePair<T, int> p in zipList)
+ res.Add(p.Value);
+ return res;
+ }
+
+ private class KeyValueComparer<T> : SCG.IComparer<KeyValuePair<T, int>>
+ where T : IComparable<T>
+ {
+ private readonly IList<T> lst;
+ public KeyValueComparer(IList<T> lst)
+ {
+ this.lst = lst;
+ }
+ public int Compare(KeyValuePair<T, int> p1, KeyValuePair<T, int> p2)
+ {
+ return p1.Key.CompareTo(p2.Key);
+ }
+ }
+ }
+}
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/TestSortedArray.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/TestSortedArray.cs
new file mode 100644
index 00000000000..15a814b4bc0
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/TestSortedArray.cs
@@ -0,0 +1,37 @@
+/*
+ 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.
+*/
+
+// C5 example: anagrams 2004-12-08
+
+// Compile with
+// csc /r:C5.dll TestSortedArray.cs
+
+using System;
+using C5;
+using SCG = System.Collections.Generic;
+
+namespace TestSortedArray {
+ class TestSortedArray {
+ public static void Main(String[] args) {
+ SortedArray<Object> sarr = new SortedArray<Object>();
+ }
+ }
+}
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/ThisFun.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/ThisFun.cs
new file mode 100644
index 00000000000..1fd29f1c122
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/ThisFun.cs
@@ -0,0 +1,46 @@
+// Experiment: implicit conversion of indexer to function
+// sestoft@dina.kvl.dk * 2005-11-08
+
+using System;
+using C5;
+
+class MyFunTest {
+ public static void Main(String[] args) {
+ FooBar fb = new FooBar();
+ IList<int> list = new LinkedList<int>();
+ list.AddAll(new int[] { 2, 3, 5, 7, 11 });
+ list.Map<double>(fb).Apply(Console.WriteLine);
+ list.Apply(fb);
+ }
+}
+
+class FooBar {
+ public double this[int x] {
+ get {
+ Console.WriteLine(x);
+ return x + 1.5;
+ }
+ }
+
+ public Fun<int,double> Fun {
+ get {
+ return delegate(int x) { return this[x]; };
+ }
+ }
+
+ public Act<int> Act {
+ get {
+ return delegate(int x) { double junk = this[x]; };
+ }
+ }
+
+ public static implicit operator Fun<int,double>(FooBar fb) {
+ return delegate(int x) { return fb[x]; };
+ }
+
+ public static implicit operator Act<int>(FooBar fb) {
+ return delegate(int x) { double junk = fb[x]; };
+ }
+}
+
+
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/Toposort.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/Toposort.cs
new file mode 100644
index 00000000000..e078f6a5bee
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/Toposort.cs
@@ -0,0 +1,139 @@
+/*
+ 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.
+*/
+
+// C5 example: topological sorting 2005-09-09
+
+// Compile with
+// csc /r:C5.dll Toposort.cs
+
+using System;
+using System.Text;
+using C5;
+using SCG = System.Collections.Generic;
+using SDD = System.Diagnostics.Debug;
+
+namespace Toposort {
+ class TestToposort {
+ public static void Main(String[] args) {
+ Node<String>
+ d = new Node<String>("d"),
+ e = new Node<String>("e"),
+ c = new Node<String>("c", d, e),
+ b = new Node<String>("b", d),
+ a = new Node<String>("a", d, b, c);
+ foreach (Node<String> n in Toposort0(a))
+ Console.WriteLine(n);
+ Console.WriteLine();
+ foreach (Node<String> n in Toposort1(a))
+ Console.WriteLine(n);
+ Console.WriteLine();
+ foreach (Node<String> n in Toposort2(a))
+ Console.WriteLine(n);
+ }
+
+ // Toposort 0, adding each node when finished, after its descendants.
+ // Classic depth-first search. Does not terminate on cyclic graphs.
+
+ public static IList<Node<T>> Toposort0<T>(params Node<T>[] starts) {
+ HashedLinkedList<Node<T>> sorted = new HashedLinkedList<Node<T>>();
+ foreach (Node<T> start in starts)
+ if (!sorted.Contains(start))
+ AddNode0(sorted, start);
+ return sorted;
+ }
+
+ private static void AddNode0<T>(IList<Node<T>> sorted, Node<T> node) {
+ SDD.Assert(!sorted.Contains(node));
+ foreach (Node<T> child in node.children)
+ if (!sorted.Contains(child))
+ AddNode0(sorted, child);
+ sorted.InsertLast(node);
+ }
+
+ // Toposort 1, using hash index to add each node before its descendants.
+ // Terminates also on cyclic graphs.
+
+ public static IList<Node<T>> Toposort1<T>(params Node<T>[] starts) {
+ HashedLinkedList<Node<T>> sorted = new HashedLinkedList<Node<T>>();
+ foreach (Node<T> start in starts)
+ if (!sorted.Contains(start)) {
+ sorted.InsertLast(start);
+ AddNode1(sorted, start);
+ }
+ return sorted;
+ }
+
+ private static void AddNode1<T>(IList<Node<T>> sorted, Node<T> node) {
+ SDD.Assert(sorted.Contains(node));
+ foreach (Node<T> child in node.children)
+ if (!sorted.Contains(child)) {
+ sorted.ViewOf(node).InsertFirst(child);
+ AddNode1(sorted, child);
+ }
+ }
+
+ // Toposort 2, node rescanning using a view.
+ // Uses no method call stack and no extra data structures, but slower.
+
+ public static IList<Node<T>> Toposort2<T>(params Node<T>[] starts) {
+ HashedLinkedList<Node<T>> sorted = new HashedLinkedList<Node<T>>();
+ foreach (Node<T> start in starts)
+ if (!sorted.Contains(start)) {
+ sorted.InsertLast(start);
+ using (IList<Node<T>> cursor = sorted.View(sorted.Count-1,1)) {
+ do {
+ Node<T> child;
+ while (null != (child = PendingChild(sorted, cursor.First))) {
+ cursor.InsertFirst(child);
+ cursor.Slide(0,1);
+ }
+ } while (cursor.TrySlide(+1));
+ }
+ }
+ return sorted;
+ }
+
+ static Node<T> PendingChild<T>(IList<Node<T>> sorted, Node<T> node) {
+ foreach (Node<T> child in node.children)
+ if (!sorted.Contains(child))
+ return child;
+ return null;
+ }
+ }
+
+ class Node<T> {
+ public readonly T id;
+ public readonly Node<T>[] children;
+
+ public Node(T id, params Node<T>[] children) {
+ this.id = id; this.children = children;
+ }
+
+ public override String ToString() {
+ return id.ToString();
+ }
+
+ public Node<T> this[int i] {
+ set { children[i] = value; }
+ get { return children[i]; }
+ }
+ }
+}
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/TreeTraversal.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/TreeTraversal.cs
new file mode 100644
index 00000000000..0fbc2478aec
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/TreeTraversal.cs
@@ -0,0 +1,107 @@
+// C5 example
+// 2004-11-09
+
+using System;
+using C5;
+using SCG = System.Collections.Generic;
+
+namespace TreeTraversal
+{
+ class MyTest
+ {
+ public static void Main(String[] args)
+ {
+ Tree<int> t = MakeTree(1, 15);
+ Act<int> act = delegate(int val) { Console.Write("{0} ", val); };
+ Console.WriteLine("Depth-first:");
+ Tree<int>.DepthFirst(t, act);
+ Console.WriteLine("\nBreadth-first:");
+ Tree<int>.BreadthFirst(t, act);
+ Console.WriteLine("\nDepth-first:");
+ Tree<int>.Traverse(t, act, new ArrayList<Tree<int>>());
+ Console.WriteLine("\nBreadth-first:");
+ Tree<int>.Traverse(t, act, new LinkedList<Tree<int>>());
+ Console.WriteLine();
+ }
+
+ // Build n-node tree with root numbered b and other nodes numbered b+1..b+n
+ public static Tree<int> MakeTree(int b, int n)
+ {
+ if (n == 0)
+ return null;
+ else
+ {
+ int k = n / 2;
+ Tree<int> t1 = MakeTree(b + 1, k), t2 = MakeTree(b + k + 1, n - 1 - k);
+ return new Tree<int>(b, t1, t2);
+ }
+ }
+ }
+
+ class Tree<T>
+ {
+ private T val;
+ private Tree<T> t1, t2;
+ public Tree(T val) : this(val, null, null) { }
+ public Tree(T val, Tree<T> t1, Tree<T> t2)
+ {
+ this.val = val; this.t1 = t1; this.t2 = t2;
+ }
+
+ public static void DepthFirst(Tree<T> t, Act<T> act)
+ {
+ IStack<Tree<T>> work = new ArrayList<Tree<T>>();
+ work.Push(t);
+ while (!work.IsEmpty)
+ {
+ Tree<T> cur = work.Pop();
+ if (cur != null)
+ {
+ work.Push(cur.t2);
+ work.Push(cur.t1);
+ act(cur.val);
+ }
+ }
+ }
+
+ public static void BreadthFirst(Tree<T> t, Act<T> act)
+ {
+ IQueue<Tree<T>> work = new CircularQueue<Tree<T>>();
+ work.Enqueue(t);
+ while (!work.IsEmpty)
+ {
+ Tree<T> cur = work.Dequeue();
+ if (cur != null)
+ {
+ work.Enqueue(cur.t1);
+ work.Enqueue(cur.t2);
+ act(cur.val);
+ }
+ }
+ }
+
+ public static void Traverse(Tree<T> t, Act<T> act, IList<Tree<T>> work)
+ {
+ work.Clear();
+ work.Add(t);
+ while (!work.IsEmpty)
+ {
+ Tree<T> cur = work.Remove();
+ if (cur != null)
+ {
+ if (work.FIFO)
+ {
+ work.Add(cur.t1);
+ work.Add(cur.t2);
+ }
+ else
+ {
+ work.Add(cur.t2);
+ work.Add(cur.t1);
+ }
+ act(cur.val);
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/Try.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/Try.cs
new file mode 100644
index 00000000000..6617ffad48d
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/Try.cs
@@ -0,0 +1,64 @@
+/*
+ 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.
+*/
+
+// C5 example: various tests 2005-01-01
+
+// Compile with
+// csc /r:C5.dll Try.cs
+
+using System;
+using System.Text;
+using C5;
+using SCG = System.Collections.Generic;
+
+namespace Try
+{
+ class MyTest
+ {
+ public static void Main()
+ {
+ IList<bool> list = new ArrayList<bool>();
+ list.AddAll(new bool[] { false, false, true, true, false });
+ list.CollectionCleared
+ += delegate(Object coll, ClearedEventArgs args) {
+ ClearedRangeEventArgs crargs = args as ClearedRangeEventArgs;
+ if (crargs != null) {
+ Console.WriteLine("Cleared {0} to {1}",
+ crargs.Start, crargs.Start+crargs.Count-1);
+ } else {
+ Console.WriteLine("Cleared {0} items", args.Count);
+ }
+ };
+ list.RemoveInterval(2, 2);
+ HashSet<int> hash = new HashSet<int>();
+ hash.ItemsRemoved
+ += delegate {
+ Console.WriteLine("Item was removed");
+ };
+ hash.ItemsAdded
+ += delegate {
+ Console.WriteLine("Item was added");
+ };
+ hash.UpdateOrAdd(2);
+ hash.UpdateOrAdd(2);
+ }
+ }
+}
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/UserGuideExamples.csproj b/mcs/class/Mono.C5/1.0/UserGuideExamples/UserGuideExamples.csproj
new file mode 100644
index 00000000000..f2559711fd9
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/UserGuideExamples.csproj
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>8.0.50727</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{B2A29FF2-A5C5-4F07-8CE7-FF5D744D7562}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <RootNamespace>UserGuideExamples</RootNamespace>
+ <AssemblyName>UserGuideExamples</AssemblyName>
+ <WarningLevel>4</WarningLevel>
+ <StartupObject>
+ </StartupObject>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>.\bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugSymbols>false</DebugSymbols>
+ <Optimize>true</Optimize>
+ <OutputPath>.\bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="AnagramHashBag.cs" />
+ <Compile Include="Anagrams.cs" />
+ <Compile Include="AnagramStrings.cs" />
+ <Compile Include="AnagramTreeBag.cs" />
+ <Compile Include="Antipatterns.cs" />
+ <Compile Include="Cloning.cs" />
+ <Compile Include="CollectionCollection.cs" />
+ <Compile Include="CollectionSanity.cs" />
+ <Compile Include="EventPatterns.cs" />
+ <Compile Include="GettingStarted.cs" />
+ <Compile Include="Graph.cs" />
+ <Compile Include="Fileindex.cs" />
+ <Compile Include="GCHForm.cs">
+ <SubType>Form</SubType>
+ </Compile>
+ <Compile Include="GConvexHull.cs" />
+ <Compile Include="GNfaToDfa.cs" />
+ <Compile Include="HashCodes.cs" />
+ <Compile Include="Jobqueue.cs" />
+ <Compile Include="KeywordRecognition.cs" />
+ <Compile Include="ListPatterns.cs" />
+ <Compile Include="Locking.cs" />
+ <Compile Include="MultiCollection.cs" />
+ <Compile Include="MultiDictionary.cs" />
+ <Compile Include="PointLocation.cs" />
+ <Compile Include="RandomSelection.cs" />
+ <Compile Include="ReadOnlyPatterns.cs" />
+ <Compile Include="Sets.cs" />
+ <Compile Include="SortedIterationPatterns.cs" />
+ <Compile Include="SortingPermutation.cs" />
+ <Compile Include="TestSortedArray.cs" />
+ <Compile Include="ThisFun.cs" />
+ <Compile Include="Toposort.cs" />
+ <Compile Include="TreeTraversal.cs" />
+ <Compile Include="Try.cs" />
+ <Compile Include="ViewPatterns.cs" />
+ <Compile Include="Views.cs" />
+ <Compile Include="WrappedArray.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <EmbeddedResource Include="GCHForm.resx">
+ <DependentUpon>GCHForm.cs</DependentUpon>
+ </EmbeddedResource>
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\C5\C5.csproj">
+ <Project>{D70489CD-ABDA-48FF-BD1E-BE3F7495BE71}</Project>
+ <Package>{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</Package>
+ <Name>C5</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="Makefile" />
+ </ItemGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Drawing" />
+ <Reference Include="System.Windows.Forms" />
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSHARP.Targets" />
+</Project> \ No newline at end of file
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/ViewPatterns.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/ViewPatterns.cs
new file mode 100644
index 00000000000..c1330ed6f10
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/ViewPatterns.cs
@@ -0,0 +1,340 @@
+/*
+ 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.
+*/
+
+// C5 example: ViewPatterns 2005-07-22
+
+// Compile with
+// csc /r:C5.dll ViewPatterns.cs
+
+using System;
+using C5;
+using SCG = System.Collections.Generic;
+
+namespace ViewPatterns {
+ class Views {
+ public static void Main(String[] args) {
+ IList<char> lst = new ArrayList<char>();
+ lst.AddAll<char>(new char[] { 'a', 'b', 'c', 'd' });
+ IList<char> v1 = lst.View(1, 1);
+ Console.WriteLine("v1 = {0}", v1);
+ InsertBeforeFirst(v1, '<', 'b');
+ InsertAfterFirst(v1, '>', 'b');
+ Console.WriteLine("v1 = {0}", v1);
+ char x;
+ if (SequencePredecessor(v1, 'b', out x))
+ Console.WriteLine("Predecessor of b is " + x);
+ if (SequenceSuccessor(v1, 'b', out x))
+ Console.WriteLine("Successor of b is " + x);
+ if (!SequencePredecessor(v1, 'c', out x))
+ Console.WriteLine("c has no predecessor");
+ if (!SequenceSuccessor(v1, 'a', out x))
+ Console.WriteLine("a has no successor");
+ IList<char> lst2 = new ArrayList<char>();
+ lst2.AddAll<char>(new char[] { 'a', 'b', 'c', 'A', 'a', 'd', 'a' });
+ foreach (int i in IndexesOf(lst2, 'a'))
+ Console.Write("{0} ", i);
+ Console.WriteLine();
+ foreach (int i in ReverseIndexesOf(lst2, 'a'))
+ Console.Write("{0} ", i);
+ Console.WriteLine();
+ Console.WriteLine(lst2);
+ IList<char> view = lst2.View(2,0);
+ InsertAtView(lst2, view, 'y');
+ Console.WriteLine(lst2);
+ InsertIntoView(view, 'x');
+ Console.WriteLine(lst2);
+ }
+
+ // --- Patterns for zero-item views -----------------------------
+
+ // Number of items before zero-item view
+
+ public static int ItemsBefore<T>(IList<T> view) {
+ return view.Offset;
+ }
+
+ // Number of items after zero-item view
+
+ public static int ItemsAfter<T>(IList<T> view) {
+ return view.Underlying.Count - view.Offset;
+ }
+
+ // Move (zero-item) view one item to the left
+
+ public static void MoveLeft<T>(IList<T> view) {
+ // One of these:
+ view.Slide(-1);
+ view.TrySlide(-1);
+ }
+
+ // Move (zero-item) view one item to the right
+
+ public static void MoveRight<T>(IList<T> view) {
+ // One of these:
+ view.Slide(+1);
+ view.TrySlide(+1);
+ }
+
+ // Test whether (zero-item) view is at beginning of list
+
+ public static bool AtBeginning<T>(IList<T> view) {
+ return view.Offset == 0;
+ }
+
+ // Test whether (zero-item) view is at end of list
+
+ public static bool AtEnd<T>(IList<T> view) {
+ return view.Offset == view.Underlying.Count;
+ }
+
+ // Insert x into zero-item view and into underlying list
+
+ public static void InsertIntoView<T>(IList<T> view, T x) {
+ view.Add(x);
+ }
+
+ // Insert x into list at zero-item view
+
+ public static void InsertAtView<T>(IList<T> list, IList<T> view, T x) {
+ list.Insert(view, x);
+ }
+
+ // Delete the item before zero-item view
+
+ public static void DeleteBefore<T>(IList<T> view) {
+ view.Slide(-1,1).RemoveFirst();
+ }
+
+ // Delete the item after zero-item view
+
+ public static void DeleteAfter<T>(IList<T> view) {
+ view.Slide(0,1).RemoveFirst();
+ }
+
+ // Get the zero-item view at left endpoint. Succeeds on all lists
+ // and valid views.
+
+ public static IList<T> LeftEndView<T>(IList<T> list) {
+ return list.View(0,0);
+ }
+
+ // Get the zero-item view at right endpoint. Succeeds on all
+ // lists and valid views.
+
+ public static IList<T> RightEndView<T>(IList<T> list) {
+ return list.View(list.Count,0);
+ }
+
+
+ // --- Patterns for one-item views ------------------------------
+
+ // Find the sequence predecessor x of y; or throw exception
+
+ public static T SequencePredecessor<T>(IList<T> list, T y) {
+ return list.ViewOf(y).Slide(-1)[0];
+ }
+
+ // Find the sequence predecessor x of y; or return false
+
+ public static bool SequencePredecessor<T>(IList<T> list, T y, out T x) {
+ IList<T> view = list.ViewOf(y);
+ bool ok = view != null && view.TrySlide(-1);
+ x = ok ? view[0] : default(T);
+ return ok;
+ }
+
+ // Find the sequence successor x of y; or throw exception
+
+ public static T SequenceSuccessor<T>(IList<T> list, T y) {
+ return list.ViewOf(y).Slide(+1)[0];
+ }
+
+ // Find the sequence successor x of y; or return false
+
+ public static bool SequenceSuccessor<T>(IList<T> list, T y, out T x) {
+ IList<T> view = list.ViewOf(y);
+ bool ok = view != null && view.TrySlide(+1);
+ x = ok ? view[0] : default(T);
+ return ok;
+ }
+
+ // Insert x into list after first occurrence of y (or throw
+ // NullReferenceException).
+
+ public static void InsertAfterFirst<T>(IList<T> list, T x, T y) {
+ list.Insert(list.ViewOf(y), x);
+ }
+
+ // Insert x into list before first occurrence of y (or throw
+ // NullReferenceException)
+
+ public static void InsertBeforeFirst<T>(IList<T> list, T x, T y) {
+ list.Insert(list.ViewOf(y).Slide(0, 0), x);
+ }
+
+ // Insert x into list after last occurrence of y (or throw
+ // NullReferenceException).
+
+ public static void InsertAfterLast<T>(IList<T> list, T x, T y) {
+ list.Insert(list.LastViewOf(y), x);
+ }
+
+ // Insert x into list before last occurrence of y (or throw
+ // NullReferenceException)
+
+ public static void InsertBeforeLast<T>(IList<T> list, T x, T y) {
+ list.Insert(list.LastViewOf(y).Slide(0, 0), x);
+ }
+
+ // Same meaning as InsertBeforeFirst on a proper list, but not on
+ // a view
+
+ public static void InsertBeforeFirstAlt<T>(IList<T> list, T x, T y) {
+ list.ViewOf(y).InsertFirst(x);
+ }
+
+ // Delete the sequence predecessor of first y; or throw exception
+
+ public static T RemovePredecessorOfFirst<T>(IList<T> list, T y) {
+ return list.ViewOf(y).Slide(-1).Remove();
+ }
+
+ // Delete the sequence successor of first y; or throw exception
+
+ public static T RemoveSuccessorOfFirst<T>(IList<T> list, T y) {
+ return list.ViewOf(y).Slide(+1).Remove();
+ }
+
+ // --- Other view patterns --------------------------------------
+
+ // Replace the first occurrence of each x from xs by y in list:
+
+ public static void ReplaceXsByY<T>(HashedLinkedList<T> list, T[] xs, T y) {
+ foreach (T x in xs) {
+ using (IList<T> view = list.ViewOf(x)) {
+ if (view != null) {
+ view.Remove();
+ view.Add(y);
+ }
+ }
+ }
+ }
+
+ // Get index in underlying list of view's left end
+
+ public static int LeftEndIndex<T>(IList<T> view) {
+ return view.Offset;
+ }
+
+ // Get index in underlying list of view's right end
+
+ public static int RightEndIndex<T>(IList<T> view) {
+ return view.Offset + view.Count;
+ }
+
+ // Test whether views overlap
+
+ public static bool Overlap<T>(IList<T> u, IList<T> w) {
+ if (u.Underlying == null || u.Underlying != w.Underlying)
+ throw new ArgumentException("views must have same underlying list");
+ else
+ return u.Offset < w.Offset+w.Count && w.Offset < u.Offset+u.Count;
+ }
+
+ // Find the length of the overlap between two views
+
+ public static int OverlapLength<T>(IList<T> u, IList<T> w) {
+ if (Overlap(u, w))
+ return Math.Min(u.Offset+u.Count, w.Offset+w.Count)
+ - Math.Max(u.Offset, w.Offset);
+ else
+ return -1; // No overlap
+ }
+
+ // Test whether view u contains view v
+
+ public static bool ContainsView<T>(IList<T> u, IList<T> w) {
+ if (u.Underlying == null || u.Underlying != w.Underlying)
+ throw new ArgumentException("views must have same underlying list");
+ else
+ if (w.Count > 0)
+ return u.Offset <= w.Offset && w.Offset+w.Count <= u.Offset+u.Count;
+ else
+ return u.Offset < w.Offset && w.Offset < u.Offset+u.Count;
+ }
+
+ // Test whether views u and v have (or are) the same underlying list
+
+ public static bool SameUnderlying<T>(IList<T> u, IList<T> w) {
+ return (u.Underlying ?? u) == (w.Underlying ?? w);
+ }
+
+ // Find the index of the first item that satisfies p
+
+ public static int FindFirstIndex<T>(IList<T> list, Fun<T,bool> p) {
+ using (IList<T> view = list.View(0, 0)) {
+ while (view.TrySlide(0, 1)) {
+ if (p(view.First))
+ return view.Offset;
+ view.Slide(+1, 0);
+ }
+ }
+ return -1;
+ }
+
+ // Find the index of the last item that satisfies p
+
+ public static int FindLastIndex<T>(IList<T> list, Fun<T,bool> p) {
+ using (IList<T> view = list.View(list.Count, 0)) {
+ while (view.TrySlide(-1, 1)) {
+ if (p(view.First))
+ return view.Offset;
+ }
+ }
+ return -1;
+ }
+
+ // Yield indexes of all items equal to x, in list order:
+
+ public static SCG.IEnumerable<int> IndexesOf<T>(IList<T> list, T x) {
+ IList<T> tail = list.View(0, list.Count);
+ tail = tail.ViewOf(x);
+ while (tail != null) {
+ yield return tail.Offset;
+ tail = tail.Slide(+1,0).Span(list);
+ tail = tail.ViewOf(x);
+ }
+ }
+
+ // Yield indexes of items equal to x, in reverse list order.
+
+ public static SCG.IEnumerable<int> ReverseIndexesOf<T>(IList<T> list, T x) {
+ IList<T> head = list.View(0, list.Count);
+ head = head.LastViewOf(x);
+ while (head != null) {
+ yield return head.Offset;
+ head = list.Span(head.Slide(0,0));
+ head = head.LastViewOf(x);
+ }
+ }
+
+ }
+}
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/Views.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/Views.cs
new file mode 100644
index 00000000000..6cf96bf1291
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/Views.cs
@@ -0,0 +1,160 @@
+/*
+ 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.
+*/
+
+// C5 example: Views 2004-12-29 OBSOLETE
+
+// Compile with
+// csc /r:C5.dll Views.cs
+
+using System;
+using C5;
+using SCG = System.Collections.Generic;
+
+namespace Views {
+ class Views {
+ public static void Main(String[] args) {
+ IList<char> lst = new LinkedList<char>();
+ lst.AddAll<char>(new char[] { 'a', 'b', 'c', 'd' });
+ IList<char>
+ A = lst.View(0, 2),
+ B = lst.View(2, 0),
+ C = lst.View(2, 1),
+ D = lst.View(3, 1),
+ E = lst.View(4, 0),
+ F = lst.View(1, 2),
+ G = lst.View(0, 4);
+ IList<char>[] views = { A, B, C, D, E, F, G };
+ Console.WriteLine("ABCDEFG overlaps with:");
+ foreach (IList<char> u in views) {
+ foreach (IList<char> w in views)
+ Console.Write(Overlap(u, w) ? '+' : '-');
+ Console.WriteLine();
+ }
+ Console.WriteLine("ABCDEFG overlap length:");
+ foreach (IList<char> u in views) {
+ foreach (IList<char> w in views) {
+ int len = OverlapLength(u, w);
+ Console.Write(len >= 0 ? String.Format("{0}", len) : " ");
+ }
+ Console.WriteLine();
+ }
+ Console.WriteLine("ABCDEFG contained in:");
+ foreach (IList<char> u in views) {
+ foreach (IList<char> w in views)
+ Console.Write(ContainsView(u, w) ? '+' : '-');
+ Console.WriteLine();
+ }
+ }
+
+ public static int LeftEndIndex<T>(IList<T> u) {
+ return u.Offset;
+ }
+
+ public static int RightEndIndex<T>(IList<T> u) {
+ return u.Offset+u.Count;
+ }
+
+ public static bool Overlap<T>(IList<T> u, IList<T> w) {
+ if (u.Underlying == null || u.Underlying != w.Underlying)
+ throw new ArgumentException("views must have same underlying list");
+ else
+ return u.Offset < w.Offset+w.Count && w.Offset < u.Offset+u.Count;
+ }
+
+ public static int OverlapLength<T>(IList<T> u, IList<T> w) {
+ if (Overlap(u, w))
+ return Math.Min(u.Offset+u.Count, w.Offset+w.Count)
+ - Math.Max(u.Offset, w.Offset);
+ else
+ return -1; // No overlap
+ }
+
+ public static bool ContainsView<T>(IList<T> u, IList<T> w) {
+ if (u.Underlying == null || u.Underlying != w.Underlying)
+ throw new ArgumentException("views must have same underlying list");
+ else
+ if (w.Count > 0)
+ return u.Offset <= w.Offset && w.Offset+w.Count <= u.Offset+u.Count;
+ else
+ return u.Offset < w.Offset && w.Offset < u.Offset+u.Count;
+ }
+
+ public static bool SameUnderlying<T>(IList<T> u, IList<T> w) {
+ return (u.Underlying ?? u) == (w.Underlying ?? w);
+ }
+
+ // Replace the first occurrence of each x from xs by y in list:
+
+ public static void ReplaceXsByY<T>(HashedLinkedList<T> list, T[] xs, T y) {
+ foreach (T x in xs) {
+ using (IList<T> view = list.ViewOf(x)) {
+ if (view != null) {
+ view.Remove();
+ view.Add(y);
+ }
+ }
+ }
+ }
+
+ // Find first item that satisfies p
+
+ public static bool Find<T>(IList<T> list, Fun<T,bool> p, out T res) {
+ IList<T> view = list.View(0, 0);
+ while (view.Offset < list.Count) {
+ view.Slide(+1, 1);
+ if (p(view.First)) {
+ res = view.First;
+ return true;
+ }
+ }
+ res = default(T);
+ return false;
+ }
+
+ // Or, using that the list is enumerable:
+
+ public static bool Find1<T>(IList<T> list, Fun<T,bool> p, out T res) {
+ foreach (T x in list) {
+ if (p(x)) {
+ res = x;
+ return true;
+ }
+ }
+ res = default(T);
+ return false;
+ }
+
+ // Find last item that satisfies p
+
+ public static bool FindLast<T>(IList<T> list, Fun<T,bool> p, out T res) {
+ IList<T> view = list.View(list.Count, 0);
+ while (view.Offset > 0) {
+ view.Slide(-1, 1);
+ if (p(view.First)) {
+ res = view.First;
+ return true;
+ }
+ }
+ res = default(T);
+ return false;
+ }
+ }
+}
diff --git a/mcs/class/Mono.C5/1.0/UserGuideExamples/WrappedArray.cs b/mcs/class/Mono.C5/1.0/UserGuideExamples/WrappedArray.cs
new file mode 100644
index 00000000000..398b9bf5b44
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/UserGuideExamples/WrappedArray.cs
@@ -0,0 +1,191 @@
+/*
+ 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.
+*/
+
+// C5 example: WrappedArray 2005-07-21
+
+// Compile with
+// csc /r:C5.dll WrappedArray.cs
+
+using System;
+using C5;
+using SCG = System.Collections.Generic;
+
+namespace WrappedArray {
+ class WrappedArray {
+ public static void Main(String[] args) {
+ }
+
+
+ // System.Array.Exists
+
+ public static bool Exists<T>(T[] arr, Fun<T,bool> p) {
+ return new WrappedArray<T>(arr).Exists(p);
+ }
+
+ // System.Array.TrueForAll
+
+ public static bool TrueForAll<T>(T[] arr, Fun<T,bool> p) {
+ return new WrappedArray<T>(arr).All(p);
+ }
+
+ // System.Array.Find(T[], Predicate)
+ // This loses the valuable bool returned by C5 Find.
+
+ public static T Find<T>(T[] arr, Fun<T,bool> p) {
+ T res;
+ new WrappedArray<T>(arr).Find(p, out res);
+ return res;
+ }
+
+ // System.Array.FindAll(T[], Predicate)
+
+ public static T[] FindAll<T>(T[] arr, Fun<T,bool> p) {
+ return new WrappedArray<T>(arr).FindAll(p).ToArray();
+ }
+
+ // System.Array.FindIndex(T[], Predicate)
+
+ public static int FindIndex<T>(T[] arr, Fun<T,bool> p) {
+ return new WrappedArray<T>(arr).FindIndex(p);
+ }
+
+ // System.Array.FindIndex(T[], int, Predicate)
+
+ public static int FindIndex<T>(T[] arr, int i, Fun<T,bool> p) {
+ int j = new WrappedArray<T>(arr).View(i,arr.Length-i).FindIndex(p);
+ return j < 0 ? j : j+i;
+ }
+
+ // System.Array.FindIndex(T[], int, int, Predicate)
+
+ public static int FindIndex<T>(T[] arr, int i, int n, Fun<T,bool> p) {
+ int j = new WrappedArray<T>(arr).View(i,n).FindIndex(p);
+ return j < 0 ? j : j+i;
+ }
+
+ // System.Array.FindLast(T[], Predicate)
+ // This loses the valuable bool returned by C5 Find.
+
+ public static T FindLast<T>(T[] arr, Fun<T,bool> p) {
+ T res;
+ new WrappedArray<T>(arr).FindLast(p, out res);
+ return res;
+ }
+
+ // System.Array.FindLastIndex(T[], Predicate)
+
+ public static int FindLastIndex<T>(T[] arr, Fun<T,bool> p) {
+ return new WrappedArray<T>(arr).FindIndex(p);
+ }
+
+ // System.Array.FindLastIndex(T[], int, Predicate)
+
+ public static int FindLastIndex<T>(T[] arr, int i, Fun<T,bool> p) {
+ int j = new WrappedArray<T>(arr).View(i,arr.Length-i).FindIndex(p);
+ return j < 0 ? j : j+i;
+ }
+
+ // System.Array.FindLastIndex(T[], int, int, Predicate)
+
+ public static int FindLastIndex<T>(T[] arr, int i, int n, Fun<T,bool> p) {
+ int j = new WrappedArray<T>(arr).View(i,n).FindIndex(p);
+ return j < 0 ? j : j+i;
+ }
+
+ // System.Array.ForEach(T[], Action)
+
+ public static void ForEach<T>(T[] arr, Act<T> act) {
+ new WrappedArray<T>(arr).Apply(act);
+ }
+
+ // System.Array.IndexOf(T[], T)
+
+ public static int IndexOf<T>(T[] arr, T x) {
+ int j = new WrappedArray<T>(arr).IndexOf(x);
+ return j < 0 ? -1 : j;
+ }
+
+ // System.Array.IndexOf(T[], T, int)
+
+ public static int IndexOf<T>(T[] arr, T x, int i) {
+ int j = new WrappedArray<T>(arr).View(i, arr.Length-i).IndexOf(x);
+ return j < 0 ? -1 : j+i;
+ }
+
+ // System.Array.IndexOf(T[], T, int, int)
+
+ public static int IndexOf<T>(T[] arr, T x, int i, int n) {
+ int j = new WrappedArray<T>(arr).View(i, n).IndexOf(x);
+ return j < 0 ? -1 : j+i;
+ }
+
+ // System.Array.LastIndexOf(T[], T)
+
+ public static int LastIndexOf<T>(T[] arr, T x) {
+ int j = new WrappedArray<T>(arr).LastIndexOf(x);
+ return j < 0 ? -1 : j;
+ }
+
+ // System.Array.LastIndexOf(T[], T, int)
+
+ public static int LastIndexOf<T>(T[] arr, T x, int i) {
+ int j = new WrappedArray<T>(arr).View(i, arr.Length-i).LastIndexOf(x);
+ return j < 0 ? -1 : j+i;
+ }
+
+ // System.Array.LastIndexOf(T[], T, int, int)
+
+ public static int LastIndexOf<T>(T[] arr, T x, int i, int n) {
+ int j = new WrappedArray<T>(arr).View(i, n).LastIndexOf(x);
+ return j < 0 ? -1 : j+i;
+ }
+
+ // System.Array.Sort(T[])
+
+ public static void Sort<T>(T[] arr) {
+ new WrappedArray<T>(arr).Sort();
+ }
+
+ // System.Array.Sort(T[], int, int)
+
+ public static void Sort<T>(T[] arr, int i, int n) {
+ new WrappedArray<T>(arr).View(i, n).Sort();
+ }
+
+ // System.Array.Sort(T[], SCG.IComparer<T>)
+
+ public static void Sort<T>(T[] arr, SCG.IComparer<T> cmp) {
+ new WrappedArray<T>(arr).Sort(cmp);
+ }
+
+ // System.Array.Sort(T[], int, int, SCG.IComparer<T>)
+
+ public static void Sort<T>(T[] arr, int i, int n, SCG.IComparer<T> cmp) {
+ new WrappedArray<T>(arr).View(i, n).Sort(cmp);
+ }
+
+ // System.Array.Sort(T[], Comparison)
+
+ public static void Sort<T>(T[] arr, Comparison<T> csn) {
+ new WrappedArray<T>(arr).Sort(new DelegateComparer<T>(csn));
+ }
+ }
+}
diff --git a/mcs/class/Mono.C5/1.0/doc/AssemblyInfo.cs b/mcs/class/Mono.C5/1.0/doc/AssemblyInfo.cs
new file mode 100644
index 00000000000..5a12cf79079
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/doc/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("")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("")]
+[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.*")]
+
+//
+// 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("")]
+[assembly: AssemblyKeyName("")]
diff --git a/mcs/class/Mono.C5/1.0/doc/Test.cs b/mcs/class/Mono.C5/1.0/doc/Test.cs
new file mode 100644
index 00000000000..c30c6b6fab2
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/doc/Test.cs
@@ -0,0 +1,137 @@
+/*
+ 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 MSG = System.Collections.Generic;
+
+namespace Try
+{
+/*
+ /// <summary>
+ /// Affenpinscher
+ /// </summary>
+ public class SSS<T,U>
+ {
+ /// <summary>
+ /// GGGGGGG <cell>tidlig <seealso cref="T:Try.Foo!3"/> <b alk="foo">bonny</b> namse</cell> efter
+ /// </summary>
+ /// <param name="u">zeU</param>
+ /// <param name="cell">zeI</param>
+ /// <param name="t">zeT</param>
+ /// <returns>zeReturn</returns>
+ public static T g(out U u, ref int cell, T t) { u = default(U); return default(T); }
+
+ /// <summary>
+ /// Nested klasse
+ /// </summary>
+ public class Inner<K>
+ {
+ /// <summary>
+ /// IIIIIIIIII
+ /// </summary>
+ /// <param name="t">TTTTTTTTTT</param>
+ /// <param name="k">KKKKKKK</param>
+ /// <returns>RRRRRRRRRRR</returns>
+ public U indre(T t, K k) { return default(U); }
+ }
+ /// <summary>
+ /// Jaj ja
+ /// </summary>
+ public class NongenNested
+ {
+ /// <summary>
+ /// Det er et y
+ /// </summary>
+ public int y;
+ }
+ /// <summary>
+ /// Lolololola
+ /// </summary>
+ public U lefield;
+ /// <summary>
+ /// Cococococola
+ /// </summary>
+ public static Foo<T,U,U> gramse;
+ /// <summary>
+ /// zesum
+ /// </summary>
+ /// <value>zeval</value>
+ public SSS<T,T> leprop { get { return default(SSS<T,T>); } }
+ /// <summary>
+ /// Sju
+ /// </summary>
+ /// <param name="f">ffffffff</param>
+ /// <param name="johndoe">ffffffff</param>
+ public string s<V,X,Y,Z>(Foo<T,Y,SSS<Z,T>> f, int johndoe) { return "7"; }
+ /// <summary>
+ /// intuism
+ /// </summary>
+ /// <param name="tudse">froe</param>
+ /// <param name="frank">sin</param>
+ public SSS(T[] tudse, double frank) { }
+ }
+
+ /// <summary>
+ /// ooh
+ /// </summary>
+
+ public class HHH
+ {
+ /// <summary>
+ /// MusseKom
+ /// </summary>
+ public class Musse { }
+ }
+
+
+
+ /// <summary>
+ /// Hejsa
+ /// </summary>
+ public class Foo<K,L,M> { }
+
+*/
+ /// <summary>
+ /// Hejsa
+ /// </summary>
+ public delegate void Mapper<T,U>(T t);
+
+
+
+ /// <summary>
+ /// Los accoutables
+ /// </summary>
+ public interface IEnumerable<T>
+ {
+ // <summary>
+ // getegetegeteg
+ // </summary>
+ // <returns>leturn</returns>
+ //MSG.IEnumerator<T> GetEnumerator();
+
+
+ /// <summary>
+ /// Apply a delegate to all items of this collection.
+ /// </summary>
+ /// <param name="a">The delegate to apply</param>
+ void Map<U>(Mapper<T,U> a);
+ }
+}
diff --git a/mcs/class/Mono.C5/1.0/doc/Timer.cs b/mcs/class/Mono.C5/1.0/doc/Timer.cs
new file mode 100644
index 00000000000..67751a5b489
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/doc/Timer.cs
@@ -0,0 +1,84 @@
+/*
+ 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.IO;
+using System.Reflection;
+using System.Xml;
+using System.Diagnostics;
+
+namespace DocNet
+{
+ class Timer
+ {
+ static System.Diagnostics.Process p;
+
+ static long sws;
+
+ static long svm;
+
+ static double stt;
+
+ static DateTime swc;
+
+ public long ws;
+
+ public long vm;
+
+ public double tt;
+
+ public DateTime wc;
+
+ public double deltat;
+
+ public double deltac;
+
+
+ public Timer()
+ {
+ if (p == null)
+ {
+ p = System.Diagnostics.Process.GetCurrentProcess();
+ stt = p.TotalProcessorTime.TotalMilliseconds;
+ sws = p.WorkingSet64;
+ svm = p.VirtualMemorySize64;
+ swc = DateTime.Now;
+ }
+ }
+
+
+ public double snap()
+ {
+ double oldt = tt;
+ DateTime oldc = wc; p.Refresh();
+ tt = p.TotalProcessorTime.TotalMilliseconds - stt;
+ deltat = tt - oldt;
+ ws = p.WorkingSet64 - sws;
+ vm = p.VirtualMemorySize64 - svm;
+ wc = DateTime.Now;
+
+ TimeSpan x = oldc.Subtract(wc);
+
+ deltac = -x.TotalMilliseconds;
+ return deltac;
+ }
+ }
+} \ No newline at end of file
diff --git a/mcs/class/Mono.C5/1.0/doc/docNet.csproj b/mcs/class/Mono.C5/1.0/doc/docNet.csproj
new file mode 100644
index 00000000000..e417f7689b0
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/doc/docNet.csproj
@@ -0,0 +1,83 @@
+<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>{42811A81-6A99-4C7A-A6DA-DF104C767B72}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <StartupObject>
+ </StartupObject>
+ <RootNamespace>docNet</RootNamespace>
+ <NoStandardLibraries>false</NoStandardLibraries>
+ <AssemblyName>docNet</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>docnet.xml</DocumentationFile>
+ </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>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Xml">
+ <HintPath>..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.2.30703\System.XML.dll</HintPath>
+ <Name>System.XML</Name>
+ </Reference>
+ <ProjectReference Include="..\C5\C5.csproj">
+ <Project>{D70489CD-ABDA-48FF-BD1E-BE3F7495BE71}</Project>
+ <Package>{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</Package>
+ <Name>C5</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="AssemblyInfo.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="docnet.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Content Include="docbuild\banner.htm" />
+ <Content Include="docbuild\docnet.css" />
+ <Content Include="docbuild\frames.htm" />
+ <Content Include="docbuild\litterature.htm" />
+ <Content Include="docbuild\userguide.htm" />
+ <Content Include="overview.xslt" />
+ <Compile Include="Test.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="Timer.cs" />
+ <Content Include="trans.xslt" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="dodoc.cmd" />
+ <None Include="mkcurrent.cmd" />
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSHARP.Targets" />
+ <PropertyGroup>
+ <PreBuildEvent>
+ </PreBuildEvent>
+ <PostBuildEvent>
+ </PostBuildEvent>
+ <ApplicationIcon>
+ </ApplicationIcon>
+ </PropertyGroup>
+ <ProjectExtensions>
+ <VisualStudio>
+ </VisualStudio>
+ </ProjectExtensions>
+</Project> \ No newline at end of file
diff --git a/mcs/class/Mono.C5/1.0/doc/docbuild/banner.htm b/mcs/class/Mono.C5/1.0/doc/docbuild/banner.htm
new file mode 100644
index 00000000000..41cbc5f6120
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/doc/docbuild/banner.htm
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html >
+<head>
+ <link rel="stylesheet" type="text/css" href="docnet.css">
+</head>
+<body>
+ <p>
+ <font size="6"><b>C5 documentation</b></font> Legend: <code class="greenbg">A</code>:
+ abstract, <code class="greenbg">F</code>: final, <code class="greenbg">N</code>:
+ non-virtual, <code class="greenbg">P</code>: protected, <code class="greenbg">S</code>:
+ static. &nbsp;<a href="userguide.htm" target="_blank">User's Guide</a></p>
+</body>
+</html>
diff --git a/mcs/class/Mono.C5/1.0/doc/docbuild/docnet.css b/mcs/class/Mono.C5/1.0/doc/docbuild/docnet.css
new file mode 100644
index 00000000000..b47b0693ba5
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/doc/docbuild/docnet.css
@@ -0,0 +1,131 @@
+BODY
+{
+ FONT-FAMILY: "Verdana", sans-serif;
+ FONT-SIZE: x-small;
+}
+CODE
+{
+ FONT-SIZE: x-small;
+}
+A:link
+{
+ COLOR: #4e4887
+}
+A:visited
+{
+ COLOR: #8080c8
+}
+A:active
+{
+ COLOR: #f16043
+}
+A:hover
+{
+ COLOR: #f16043
+}
+P
+{
+ MARGIN-BOTTOM: 0.5em;
+ MARGIN-TOP: 0.5em
+}
+.greenbg
+{
+ BACKGROUND-COLOR: #00ff00;
+ font-weight:bold
+}
+TABLE
+{
+ BORDER-BOTTOM: medium none;
+ BORDER-LEFT: medium none;
+ BORDER-RIGHT: medium none;
+ BORDER-TOP: medium none;
+}
+TD
+{
+ BACKGROUND-COLOR: #bedfff;
+ BORDER-BOTTOM: medium none;
+ BORDER-LEFT: medium none;
+ BORDER-RIGHT: medium none;
+ BORDER-TOP: medium none;
+ FONT-SIZE:x-small;
+ MARGIN: 2px;
+ PADDING-BOTTOM: 2px;
+ PADDING-LEFT: 2px;
+ PADDING-RIGHT: 2px;
+ PADDING-TOP: 2px;
+ TEXT-ALIGN: left
+}
+TH
+{
+ BACKGROUND-COLOR: #ffdfbe;
+ BORDER-BOTTOM: medium none;
+ BORDER-LEFT: medium none;
+ BORDER-RIGHT: medium none;
+ BORDER-TOP: medium none;
+ FONT-SIZE: x-small;
+ MARGIN: 2px;
+ PADDING-BOTTOM: 2px;
+ PADDING-LEFT: 2px;
+ PADDING-RIGHT: 2px;
+ PADDING-TOP: 2px;
+ TEXT-ALIGN: left
+}
+TH
+{
+ BACKGROUND-COLOR: #ffaa57
+}
+UL
+{
+ MARGIN-TOP: 0.5em
+}
+OL
+{
+ MARGIN-TOP: 0.5em
+}
+H1
+{
+ COLOR: #336699;
+ FONT-SIZE: x-large;
+ MARGIN-BOTTOM: 0.5em;
+ MARGIN-TOP: 1em;
+ PADDING-LEFT: 4px
+}
+H2
+{
+ BORDER-LEFT: #4e4887 8px solid;
+ BORDER-TOP: #4e4887 1px solid;
+ COLOR: #4e4887;
+ FONT-SIZE: medium;
+ MARGIN-BOTTOM: 0.5em;
+ MARGIN-TOP: 1em;
+ PADDING-LEFT: 4px
+}
+H3
+{
+ BORDER-LEFT: #4e4887 4px solid;
+ BORDER-TOP: #4e4887 1px solid;
+ COLOR: #4e4887;
+ FONT-SIZE: small;
+ MARGIN-BOTTOM: 0.5em;
+ MARGIN-TOP: 1em;
+ PADDING-LEFT: 4px
+}
+H4
+{
+ COLOR: #4e4887;
+ FONT-SIZE: small;
+ MARGIN-BOTTOM: 0.5em
+}
+H5
+{
+ COLOR: #4e4887;
+ FONT-SIZE: x-small;
+ MARGIN-BOTTOM: 0.5em
+}
+H6
+{
+ COLOR: #4e4887;
+ FONT-SIZE: x-small;
+ FONT-STYLE: italic;
+ MARGIN-BOTTOM: 0.5em
+}
diff --git a/mcs/class/Mono.C5/1.0/doc/docbuild/frames.htm b/mcs/class/Mono.C5/1.0/doc/docbuild/frames.htm
new file mode 100644
index 00000000000..d903905392e
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/doc/docbuild/frames.htm
@@ -0,0 +1,12 @@
+<html>
+<frameset rows="84,*">
+ <frame name="banner" scrolling="no" noresize src="banner.htm">
+ <frameset cols="200,*">
+ <frame name="contents" src="contents.htm">
+ <frame name="main" >
+ </frameset>
+ <noframes>
+ <p>This page requires frames, but your browser does not support them.</p>
+ </noframes>
+</frameset>
+</html>
diff --git a/mcs/class/Mono.C5/1.0/doc/docbuild/litterature.htm b/mcs/class/Mono.C5/1.0/doc/docbuild/litterature.htm
new file mode 100644
index 00000000000..9e969e669e8
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/doc/docbuild/litterature.htm
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<title>C5 collection classes - litterature references</title>
+<meta name="GENERATOR" content="Microsoft Visual Studio.NET 7.0">
+<meta name=ProgId content=VisualStudio.HTML>
+<meta name=Originator content="Microsoft Visual Studio.NET 7.0">
+</head>
+<body>
+<h1>C5 collection classes - litterature references</h1>
+<table border="1" cellspacing="0">
+ <tr>
+ <td>
+ <a name="CLRS">CLRS</a></td>
+ <td>Cormen, Leiserson, Rivest, Shamir: ...</td>
+ </tr>
+ <tr>
+ <td>
+ <a name="DSST">DSST</a></td>
+ <td>D, Sarnak, Sleator, Tarjan, ...</td>
+ </tr>
+ <tr>
+ <td>
+ <a name="Tarjan1">Tarjan1</a>Tarjan: (the booklet)</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>
+ <a name=""></a></td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>
+ <a name=""></a></td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>
+ <a name=""></a></td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>
+ <a name=""></a></td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>
+ <a name=""></a></td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>
+ <a name=""></a></td>
+ <td></td>
+ </tr>
+</table>
+
+
+</body>
+</html>
diff --git a/mcs/class/Mono.C5/1.0/doc/docbuild/userguide.htm b/mcs/class/Mono.C5/1.0/doc/docbuild/userguide.htm
new file mode 100644
index 00000000000..cea0e026e0e
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/doc/docbuild/userguide.htm
@@ -0,0 +1,2519 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>C5 User's Guide</title>
+ <style>
+<!--
+.revvid { color: #FFFFFF; background-color: #00AA00; font-weight: bold }
+-->
+ </style>
+</head>
+<body>
+<h1><a class="mozTocH1" name="mozTocId905770"></a>C5 User's guide for
+prerelease version 0.5</h1>
+<h2><a class="mozTocH2" name="mozTocId507311"></a>Table of contents</h2>
+<ul class="readonly" id="mozToc">
+<!--mozToc h1 1 h2 2 h3 3 h4 4 h5 5 h6 6--><li><a href="#mozTocId905770">C5
+User's guide for prerelease version 0.5</a>
+ <ul>
+ <li><a href="#mozTocId507311">Table of contents</a></li>
+ </ul>
+ </li>
+ <li><a href="#mozTocId564527">Overview</a></li>
+ <li><a href="#mozTocId86956">Interfaces</a>
+ <ul>
+ <li><a href="#mozTocId21725">"Proper" collection interfaces</a></li>
+ <li><a href="#mozTocId721827">Dictionary interfaces</a></li>
+ <li><a href="#mozTocId908053">Query result interfaces</a></li>
+ </ul>
+ </li>
+ <li><a href="#mozTocId110895">To construct a collection</a>
+ <ul>
+ <li><a href="#mozTocId850165">To use an external equalityComparer</a></li>
+ <li><a href="#mozTocId162938">To use an external comparer</a></li>
+ <li><a href="#mozTocId957374">To make collections of collections</a></li>
+ </ul>
+ </li>
+ <li><a href="#mozTocId486186">Special topics</a>
+ <ul>
+ <li><a href="#mozTocId48263">To choose a set or bag collection</a></li>
+ <li><a href="#mozTocId929755">To work on part of a list: list
+views</a></li>
+ <li><a href="#mozTocId650306">To work with persistent red-black
+trees</a></li>
+ <li><a href="#mozTocId553609">To implement new collection classes
+or subclass an existing one</a></li>
+ <li><a href="#mozTocId753674">To present a read only view of a
+collection</a></li>
+ </ul>
+ </li>
+ <li><a href="#mozTocId6619">Collection classes by data structure/class</a></li>
+ <li><a href="#mozTocId393559">Planned architecture or interface
+changes for first release</a></li>
+ <li><a href="#mozTocId336849">Performance details for proper
+collection classes</a></li>
+ <li><a href="#mozTocId712409">Performance details for dictionary
+classes</a></li>
+</ul>
+<h1><a class="mozTocH1" name="mozTocId564527"></a>Overview<br>
+</h1>
+<p>C5 is a comprehensive library of collection classes for the <a
+ href="http://www.ecma-international.org/publications/standards/Ecma-335.htm">Common
+Language Infrastructure</a> (CLI). This guide describes prerelease
+version 0.5 of&nbsp; C5. <br>
+</p>
+<p>C5 is a
+refactoring and extension of the <a
+ href="http://www.dina.kvl.dk/%7Esestoft/gcsharp/index.html#collection">generic
+collection classes</a> developed by Peter Sestoft while visiting
+Microsoft
+Research in Cambridge.</p>
+<p> Unless stated otherwise types mentioned below will belong to the
+"C5"
+namespace; and all code examples assume a "using C5;" clause (and no
+"using System.Collection.Generics;" clause)..&nbsp;</p>
+<p>The goals in the development of the library has been</p>
+<ul>
+ <li>
+ <p class="MsoNormal"><span style="" lang="EN-US">To create a
+library of collection classes for the CLI that can assist expert and
+non-expert programmers on the platform to develop correct and efficient
+applications.</span> </p>
+ </li>
+ <li>
+ <p class="MsoNormal"><span style="" lang="EN-US">The library should
+at least fill the gaps in the standard &#8220;System.Collections.Generics&#8221;
+namespace compared to standard collection class libraries for related
+object oriented languages like Java, and utilize the new facilities for
+generic </span><span style="" lang="EN-US">programming. Microsoft
+recently (mid 2004) seems to have changed their minds and ntend to
+bridge that gap in the beta2 version of VS 2005 due at the end of 2004.</span>
+ </p>
+ </li>
+</ul>
+<p>In order to fulfill the efficiency goal, the library utilizes
+first-class <a href="#datastructures">data structures</a>
+inside its collection classes. The library has been constructed with
+the modern
+object oriented programming principle of&nbsp; "<a href="#Interfaces">code
+to interfaces, not to implementations</a>" in mind, while the interface
+architecture has been carefully crafted to reflect the efficient data
+structures
+actually existence.</p>
+<p>A collection in the sense of this library is a plain "collection of
+items of a single type". A collection does not impose any other logical
+structure on its items than perhaps uniqueness or sequence ordering.</p>
+<p>The main division line among the collection classes of this library
+is the
+distinction between <a href="#Proper%20collection%20interfaces">"proper"
+collections</a> and <a href="#Dictionary%20interfaces">dictionaries</a>.
+A
+dictionary is a class that defines a partial function (or map) from one
+item
+type (the keys) to another one (the values). A dictionary can be viewed
+as a
+collection of (key,value) pairs having the property of defining a
+partial
+function.</p>
+<p>The item type for the collection classes are always given by generic
+parameters. For a proper collection, there will be a single parameter,
+customarily called T, as in HashSet&lt;T&gt;. For a dictionary there
+will be two - the key and value types -
+as in HashDictionary&lt;K,V&gt;.</p>
+<p>A collection class, or rather the data structure inside, can be
+either
+equality based or comparison based. An equality based collection will
+have an
+associated so-called equalityComparer of type <a href="main.htm#T:C5.IEqualityComparer%601">IEqualityComparer&lt;T&gt;</a>,
+where T is the item type of the collection. A comparison based
+collection has an
+associated comparer of type <a href="main.htm#T:C5.IComparer%601">IComparer&lt;T&gt;</a>.
+The section below on <a href="#Constructing">creation</a> of
+collection classes
+explains how the equalityComparers and comparers are chosen. NB: this design will
+be modified soon, cf. <a href="#planned">Planned changes</a>.<br>
+</p>
+<p>Collection classes in the library have either set or bag semantics.
+A set
+collection can at most contain one copy of an item, while bag
+collections may
+contain several. One can programmatically see at runtime if an editable
+collection class has set or bag semantics by checking the <a
+ href="main.htm#P:C5.IExtensible%601.AllowsDuplicates">
+AllowsDuplicates</a>
+property. At compile time, refer to the <a href="#set%20or%20bag">set
+or bag table</a>
+below for an overview. <br>
+</p>
+<h1><a class="mozTocH1" name="mozTocId86956"></a><a name="Interfaces">Interfaces</a></h1>
+<p>The C5 library is designed to make it easy to program to interfaces
+instead
+of implementations. In particular, all public properties and methods of
+the
+collection classes belong to their implemented interfaces (except for
+the odd
+special diagnostic method and the odd mistake to be weeded out before
+release). The typical programming style
+would be</p>
+<blockquote>
+ <p><code>IList&lt;int&gt; lst = new LinkedList&lt;int&gt;();<br>
+lst.Add(7);</code></p>
+</blockquote>
+<p>instead of&nbsp;</p>
+<blockquote>
+ <p><code> LinkedList&lt;int&gt; lst = new LinkedList&lt;int&gt;();<br>
+lst.Add(7);</code></p>
+</blockquote>
+<p>Note that with this programming style, the Add call will be compiled
+to an
+interface call instead of a (virtual) method call, but interface calls
+on the
+CLR (at least the Microsoft implementation) are at most very slightly
+slower
+than virtual calls, so one should not shun the interface style for
+performance
+reasons.</p>
+<p>We will discuss the collection classes available in C5 structured
+according
+to the main functional interfaces of the <a
+ href="#Proper%20collection%20interfaces">proper
+collections</a>, the <a href="#Dictionary%20interfaces">dictionaries</a>
+and the
+interfaces of <a href="#Query%20result%20interfaces">query results</a>.</p>
+<h2><a class="mozTocH2" name="mozTocId21725"></a><a
+ name="Proper collection interfaces">"Proper" collection interfaces</a></h2>
+<p>The following diagam shows the type hierarchy of the proper
+collection classes:</p>
+<p><img alt="Interface hierarchy" src="ClsdiagWork.png"
+ style="width: 757px; height: 498px;"><br>
+The&nbsp;most important interfaces - those that are directly
+implemented by
+collection classes - are listed to the left in this table with a short
+description in the middle and all implementing classes to the
+right.&nbsp;</p>
+<p>Please see also the <a href="#PerformanceProper">complete
+complexity table</a>
+for more comprehensive guidance.</p>
+<p>To identify which classes are equalityComparer or comparer based and which
+classes
+implement set or bag we use the following symbols:</p>
+<table border="1" width="471">
+ <tbody>
+ <tr>
+ <td width="116">set: <code class="revvid">S</code> </td>
+ <td width="117"> bag: <code class="revvid">B</code> </td>
+ <td width="117"> equalityComparer: <code class="revvid">H</code> </td>
+ <td width="117"> comparer: <code class="revvid">C</code> </td>
+ </tr>
+ </tbody>
+</table>
+<table border="1" width="100%">
+ <tbody>
+ <tr>
+ <th width="19%">Interface</th>
+ <th width="52%">Short description</th>
+ <th width="29%">Implementing classes</th>
+ </tr>
+ <tr>
+ <td valign="top" width="19%"><a
+ href="main.htm#T:C5.ICollection%601">ICollection&lt;T&gt;</a>&nbsp;</td>
+ <td valign="top" width="52%">This is the fundamental&nbsp;type
+of&nbsp; updateable collections. It has operations for searching for
+items, for adding, updating and removing one or a bunch of items, for
+clearing the collection and transforming the collection to an
+array.&nbsp;
+ <p>If one only needs these operations, the hash set and hash bag
+classes are fastest for if we have a equalityComparer for the items and the
+red-black tree classes are fastest if we must use a comparer.</p>
+ </td>
+ <td valign="top" width="29%"><code class="revvid">SH</code> <a
+ href="main.htm#T:C5.HashSet%601">HashSet&lt;T&gt;</a><br>
+ <code class="revvid">BH</code> <a
+ href="main.htm#T:C5.HashBag%601">HashBag&lt;T&gt;</a><br>
+ <code class="revvid">BH</code> <a
+ href="main.htm#T:C5.LinkedList%601">LinkedList&lt;T&gt;</a><br>
+ <code class="revvid">SH</code> <a
+ href="main.htm#T:C5.HashedLinkedList%601">HashedLinkedList&lt;T&gt;</a><br>
+ <code class="revvid">BH</code> <a
+ href="main.htm#T:C5.ArrayList%601">ArrayList&lt;T&gt;</a><br>
+ <code class="revvid">SH</code> <a
+ href="main.htm#T:C5.HashedArrayList%601"> HashedArrayList&lt;T&gt;<br>
+ </a> <code class="revvid">SC</code> <a
+ href="main.htm#T:C5.SortedArray%601"> SortedArray&lt;T&gt;</a><br>
+ <code class="revvid">SC</code> <a
+ href="main.htm#T:C5.TreeSet%601"> TreeSet&lt;T&gt;</a><br>
+ <code class="revvid">BC</code> <a
+ href="main.htm#T:C5.TreeBag%601"> TreeBag&lt;T&gt;</a></td>
+ </tr>
+ <tr>
+ <td valign="top" width="19%"><a
+ href="main.htm#T:C5.IPriorityQueue%601">IPriorityQueue&lt;T&gt;</a>&nbsp;</td>
+ <td valign="top" width="52%">This is a special case in the
+library, being the only type of updateable collection interface that
+does not implement IEditableCollection&lt;T&gt;. The reason for its
+presence is the specialized "heap" data structures for priority queues
+that only support these operations.
+ <p>If one only needs these the priority queue operations and is
+satisfied with bag semantics, then IntervalHeap&lt;P&gt;&nbsp; is the
+fastest choice. </p>
+ </td>
+ <td valign="top" width="29%"> <code class="revvid">BC</code> <a
+ href="main.htm#T:C5.IntervalHeap%601">IntervalHeap&lt;T&gt;</a><br>
+ <code class="revvid">SC</code> <a
+ href="main.htm#T:C5.TreeSet%601"> TreeSet&lt;T&gt;</a><br>
+ <code class="revvid">BC</code> <a
+ href="main.htm#T:C5.TreeBag%601"> TreeBag&lt;T&gt;</a></td>
+ </tr>
+ <tr>
+ <td valign="top" width="19%"><a href="main.htm#T:C5.IList%601">IList&lt;T&gt;</a>&nbsp;</td>
+ <td valign="top" width="52%">This is an updateable collection
+with sequence order imposed on the items by the user at insertion time
+or by later rearrangements.&nbsp;
+ <p>There are two main base data structures: dynamic arrays and
+doubly linked lists with very different complexity profile.&nbsp;The
+plain linked list is fast for operations at the end points only, while
+the plain array list have very fast lookups by index, but update
+operations are only fast at the right end point.&nbsp;</p>
+ <p>The Hashed- variants employ an index based on a hash table.
+This speeds up lookups by item considerably and for the linked list
+variant also insertions before or after specific items. The index
+changes the classes from bags to sets.&nbsp;</p>
+ <p>The hashed variants more than double the time of otherwise
+fast update operations, and should only be used when really
+needed.&nbsp;</p>
+ </td>
+ <td valign="top" width="29%"> <code class="revvid">BH</code> <a
+ href="main.htm#T:C5.LinkedList%601"> LinkedList&lt;T&gt;</a><br>
+ <code class="revvid">SH</code> <a
+ href="main.htm#T:C5.HashedLinkedList%601"> HashedLinkedList&lt;T&gt;</a><br>
+ <code class="revvid">BH</code> <a
+ href="main.htm#T:C5.ArrayList%601"> ArrayList&lt;T&gt;</a><br>
+ <code class="revvid">SH</code> <a
+ href="main.htm#T:C5.HashedArrayList%601"> HashedArrayList&lt;T&gt;</a></td>
+ </tr>
+ <tr>
+ <td valign="top" width="19%"><a
+ href="main.htm#T:C5.IIndexedSorted%601">IIndexedSorted&lt;T&gt;</a>&nbsp;</td>
+ <td valign="top" width="52%">This is an updateable collection
+with sequence order given by a comparer.&nbsp;
+ <p>There are two main data structures inside the implementations:
+red-black search trees and a dynamic array kept sorted at all times.</p>
+ <p>The differences are chiefly that the trees have much faster
+update operations, while the sorted array is somewhat faster at index
+lookups. In fact, the sorted array should only be used for static
+operation, where the collection is created and populated and then not
+changed again. </p>
+ </td>
+ <td valign="top" width="29%"> <code class="revvid">SC</code> <a
+ href="main.htm#T:C5.SortedArray%601"> SortedArray&lt;T&gt;</a><br>
+ <code class="revvid">SC</code> <a
+ href="main.htm#T:C5.TreeSet%601"> TreeSet&lt;T&gt;</a><br>
+ <code class="revvid">BC</code> <a
+ href="main.htm#T:C5.TreeBag%601"> TreeBag&lt;T&gt;</a></td>
+ </tr>
+ <tr>
+ <td valign="top" width="19%"><a
+ href="main.htm#T:C5.IPersistentSorted%601">IPersistentSorted&lt;T&gt;</a>&nbsp;</td>
+ <td valign="top" width="52%">This is a sorted collection that
+support very fast clones that themselves are sorted. The only
+implementation is the tree implementation with set and bag variants. </td>
+ <td valign="top" width="29%"> <code class="revvid">SC</code> <a
+ href="main.htm#T:C5.TreeSet%601"> TreeSet&lt;T&gt;</a><br>
+ <code class="revvid">BC</code> <a
+ href="main.htm#T:C5.TreeBag%601"> TreeBag&lt;T&gt;</a></td>
+ </tr>
+ </tbody>
+</table>
+<h2><a class="mozTocH2" name="mozTocId721827"></a><a
+ name="Dictionary interfaces">Dictionary interfaces</a></h2>
+<p>There are two dictionary interfaces:</p>
+<table border="1" width="100%">
+ <tbody>
+ <tr>
+ <th valign="top" width="19%">Interface</th>
+ <th width="56%">Short description</th>
+ <th width="25%">Implementing classes</th>
+ </tr>
+ <tr>
+ <td valign="top" width="19%"><a
+ href="main.htm#T:C5.IDictionary%602">IDictionary&lt;K,V&gt;</a> </td>
+ <td width="56%">This is the base dictionary interface.&nbsp;
+ <p>The choice is that one should use the hash dictionary unless
+one only has a comparer for the items, in which case the tree
+dictionary can be used.&nbsp; </p>
+ </td>
+ <td width="25%"><a href="main.htm#T:C5.HashDictionary%602">HashDictionary&lt;K,V&gt;</a><br>
+ <a href="main.htm#T:C5.TreeDictionary%602">TreeDictionary&lt;K,V&gt;</a></td>
+ </tr>
+ <tr>
+ <td valign="top" width="19%"><a
+ href="main.htm#T:C5.ISortedDictionary%602">ISortedDictionary&lt;K,V&gt;</a>
+ </td>
+ <td width="56%">This is a dictionary based on a comparer for the
+keys. There is only the tree implementation.&nbsp; </td>
+ <td width="25%"><a href="main.htm#T:C5.TreeDictionary%602">TreeDictionary&lt;K,V&gt;</a></td>
+ </tr>
+ </tbody>
+</table>
+<h2><a class="mozTocH2" name="mozTocId908053"></a><a
+ name="Query result interfaces">Query result interfaces</a></h2>
+<p>Some of the most basic collection interfaces have an important usage
+as the
+types of results of queries to collections, although these interfaces
+also
+appear at the base of the other collection interfaces and even as the
+types of
+synthetic collections. The interfaces in question are the standard
+System.Collections.Generics.IEnumerable&lt;T&gt;,
+<a href="main.htm#T:C5.ICollectionValue%601">ICollectionValue&lt;T&gt;</a>,
+<a href="main.htm#T:C5.IDirectedEnumerable%601">IDirectedEnumerable&lt;T&gt;</a>
+and <a href="main.htm#T:C5.IDirectedCollectionValue%601">IDirectedCollectionValue&lt;T&gt;</a>.</p>
+<p>The differences between the "Enumerable" and "Collection"
+variants are that the "Enumerable" variant only knows how to
+enumerate through its items, the "Collection" variants also knows how
+many items it has (without having to walk through an enumeration). The
+"Directed" variants are used for results of queries to sequenced
+collections (implementing <a href="main.htm#T:C5.ISequenced%601">ISequenced&lt;T&gt;</a>)
+and therefore have a non-implementation dependent enumeration order.
+The
+"Directed" variants supports two operations, <a
+ href="main.htm#M:C5.IDirectedCollectionValue%601.Backwards">Backwards()</a>
+to enable enumeration in the opposite direction and <a
+ href="main.htm#P:C5.IDirectedEnumerable%601.Direction">Direction</a>
+to tell if the enumeration order is forwards or backwards with respect
+to the
+original collection.</p>
+<p>Note: operations on an enumerator created by the GetEnumerator()
+method on System.Collections.Generics.IEnumerable&lt;T&gt; cannot be
+interleaved with update
+operations on
+the underlying collection.</p>
+<p>Note: for all enumerators in the library the operations have O(1)
+amortized
+complexity.</p>
+<h1><a class="mozTocH1" name="mozTocId110895"></a>To <a
+ name="Constructing">construct</a> a collection</h1>
+<p>All collections classes in C5 have (zero parameter) default
+constructors. So
+if we want to make a linked list of items of some type, <code>TheType</code>,
+and add an item to the list we will do</p>
+<p><code>&nbsp;&nbsp;&nbsp; IList&lt;TheType&gt; lst = new
+LinkedList&lt;TheType&gt;();<br>
+&nbsp;&nbsp;&nbsp; TheType t = ...;<br>
+&nbsp;&nbsp;&nbsp; lst.Add(t);</code></p>
+<p>The collection classes have no constructors that will take an array
+or a
+collection as parameter for prepopulating the collection, use the <a
+ href="file:///C:/home/kokholm/c5/vs/C5/main.htm#M:C5.ISink%601.AddAll%28C5.IEnumerable%7B%210%7D%29">
+AddAll</a> method
+instead. NB: in the released version, expect constructors with an
+enumerable as argument and constructors with a variable number of
+arguments ("params") for the initialization of the collection, see the <a
+ href="#planned">planned changes</a> section.<br>
+</p>
+<p>Some collection classes are governed by internal parameters that one
+can give
+non-default values at creation time (<code>fill</code> in <a
+ href="main.htm#T:C5.HashSet%601">HashSet&lt;T&gt;</a>,&nbsp;
+<a href="main.htm#T:C5.HashBag%601">HashBag&lt;T&gt;</a>, <a
+ href="main.htm#T:C5.HashDictionary%602">HashDictionary&lt;K,V&gt;</a>)
+or use internal tables that one can expand in advance if one has
+expectations of
+how large the collection will grow (HashSet&lt;T&gt;,&nbsp;
+HashBag&lt;T&gt;, HashDictionary&lt;K,V&gt;, <a
+ href="main.htm#T:C5.ArrayList%601">ArrayList&lt;T&gt;</a>,
+<a href="main.htm#T:C5.HashedArrayList%601"> HashedArrayList&lt;T&gt;</a>,
+<a href="main.htm#T:C5.SortedArray%601">SortedArray&lt;T&gt;</a>,
+<a href="main.htm#T:C5.IntervalHeap%601">IntervalHeap&lt;T&gt;</a>).</p>
+<p>For equality-based collection classes, these constructors will use a
+default
+equalityComparer to define equality of items according to the following table:</p>
+<table border="1">
+ <tbody>
+ <tr>
+ <th>T</th>
+ <th>default equalityComparer (implements IEqualityComparer&lt;T&gt;)</th>
+ <th>Equality and hash code by</th>
+ </tr>
+ <tr>
+ <td>int</td>
+ <td><a href="main.htm#T:C5.IntEqualityComparer">IntEqualityComparer</a></td>
+ <td>Equals and hash code of integer</td>
+ </tr>
+ <tr>
+ <td>other value type</td>
+ <td><a href="main.htm#T:C5.DefaultValueTypeEqualityComparer%601">DefaultValueTypeEqualityComparer&lt;T&gt;</a></td>
+ <td>methods inherited from object</td>
+ </tr>
+ <tr>
+ <td>IEditableCollection&lt;S&gt;</td>
+ <td><a href="main.htm#T:C5.EqualityComparerBuilder.UnsequencedEqualityComparer%602">EqualityComparerBuilder.UnsequencedEqualityComparer&lt;S,IEditableCollection&lt;S&gt;&gt;</a></td>
+ <td>contents without regards to sequence</td>
+ </tr>
+ <tr>
+ <td>ISequenced&lt;S&gt;</td>
+ <td><a href="main.htm#T:C5.EqualityComparerBuilder.SequencedEqualityComparer%602">EqualityComparerBuilder.SequencedEqualityComparer&lt;S,IEditableCollection&lt;S&gt;&gt;</a></td>
+ <td>contents with regards to sequence</td>
+ </tr>
+ <tr>
+ <td>other reference type</td>
+ <td><a href="main.htm#T:C5.DefaultReferenceTypeEqualityComparer%601">DefaultReferenceTypeEqualityComparer&lt;T&gt;</a></td>
+ <td>methods inherited from object</td>
+ </tr>
+ </tbody>
+</table>
+<p>For comparison-based collection classes, these constructors will use
+a
+default comparer:</p>
+<table border="1">
+ <tbody>
+ <tr>
+ <th>T</th>
+ <th>default comparer&nbsp;<br>
+(implements IComparer&lt;T&gt;)</th>
+ <th>Comparison by</th>
+ </tr>
+ <tr>
+ <td>int</td>
+ <td>IC</td>
+ <td>Standard integer comparison</td>
+ </tr>
+ <tr>
+ <td>implementing IComparable&lt;T&gt;</td>
+ <td><a href="main.htm#T:C5.NaturalComparer%601">NaturalComparer&lt;T&gt;</a></td>
+ <td>The CompareTo(T o)&nbsp; instance method</td>
+ </tr>
+ <tr>
+ <td>other implementing System.IComparable</td>
+ <td><a href="main.htm#T:C5.NaturalComparerO%601">NaturalComparerO&lt;T&gt;</a></td>
+ <td>The CompareTo(object o) instance method</td>
+ </tr>
+ <tr>
+ <td>other</td>
+ <td>-</td>
+ <td><i>collection class constructor throws an exception</i></td>
+ </tr>
+ </tbody>
+</table>
+<p>Sometimes, the default equalityComparer or comparer is not the right one for
+the
+problem at hand. In that case one must get hold on a equalityComparer or comparer
+of the
+right kind and supply it to one of the constructors of the collection
+classes
+that supports such a parameter. The procedure is demonstrated in the
+sections
+below on <a href="#external%20equalityComparer">external equalityComparers</a>, <a
+ href="#external%20comparer">external
+comparers</a> and <a href="#collections%20of%20collections">collections
+as items</a>.<br>
+</p>
+<p>NB: in the released version, expect the equalityComparers and comparers to be
+of the System.Collections.Generics.IComparer&lt;T&gt; type, see the <a
+ href="userguide.htm#planned">planned changes</a> section.</p>
+<h2><a class="mozTocH2" name="mozTocId850165"></a>To use an <a
+ name="external equalityComparer"> external equalityComparer</a></h2>
+<p>In addition to the helper classes referenced above, the library has
+the
+helper class <a href="main.htm#T:C5.KeyValuePairEqualityComparer%602">KeyValuePairEqualityComparer&lt;K,V&gt;</a>
+to construct a equalityComparer for pairs of the type <a
+ href="main.htm#T:C5.KeyValuePair%602">KeyValuePair&lt;K,V&gt;</a>,
+the type of entry of a K to V dictionary. The constructed equalityComparer will
+only take
+the first component of the pair into account. We can use these classes
+in the
+following way to make a linked list (with hash index) of pairs of
+strings
+identified by their first components using some custom equalityComparer on
+strings:</p>
+<blockquote>
+ <p><code>IEqualityComparer&lt;string&gt; csh = ...;<br>
+IEqualityComparer&lt;KeyValuePair&lt;string,string&gt;&gt; cph =&nbsp;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+new KeyValuePairEqualityComparer&lt;string,string&gt;(csh);<br>
+IList&lt;KeyValuePair&lt;string,string&gt;&gt; lst =<br>
+ </code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<code>
+new HashedLinkedList&lt;KeyValuePair&lt;string,string&gt;&gt;(cph);<br>
+lst.Add(new KeyValuePair&lt;string,string&gt;("abe","kat"));</code></p>
+</blockquote>
+<p>One may, of course, program a equalityComparer oneself. This one should always
+do if
+the item type is defined as a struct (value type) that does not
+override the
+Equals and GetHashCode methods of object, since in that case the
+default equalityComparer
+will use the slow default versions of those methods supplied by the
+runtime via
+reflection.&nbsp;</p>
+<h2><a class="mozTocH2" name="mozTocId162938"></a>To use an <a
+ name="external comparer"> external comparer</a></h2>
+<p>There is a helper class for comparer of pairs: <a
+ href="main.htm#T:C5.KeyValuePairEqualityComparer%602">KeyValuePairComparer&lt;K,V&gt;</a>.
+We will show an example of a custom comparer. Imagine wanting to
+compare double
+precision floating point numbers with a tolerance. The following code
+snippet
+shows how one could make a tree set out of such numbers:</p>
+<blockquote>
+ <p><code>class DC : IComparer&lt;double&gt; {<br>
+&nbsp;&nbsp; const double eps = 1E-10;<br>
+&nbsp;&nbsp; int Compare(double a, double b)&nbsp;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {return a &gt; b + eps ? 1 : a &lt; b -
+eps ? -1 : 0;}<br>
+}<br>
+ <br>
+void dowork() {<br>
+&nbsp;&nbsp; IComparer&lt;double&gt; dc = new DC();<br>
+&nbsp;&nbsp; ISorted&lt;double&gt; tree = new TreeSet&lt;double&gt;(dc);<br>
+&nbsp;&nbsp; tree.Add(3.45);<br>
+&nbsp;&nbsp; ...<br>
+}</code></p>
+</blockquote>
+<p>In this particular case, one would have to make sure, that two
+different
+floating point numbers are only identified by the comparer if they
+really should
+represent the same value and not by coincidence.</p>
+<h2><a class="mozTocH2" name="mozTocId957374"></a>To make <a
+ name="collections of collections"> collections of collections</a></h2>
+<p>When one wants to use a collection whose items itself are of
+collection type,
+one usually wants the interior collections to be identified by contents
+- either
+according to or irrespective of sequence order. An example could be
+transformations of <a
+ href="http://www.dina.kvl.dk/%7Esestoft/gcsharp/index.html#regexp">Finite
+Automatons</a>. The default equalityComparers and the EqualityComparerBuilder classes
+mentioned
+above may help to construct such collections of collections as in the
+examples
+that follow:</p>
+<p>To make an array list of sequenced collections identified by
+contents in
+sequenced fashion one would simply do:</p>
+<blockquote>
+ <p><code>ArrayList&lt;ISequenced&lt;int&gt;&gt; lst = new
+ArrayList&lt;ISequenced&lt;int&gt;&gt;();</code></p>
+</blockquote>
+<p>To make a linked list of linked lists identified by contents
+unsequenced, explicitly
+construct the collection equalityComparer:</p>
+<blockquote>
+ <p><code>IEqualityComparer&lt;LinkedList&lt;int&gt;&gt; lsth =<br>
+ </code>&nbsp;&nbsp;&nbsp;&nbsp; <code>new
+EqualityComparerBuilder.UnsequencedEqualityComparer&lt;int,LinkedList&lt;int&gt;&gt;();<br>
+LinkedList&lt;LinkedList&lt;int&gt;&gt; lst =<br>
+&nbsp;&nbsp; new LinkedList&lt;LinkedList&lt;int&gt;&gt;(lsth);</code></p>
+</blockquote>
+<p>If for some strange reason one would like to make a hash set of
+linked lists
+with the lists identified by reference equality one would simply do:</p>
+<blockquote>
+ <p><code>HashSet&lt;LinkedList&lt;int&gt;&gt; lst = new
+HashSet&lt;LinkedList&lt;int&gt;&gt;();</code></p>
+</blockquote>
+<p>If for even stranger reasons one would make a hash set of
+ISequenced&lt;int&gt; collections with the collections identified by
+reference
+equality one would do like this:</p>
+<blockquote>
+ <p><code>IEqualityComparer&lt;</code><code>ISequenced</code><code>&lt;int&gt;&gt;
+lsth =<br>
+ </code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <code>new
+DefaultReferenceTypeEqualityComparer&lt;</code><code>ISequenced</code><code>&lt;int&gt;&gt;();<br>
+HashSet&lt;</code><code>ISequenced</code><code>&lt;int&gt;&gt; lst =<br>
+&nbsp;&nbsp; new HashSet&lt;</code><code>ISequenced</code><code>&lt;int&gt;&gt;(lsth);</code></p>
+</blockquote>
+<h1><a class="mozTocH1" name="mozTocId486186"></a>Special topics</h1>
+<h2><a class="mozTocH2" name="mozTocId48263"></a>To choose a <a
+ name="set or bag"> set or bag</a> collection</h2>
+<p>The following table shows which of the collection classes have set
+semantics
+and which have bag semantics. All the implemented classes have fixed,
+compiled in semantics. <br>
+</p>
+<p>Note: when in a set collection, methods with an Add in the name will
+ignore
+attempts to add an item already there or flag the failed attempt by a
+Boolean return value; methods with an Insert in the name (only in
+lists) will throw an
+exception.</p>
+<table border="1" width="38%">
+ <tbody>
+ <tr>
+ <td valign="top" width="6%"><a href="main.htm#T:C5.HashSet%601">HashSet&lt;T&gt;</a></td>
+ <td valign="top" width="5%">set</td>
+ </tr>
+ <tr>
+ <td valign="top" width="6%"> <a href="main.htm#T:C5.HashBag%601">HashBag&lt;T&gt;</a></td>
+ <td valign="top" width="5%">bag</td>
+ </tr>
+ <tr>
+ <td valign="top" width="6%"> <a
+ href="main.htm#T:C5.LinkedList%601"> LinkedList&lt;T&gt;</a></td>
+ <td valign="top" width="5%">bag</td>
+ </tr>
+ <tr>
+ <td valign="top" width="6%"> <a
+ href="main.htm#T:C5.HashedLinkedList%601"> HashedLinkedList&lt;T&gt;</a></td>
+ <td valign="top" width="5%">set</td>
+ </tr>
+ <tr>
+ <td valign="top" width="6%"> <a
+ href="main.htm#T:C5.ArrayList%601"> ArrayList&lt;T&gt;</a></td>
+ <td valign="top" width="5%">bag</td>
+ </tr>
+ <tr>
+ <td valign="top" width="6%"> <a
+ href="main.htm#T:C5.HashedArrayList%601"> HashedArrayList&lt;T&gt; </a>
+ </td>
+ <td valign="top" width="5%">set</td>
+ </tr>
+ <tr>
+ <td valign="top" width="6%"> <a
+ href="main.htm#T:C5.SortedArray%601"> SortedArray&lt;T&gt;</a></td>
+ <td valign="top" width="5%">set</td>
+ </tr>
+ <tr>
+ <td valign="top" width="6%"> <a href="main.htm#T:C5.TreeSet%601">TreeSet&lt;T&gt;</a></td>
+ <td valign="top" width="5%">set</td>
+ </tr>
+ <tr>
+ <td valign="top" width="6%"> <a href="main.htm#T:C5.TreeBag%601">TreeBag&lt;T&gt;</a></td>
+ <td valign="top" width="5%">bag</td>
+ </tr>
+ <tr>
+ <td valign="top" width="6%"><a
+ href="main.htm#T:C5.IntervalHeap%601">IntervalHeap&lt;T&gt;</a></td>
+ <td valign="top" width="5%">bag</td>
+ </tr>
+ </tbody>
+</table>
+<h2><a class="mozTocH2" name="mozTocId929755"></a>To work on part of a
+list: list views</h2>
+<p>The IList&lt;T&gt; interface supports via the <a
+ href="main.htm#M:C5.IList%601.View%28System.Int32,System.Int32%29">
+View</a>
+method the functionality that one can zoom in on part of a list and use
+it as an
+IList&lt;T&gt; in its own right while having updates to the view passed
+through
+to the base (original) IList&lt;T&gt;. Using the <a
+ href="main.htm#M:C5.IList%601.Slide%28System.Int32%29">Slide</a>
+method calls, one may move the view around the base list. Using Slide
+repeatedly
+one can implement safe ways to iterate over a list while updating it.
+The
+IList&lt;T&gt; interface also has properties <a
+ href="main.htm#P:C5.IList%601.Underlying">Underlying</a>
+and <a href="main.htm#P:C5.IList%601.Offset">Offset</a> showing the
+base list of a
+view and the current site of a view.</p>
+<p>One can create a view on a view, but the new view will have the
+original base
+list as base. A view will be invalidated if an update operation is
+performed on
+the base list by any other means than through this particular view.</p>
+<p>The following code snippet shows a silly example of iterating over a
+list,
+doing an insertion each time certain combination of items are seen (the
+example
+iterates right to left and inserts 666 whenever two consecutive items
+have an
+odd difference):</p>
+<blockquote>
+ <p><code>IList&lt;int&gt; lst = ...;<br>
+IList&lt;int&gt; view = lst.CreateView(lst.Count-2, 2);<br>
+while (true) {<br>
+&nbsp;&nbsp;&nbsp; if ((view.Last - view.First) % 2 == 1)<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; view.Insert(1, 666);<br>
+&nbsp;&nbsp;&nbsp; if (view.Offset == 0)<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>
+&nbsp;&nbsp;&nbsp; else<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; view.Slide(-1,2);<br>
+}</code></p>
+</blockquote>
+<h2><a class="mozTocH2" name="mozTocId650306"></a>To work with
+persistent red-black trees</h2>
+<p>The search tree implementation in the library is based on node copy
+persistent red-black trees. The persistence is exposed in the <a
+ href="main.htm#M:C5.IPersistentSorted%601.Snapshot">Snapshot</a>
+method that can be considered a very fast and space-saving way of
+making a
+read-only clone of the tree. When using persistence, the space use of a
+red-black tree in this implementation is linear in the number of
+operations
+since the creation of the tree.</p>
+<p>One use of persistence could be to safely enumerate a tree
+interleaved with
+updates:</p>
+<blockquote>
+ <p><code>IPersistentSorted&lt;int&gt; tree = new TreeSet&lt;int&gt;();<br>
+tree.Add(5);<br>
+...<br>
+ISorted&lt;int&gt; snap = tree.Snapshot();<br>
+foreach (int i in snap)<br>
+&nbsp;&nbsp;&nbsp; tree.Add(i+7);</code></p>
+</blockquote>
+<p>The GUITester project of the complete library source code contains
+an
+interesting (standard) usage of persistent search trees to the
+geometric problem
+of constructing an efficient data structure for point location in a
+division of
+the plane given by a list of line segments.</p>
+<h2><a class="mozTocH2" name="mozTocId553609"></a>To implement new
+collection classes or subclass an existing one</h2>
+<p>All interface methods and properties of the collection classes
+implemented in
+the library are virtual and so it should be safe to subclass these
+classes. Some
+classes may have protected members if they are subclassed in the
+library itself.
+We refer to the detailed reference manuals and the library source for
+information on the protected members and their role in subclassing.</p>
+<p>There is a sequence of helper classes designed to be used as base
+classes of
+collection classes: <a href="main.htm#T:C5.EnumerableBase%601">EnumerableBase&lt;T&gt;</a>,
+<a href="main.htm#T:C5.CollectionValueBase%601">CollectionValueBase&lt;T&gt;</a>,
+<a href="main.htm#T:C5.CollectionBase%601">CollectionBase&lt;T&gt;</a>,
+<a href="main.htm#T:C5.SequencedBase%601">SequencedBase&lt;T&gt;</a>
+and <a href="main.htm#T:C5.ArrayBase%601">ArrayBase&lt;T&gt;</a>.
+Please see the reference manual and the library source code for
+documentation
+and examples.</p>
+<p>As for dictionaries, the DictionaryBase&lt;K,V&gt; class will
+construct a
+class implementing IDictionary&lt;K,V&gt; by simply plugging in a set
+implementation.</p>
+<h2><a class="mozTocH2" name="mozTocId753674"></a>To present a read
+only view of a collection</h2>
+<p>The library contains a long list of wrapper classes all with name
+starting
+with Guarded having the purpose of creating a read-only view of an
+existing
+collection. The wrapping is done by the constructors of the classes. If
+we want
+to give some code access to only lookup operations on a, say, list we
+can do as
+follows:</p>
+<blockquote>
+ <p><code>IList&lt;int&gt; lst;<br>
+...<br>
+IList&lt;int&gt; rolst = new GList&lt;int&gt;(lst);<br>
+OtherObject.dowork(rolst);</code></p>
+</blockquote>
+<p>Please see the reference manual for details on available wrapper
+classes.</p>
+<h1><a class="mozTocH1" name="mozTocId6619"></a><a name="datastructures">Collection
+classes by data structure/class</a></h1>
+<p>The following table&nbsp;shows the underlying data structure of the
+various collection classes.</p>
+<table border="1">
+ <tbody>
+ <tr>
+ <th>Data structure</th>
+ <th>Classes</th>
+ <th>Primary Interfaces</th>
+ </tr>
+ <tr>
+ <td>hash table</td>
+ <td>HashSet&lt;T&gt;</td>
+ <td> ICollection&lt;T&gt;</td>
+ </tr>
+ <tr>
+ <td>hash table</td>
+ <td>HashBag&lt;T&gt;</td>
+ <td> ICollection&lt;T&gt;</td>
+ </tr>
+ <tr>
+ <td>hash table</td>
+ <td>HashDictionary&lt;K,V&gt;</td>
+ <td>IDictionary&lt;K,V&gt;</td>
+ </tr>
+ <tr>
+ <td>linked list</td>
+ <td>LinkedList&lt;T&gt;</td>
+ <td>IList&lt;T&gt;</td>
+ </tr>
+ <tr>
+ <td>linked list with hash index</td>
+ <td>HashedLinkedList&lt;T&gt;</td>
+ <td>IList&lt;T&gt;</td>
+ </tr>
+ <tr>
+ <td>dynamic array</td>
+ <td>ArrayList&lt;T&gt;</td>
+ <td>IList&lt;T&gt;</td>
+ </tr>
+ <tr>
+ <td>dynamic array with hash index</td>
+ <td>HashedArrayList&lt;T&gt;</td>
+ <td>IList&lt;T&gt;</td>
+ </tr>
+ <tr>
+ <td>sorted dynamic array</td>
+ <td>SortedArray&lt;T&gt;</td>
+ <td>IIndexedSorted&lt;T&gt;</td>
+ </tr>
+ <tr>
+ <td>heap</td>
+ <td>IntervalHeap&lt;T&gt;</td>
+ <td>IPriorityQueue&lt;T&gt;</td>
+ </tr>
+ <tr>
+ <td>red-black search tree</td>
+ <td>TreeSet&lt;T&gt;</td>
+ <td>IIndexedSorted&lt;T&gt;, IPersistentSorted&lt;T&gt;</td>
+ </tr>
+ <tr>
+ <td>red-black search tree</td>
+ <td>TreeBag&lt;T&gt;</td>
+ <td>IIndexedSorted&lt;T&gt;, IPersistentSorted&lt;T&gt;</td>
+ </tr>
+ <tr>
+ <td>red-black search tree</td>
+ <td>TreeDictionary&lt;K,V&gt;</td>
+ <td>ISortedDictionary&lt;K,V&gt;</td>
+ </tr>
+ </tbody>
+</table>
+<br>
+<h1><a class="mozTocH1" name="mozTocId393559"></a>&lt;&gt;<a
+ name="planned"></a>Planned<span style="font-weight: bold;"> </span>architecture
+or interface changes
+for first release<br>
+</h1>
+<ol>
+ <li>Eliminate the use of our own generic equality/comparator types,
+C5.IComparer&lt;T&gt; and C5.IEqualityComparer&lt;T&gt; and use the new design of
+VS 2005 beta1 in the form of the combined
+System.Collections.Generic.IComparer&lt;T&gt;.</li>
+ <li>Vararg (params) constructors? (And IEnum do.)</li>
+ <li>Possibly extended use of "wildcard style" operations like
+AddAll&lt;U&gt;(IEnumerable&lt;U&gt; items)?</li>
+ <li>Make all collection classes clonable and serializable.</li>
+</ol>
+<h1><a class="mozTocH1" name="mozTocId336849"></a><a
+ name="PerformanceProper">Performance</a> details for proper collection
+classes</h1>
+<p>This section overviews the complexities of cc public methods and
+property
+accesses.</p>
+<p>In the table below, for lack of space we use the following numbers
+to
+identify collection classes:</p>
+<table border="1">
+ <tbody>
+ <tr>
+ <th>Class</th>
+ <th>Column</th>
+ </tr>
+ <tr>
+ <td>HashSet&lt;T&gt;</td>
+ <td>HS</td>
+ </tr>
+ <tr>
+ <td>HashBag&lt;T&gt;</td>
+ <td>HB</td>
+ </tr>
+ <tr>
+ <td>ArrayList&lt;T&gt;</td>
+ <td>AL</td>
+ </tr>
+ <tr>
+ <td>LinkedList&lt;T&gt;</td>
+ <td>LL</td>
+ </tr>
+ <tr>
+ <td>HashedArrayList&lt;T&gt;</td>
+ <td>HAL</td>
+ </tr>
+ <tr>
+ <td>HashedLinkedList&lt;T&gt;</td>
+ <td>HLL</td>
+ </tr>
+ <tr>
+ <td>TreeSet&lt;T&gt;</td>
+ <td>RBTS</td>
+ </tr>
+ <tr>
+ <td>TreeBag&lt;T&gt;</td>
+ <td>RBTB</td>
+ </tr>
+ <tr>
+ <td>SortedArray&lt;T&gt;</td>
+ <td>SA</td>
+ </tr>
+ <tr>
+ <td>IntervalHeap&lt;T&gt;</td>
+ <td>IH</td>
+ </tr>
+ </tbody>
+</table>
+<p>And the following special symbols:&nbsp;</p>
+<p>
+n size of collection,&nbsp;<br>
+m size of argument if collection-: not supported<br>
+*: means: suboptimal complexity (library is in error)<br>
+$: special at end: the operation is much faster at the start and/or end
+(end for
+array list, both for linked list)
+</p>
+<p>Note: we do not show return type&nbsp; or parameters for methods,
+just mark
+with ()<br>
+Note: we ignore time for reclaiming of internal array space (e.g. Clear)<br>
+User supplied operations like comparers or equalityComparers are assumed to be
+O(1)</p>
+<table border="1" height="2893" width="100%">
+ <tbody>
+ <tr>
+ <th height="23" width="9%">Member</th>
+ <th height="23" width="8%">HS</th>
+ <th height="23" width="8%">HB</th>
+ <th height="23" width="8%">AL</th>
+ <th height="23" width="8%">LL</th>
+ <th height="23" width="8%">HAL</th>
+ <th height="23" width="8%">HLL</th>
+ <th height="23" width="8%">RBTS</th>
+ <th height="23" width="8%">RBTB</th>
+ <th height="23" width="9%">SA</th>
+ <th height="23" width="9%">IH</th>
+ </tr>
+ <tr>
+ <td height="22" width="14%"><i><font color="#808080" size="2">&nbsp;IEnumerable&lt;T&gt;</font></i></td>
+ <td height="22" width="8%">&nbsp;&nbsp;</td>
+ <td height="22" width="8%">&nbsp;</td>
+ <td height="22" width="8%">&nbsp;</td>
+ <td height="22" width="8%">&nbsp;</td>
+ <td height="22" width="8%">&nbsp;</td>
+ <td height="22" width="8%">&nbsp;</td>
+ <td height="22" width="8%">&nbsp;</td>
+ <td height="22" width="8%">&nbsp;</td>
+ <td height="22" width="9%">&nbsp;</td>
+ <td height="22" width="9%">&nbsp;</td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">GetEnumerator()</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">O(1)</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="14%"><i><font color="#808080" size="2">IDirectedEnumerable&lt;T&gt;</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">HS</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">HB</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">AL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">LL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">HAL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">HLL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">RBTS</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">RBTB</font></i></td>
+ <td align="center" height="22" width="9%"><i><font color="#808080"
+ size="2">SA</font></i></td>
+ <td align="center" height="22" width="9%"><i><font color="#808080"
+ size="2">IH</font></i></td>
+ </tr>
+ <tr>
+ <td height="22" width="18%"><font size="2">Direction</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="18%"><font size="2">Backwards()</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="14%"><i><font color="#808080" size="2">ICollectionValue&lt;T&gt;</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">HS</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">HB</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">AL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">LL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">HAL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">HLL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">RBTS</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">RBTB</font></i></td>
+ <td align="center" height="22" width="9%"><i><font color="#808080"
+ size="2">SA</font></i></td>
+ <td align="center" height="22" width="9%"><i><font color="#808080"
+ size="2">IH</font></i></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">Count</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">O(1)</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="18%"><font size="2">CopyTo</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="9%"><font size="2">O(n)</font></td>
+ <td height="22" width="9%"><font size="2">O(n)</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">ToArray</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="9%"><font size="2">O(n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">Apply()</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="9%"><font size="2">O(n)</font></td>
+ <td height="22" width="9%"><font size="2">O(n)</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">Exists()</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="9%"><font size="2">O(n)</font></td>
+ <td height="22" width="9%"><font size="2">O(n)</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">All()</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="9%"><font size="2">O(n)</font></td>
+ <td height="22" width="9%"><font size="2">O(n)</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="14%"><i><font color="#808080" size="2">IDirectedCollectionValue&lt;T&gt;</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">HS</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">HB</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">AL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">LL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">HAL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">HLL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">RBTS</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">RBTB</font></i></td>
+ <td align="center" height="22" width="9%"><i><font color="#808080"
+ size="2">SA</font></i></td>
+ <td align="center" height="22" width="9%"><i><font color="#808080"
+ size="2">IH</font></i></td>
+ </tr>
+ <tr>
+ <td height="22" width="18%"><font size="2">Backwards()</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="13%"><i><font color="#808080" size="2">IExtensible&lt;T&gt;</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">HS</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">HB</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">AL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">LL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">HAL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">HLL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">RBTS</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">RBTB</font></i></td>
+ <td align="center" height="22" width="9%"><i><font color="#808080"
+ size="2">SA</font></i></td>
+ <td align="center" height="22" width="9%"><i><font color="#808080"
+ size="2">IH</font></i></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">AllowsDuplicates</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">O(1)</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">SyncRoot</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">O(1)</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">IsEmpty</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">O(1)</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">Add</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">AddAll</font></td>
+ <td height="22" width="8%"><font size="2">O(m)</font></td>
+ <td height="22" width="8%"><font size="2">O(m)</font></td>
+ <td height="22" width="8%"><font size="2">O(m)</font></td>
+ <td height="22" width="8%"><font size="2">O(m)</font></td>
+ <td height="22" width="8%"><font size="2">O(m)</font></td>
+ <td height="22" width="8%"><font size="2">O(m)</font></td>
+ <td height="22" width="8%"><font size="2">O(mlog n)</font></td>
+ <td height="22" width="8%"><font size="2">O(mlog n)</font></td>
+ <td height="22" width="9%"><font size="2">O(mlog n)</font></td>
+ <td height="22" width="9%"><font size="2">??</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="14%"><i><font color="#808080" size="2">ICollection&lt;T&gt;</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">HS</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">HB</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">AL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">LL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">HAL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">HLL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">RBTS</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">RBTB</font></i></td>
+ <td align="center" height="22" width="9%"><i><font color="#808080"
+ size="2">SA</font></i></td>
+ <td align="center" height="22" width="9%"><i><font color="#808080"
+ size="2">IH</font></i></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">IsReadOnly</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">ContainsSpeed</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">GetHashCode</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">Equals</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">Contains</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">ContainsCount</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">ContainsAll</font></td>
+ <td height="22" width="8%"><font size="2">O(m)</font></td>
+ <td height="22" width="8%"><font size="2">O(m)</font></td>
+ <td height="22" width="8%"><font size="2">O(mn)*</font></td>
+ <td height="22" width="8%"><font size="2">O(mn)*</font></td>
+ <td height="22" width="8%"><font size="2">O(m)</font></td>
+ <td height="22" width="8%"><font size="2">O(m)</font></td>
+ <td height="22" width="8%"><font size="2">O(m logn)</font></td>
+ <td height="22" width="8%"><font size="2">O(m logn)</font></td>
+ <td height="22" width="9%"><font size="2">O(m logn)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">Find</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">FindOrAdd</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">Update</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">UpdateOrAdd</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">Remove</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">RemoveWithReturn</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">RemoveAllCopies</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">RemoveAll</font></td>
+ <td height="22" width="8%"><font size="2">O(m)</font></td>
+ <td height="22" width="8%"><font size="2">O(m)</font></td>
+ <td height="22" width="8%"><font size="2">O(mn)*</font></td>
+ <td height="22" width="8%"><font size="2">O(mn)*</font></td>
+ <td height="22" width="8%"><font size="2">O(m+n)</font></td>
+ <td height="22" width="8%"><font size="2">O(m)</font></td>
+ <td height="22" width="8%"><font size="2">O(m logn)</font></td>
+ <td height="22" width="8%"><font size="2">O(m logn)</font></td>
+ <td height="22" width="9%"><font size="2">O(m logn)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">Clear</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">RetainAll</font></td>
+ <td height="22" width="8%"><font size="2">O(m)?</font></td>
+ <td height="22" width="8%"><font size="2">O(m)</font></td>
+ <td height="22" width="8%"><font size="2">O(mn)*</font></td>
+ <td height="22" width="8%"><font size="2">O(mn)*</font></td>
+ <td height="22" width="8%"><font size="2">O(m+n)</font></td>
+ <td height="22" width="8%"><font size="2">O(m)</font></td>
+ <td height="22" width="8%"><font size="2">O(m logn)</font></td>
+ <td height="22" width="8%"><font size="2">O(m logn)</font></td>
+ <td height="22" width="9%"><font size="2">O(m logn)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="14%"><i><font color="#808080" size="2">ISequenced&lt;T&gt;</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">HS</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">HB</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">AL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">LL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">HAL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">HLL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">RBTS</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">RBTB</font></i></td>
+ <td align="center" height="22" width="9%"><i><font color="#808080"
+ size="2">SA</font></i></td>
+ <td align="center" height="22" width="9%"><i><font color="#808080"
+ size="2">IH</font></i></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">GetHashCode</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">Equals</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="14%"><i><font color="#808080" size="2">IIndexed&lt;T&gt;</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">HS</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">HB</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">AL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">LL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">HAL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">HLL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">RBTS</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">RBTB</font></i></td>
+ <td align="center" height="22" width="9%"><i><font color="#808080"
+ size="2">SA</font></i></td>
+ <td align="center" height="22" width="9%"><i><font color="#808080"
+ size="2">IH</font></i></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">this[i]</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)$</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)$</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">this[start,end]</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">IndexOf()</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">LastIndexOf()</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">RemoveAt</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(n)$</font></td>
+ <td height="22" width="8%"><font size="2">O(n)$</font></td>
+ <td height="22" width="8%"><font size="2">O(n)$</font></td>
+ <td height="22" width="8%"><font size="2">O(n)$</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">RemoveInterval</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n log n)*</font></td>
+ <td height="22" width="8%"><font size="2">O(n log n)*</font></td>
+ <td height="22" width="9%"><font size="2">O(n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="14%"><i><font color="#808080" size="2">IList&lt;T&gt;</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">HS</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">HB</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">AL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">LL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">HAL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">HLL</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">RBTS</font></i></td>
+ <td align="center" height="22" width="8%"><i><font color="#808080"
+ size="2">RBTB</font></i></td>
+ <td align="center" height="22" width="9%"><i><font color="#808080"
+ size="2">SA</font></i></td>
+ <td align="center" height="22" width="9%"><i><font color="#808080"
+ size="2">IH</font></i></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">First</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">Last</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">FIFO</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">this[i]</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)$</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)$</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">Base</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">Offset</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">Map()</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">Insert()</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(n)$</font></td>
+ <td height="22" width="8%"><font size="2">O(n)$</font></td>
+ <td height="22" width="8%"><font size="2">O(n)$</font></td>
+ <td height="22" width="8%"><font size="2">O(n)$</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">InsertFirst()</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">InsertLast()</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">InsertBefore()</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">InsertAfter()</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">InsertAll()</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(m+n)</font></td>
+ <td height="22" width="8%"><font size="2">O(m+n)</font></td>
+ <td height="22" width="8%"><font size="2">O(m+n)</font></td>
+ <td height="22" width="8%"><font size="2">O(m+n)</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">FindAll()</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">Remove()</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(n)$</font></td>
+ <td height="22" width="8%"><font size="2">(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)$</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">RemoveFirst()</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">RemoveLast()</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">View()</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">Slide() (amount: d)</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(d)</font></td>
+ <td height="22" width="8%"><font size="2">O(d)</font></td>
+ <td height="22" width="8%"><font size="2">O(d)</font></td>
+ <td height="22" width="8%"><font size="2">O(d)</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">Reverse()</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">IsSorted()</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">Sort()</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(n log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n log n)</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">Shuffle()</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="14%"><i><font color="#808080" size="2">IPriorityQueue&lt;T&gt;</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">HS</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">HB</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">AL</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">LL</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">HAL</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">HLL</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">RBTS</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">RBTB</font></i></td>
+ <td height="22" width="9%"><i><font color="#808080" size="2">SA</font></i></td>
+ <td height="22" width="9%"><i><font color="#808080" size="2">IH</font></i></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">FindMin()</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(1)</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">DeleteMin()</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">FindMax()</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(1)</font></td>
+ </tr>
+ <tr>
+ <td height="30" width="9%"><font size="2">DeleteMax()</font></td>
+ <td height="30" width="8%"><font size="2">-</font></td>
+ <td height="30" width="8%"><font size="2">-</font></td>
+ <td height="30" width="8%"><font size="2">-</font></td>
+ <td height="30" width="8%"><font size="2">-</font></td>
+ <td height="30" width="8%"><font size="2">-</font></td>
+ <td height="30" width="8%"><font size="2">-</font></td>
+ <td height="30" width="8%"><font size="2">O(log n)</font></td>
+ <td height="30" width="8%"><font size="2">O(log n)</font></td>
+ <td height="30" width="9%"><font size="2">O(log n)</font></td>
+ <td height="30" width="9%"><font size="2">O(log n)</font></td>
+ </tr>
+ <tr>
+ <td height="30" width="9%"> <font size="2">Comparer</font></td>
+ <td height="30" width="8%"> <font size="2">-</font></td>
+ <td height="30" width="8%"> <font size="2">-</font></td>
+ <td height="30" width="8%"> <font size="2">-</font></td>
+ <td height="30" width="8%"> <font size="2">-</font></td>
+ <td height="30" width="8%"> <font size="2">-</font></td>
+ <td height="30" width="8%"> <font size="2">-</font></td>
+ <td height="30" width="8%"> <font size="2">O(1)</font></td>
+ <td height="30" width="8%"> <font size="2">O(1)</font></td>
+ <td height="30" width="9%"> <font size="2">O(1)</font></td>
+ <td height="30" width="9%"> <font size="2">O(1)</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="14%"><i><font color="#808080" size="2">ISorted&lt;T&gt;</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">HS</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">HB</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">AL</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">LL</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">HAL</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">HLL</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">RBTS</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">RBTB</font></i></td>
+ <td height="22" width="9%"><i><font color="#808080" size="2">SA</font></i></td>
+ <td height="22" width="9%"><i><font color="#808080" size="2">IH</font></i></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">Predecessor</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">Successor</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">WeakPredecessor</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">WeakSuccessor</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">Cut</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">RangeFrom</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">RangeFromTo</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">RangeTo</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">RangeAll</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">AddSorted</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">?</font></td>
+ <td height="22" width="8%"><font size="2">?</font></td>
+ <td height="22" width="9%"><font size="2">?</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">RemoveRangeFrom</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(nlog n)*</font></td>
+ <td height="22" width="8%"><font size="2">O(nlog n)*</font></td>
+ <td height="22" width="9%"><font size="2">O(n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">RemoveRangeFromTo</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(nlog n)*</font></td>
+ <td height="22" width="8%"><font size="2">O(nlog n)*</font></td>
+ <td height="22" width="9%"><font size="2">O(n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">RemoveRangeTo</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(nlog n)*</font></td>
+ <td height="22" width="8%"><font size="2">O(nlog n)*</font></td>
+ <td height="22" width="9%"><font size="2">O(n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="14%"><i><font color="#808080" size="2">IIndexedSorted&lt;T&gt;</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">HS</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">HB</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">AL</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">LL</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">HAL</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">HLL</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">RBTS</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">RBTB</font></i></td>
+ <td height="22" width="9%"><i><font color="#808080" size="2">SA</font></i></td>
+ <td height="22" width="9%"><i><font color="#808080" size="2">IH</font></i></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">Map</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="9%"><font size="2">O(n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">CountFrom</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">CountFromTo</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">CountTo</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">RangeFrom</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">RangeFromTo</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">RangeTo</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="8%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">O(log n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">FindAll</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="8%"><font size="2">O(n)</font></td>
+ <td height="22" width="9%"><font size="2">O(n)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="14%"><i><font color="#808080" size="2">IPersistentSorted&lt;T&gt;</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">HS</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">HB</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">AL</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">LL</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">HAL</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">HLL</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">RBTS</font></i></td>
+ <td height="22" width="8%"><i><font color="#808080" size="2">RBTB</font></i></td>
+ <td height="22" width="9%"><i><font color="#808080" size="2">SA</font></i></td>
+ <td height="22" width="9%"><i><font color="#808080" size="2">IH</font></i></td>
+ </tr>
+ <tr>
+ <td height="22" width="9%"><font size="2">Snapshot()</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">-</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="8%"><font size="2">O(1)</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ <td height="22" width="9%"><font size="2">-</font></td>
+ </tr>
+ </tbody>
+</table>
+<h1><a class="mozTocH1" name="mozTocId712409"></a><a
+ name="PerformanceDict">Performance</a> details for dictionary classes</h1>
+<table border="1" width="467">
+ <tbody>
+ <tr>
+ <th width="302">Member</th>
+ <th width="79">HashDictionary&lt;K,V&gt;</th>
+ <th width="64">TreeDictionary&lt;K,V&gt;</th>
+ </tr>
+ <tr>
+ <td width="302"><i><font color="#808080" size="2">IEnumerable&lt;KeyValuePair&lt;K,V&gt;&gt;</font></i></td>
+ <td width="79"><font color="#808080">&nbsp;</font></td>
+ <td width="64">&nbsp;</td>
+ </tr>
+ <tr>
+ <td width="302"><font size="2">GetEnumerator()</font></td>
+ <td width="79"><font size="2">O(1)</font></td>
+ <td width="64"><font size="2">O(1)</font></td>
+ </tr>
+ <tr>
+ <td width="302"><i><font color="#808080" size="2">IDictionary&lt;K,V&gt;</font></i></td>
+ <td width="79"><font color="#808080">&nbsp;</font></td>
+ <td width="64">&nbsp;</td>
+ </tr>
+ <tr>
+ <td width="302"><font size="2">this[key]</font></td>
+ <td width="79"><font size="2">O(1)</font></td>
+ <td width="64"><font size="2">O(log n)</font></td>
+ </tr>
+ <tr>
+ <td width="302"><font size="2">Count</font></td>
+ <td width="79"><font size="2">O(1)</font></td>
+ <td width="64"><font size="2">O(1)</font></td>
+ </tr>
+ <tr>
+ <td width="302"><font size="2">IsReadOnly</font></td>
+ <td width="79"><font size="2">O(1)</font></td>
+ <td width="64"><font size="2">O(1)</font></td>
+ </tr>
+ <tr>
+ <td width="302"><font size="2">SyncRoot</font></td>
+ <td width="79"><font size="2">O(1)</font></td>
+ <td width="64"><font size="2">O(1)</font></td>
+ </tr>
+ <tr>
+ <td width="302"><font size="2">Keys</font></td>
+ <td width="79"><font size="2">O(1)</font></td>
+ <td width="64"><font size="2">O(1)</font></td>
+ </tr>
+ <tr>
+ <td width="302"><font size="2">Values</font></td>
+ <td width="79"><font size="2">O(1)</font></td>
+ <td width="64"><font size="2">O(1)</font></td>
+ </tr>
+ <tr>
+ <td width="302"><font size="2">Add()</font></td>
+ <td width="79"><font size="2">O(1)</font></td>
+ <td height="22" width="64"><font size="2">O(log n)</font></td>
+ </tr>
+ <tr>
+ <td width="302"><font size="2">Remove()</font></td>
+ <td width="79"><font size="2">O(1)</font></td>
+ <td height="22" width="64"><font size="2">O(log n)</font></td>
+ </tr>
+ <tr>
+ <td width="302"><font size="2">Clear()</font></td>
+ <td width="79"><font size="2">O(1)</font></td>
+ <td height="22" width="64"><font size="2">O(1)</font></td>
+ </tr>
+ <tr>
+ <td width="302"><font size="2">Contains()</font></td>
+ <td width="79"><font size="2">O(1)</font></td>
+ <td height="22" width="64"><font size="2">O(log n)</font></td>
+ </tr>
+ <tr>
+ <td width="302"><font size="2">Find()</font></td>
+ <td width="79"><font size="2">O(1)</font></td>
+ <td height="22" width="64"><font size="2">O(log n)</font></td>
+ </tr>
+ <tr>
+ <td width="302"><font size="2">Update()</font></td>
+ <td width="79"><font size="2">O(1)</font></td>
+ <td height="22" width="64"><font size="2">O(log n)</font></td>
+ </tr>
+ <tr>
+ <td width="302"><font size="2">FindOrAdd</font></td>
+ <td width="79"><font size="2">O(1)</font></td>
+ <td height="22" width="64"><font size="2">O(log n)</font></td>
+ </tr>
+ <tr>
+ <td width="302"><font size="2">UpdateOrAdd</font></td>
+ <td width="79"><font size="2">O(1)</font></td>
+ <td height="22" width="64"><font size="2">O(log n)</font></td>
+ </tr>
+ <tr>
+ <td width="302"><i><font color="#808080" size="2">ISortedDictionary&lt;K,V&gt;</font></i></td>
+ <td width="79"><font color="#808080">&nbsp;</font></td>
+ <td width="64">&nbsp;</td>
+ </tr>
+ <tr>
+ <td height="22" width="302"><font size="2">Predecessor</font></td>
+ <td width="79"><font size="2">-</font></td>
+ <td height="22" width="64"><font size="2">O(log n)</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="302"><font size="2">Successor</font></td>
+ <td width="79"><font size="2">-</font></td>
+ <td height="22" width="64"><font size="2">O(log n)</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="302"><font size="2">WeakPredecessor</font></td>
+ <td width="79"><font size="2">-</font></td>
+ <td height="22" width="64"><font size="2">O(log n)</font></td>
+ </tr>
+ <tr>
+ <td height="22" width="302"><font size="2">WeakSuccessor</font></td>
+ <td width="79"><font size="2">-</font></td>
+ <td height="22" width="64"><font size="2">O(log n)</font></td>
+ </tr>
+ </tbody>
+</table>
+</body>
+</html>
diff --git a/mcs/class/Mono.C5/1.0/doc/docnet.cs b/mcs/class/Mono.C5/1.0/doc/docnet.cs
new file mode 100644
index 00000000000..7ca6e48dbcf
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/doc/docnet.cs
@@ -0,0 +1,772 @@
+/*
+ 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.
+*/
+
+// DocNet.cs
+// Author: Antonio Cisternino
+// Version: 0.1
+// Last update: 5/12/2001
+// Modified Jan 2004 by kokholm@itu.dk
+
+using System;
+using System.IO;
+using System.Reflection;
+using System.Xml;
+using System.Text;
+using System.Diagnostics;
+
+namespace DocNet
+{
+ class DocNet
+ {
+ private Assembly assembly;
+
+ //private XmlDocument xml;
+
+ private string defaultNamespace;
+
+ private string assemblyName;
+
+ private static C5.HashDictionary<string, string> longtype2short;
+
+ private static C5.HashDictionary<string, XmlNode> cachedDocComments;
+
+ static DocNet()
+ {
+ longtype2short = new C5.HashDictionary<string, string>();
+ cachedDocComments = new C5.HashDictionary<string, XmlNode>();
+ longtype2short.Add("System.Boolean", "bool");
+ longtype2short.Add("System.Byte", "byte");
+ longtype2short.Add("System.Int32", "int");
+ longtype2short.Add("System.Double", "double");
+ longtype2short.Add("System.Void", "void");
+ longtype2short.Add("System.Object", "object");
+ longtype2short.Add("System.String", "string");
+ longtype2short.Add("System.Collections.Generic.IEnumerable{T}", "IEnumerable{T}");
+ longtype2short.Add("System.Collections.Generic.IEnumerable{U}", "IEnumerable{U}");
+ //longtype2short.Add("", "");
+ }
+
+
+ DocNet(string a, string x, string defaultNamespace)
+ {
+ this.defaultNamespace = defaultNamespace;
+ assembly = Assembly.LoadFrom(a, null);
+ XmlDocument xml = new XmlDocument();
+ xml.Load(x);
+ assemblyName = xml.SelectSingleNode("doc/assembly/name").InnerXml;
+
+ if (!assembly.FullName.StartsWith(assemblyName + ","))
+ throw new Exception("Wrong assembly specified!\n>> " + assembly.FullName + "\n>> " + assemblyName);
+
+ foreach (XmlNode node in xml.SelectNodes("doc/members/member"))
+ cachedDocComments.Add(node.SelectNodes("@name").Item(0).Value, node);
+ }
+
+
+ private void CopyCodeDoc(XmlElement p, string xpath, XmlDocument ret)
+ {
+ XmlNode n;
+ //xml.SelectSingleNode(xpath);
+
+ if (cachedDocComments.Find(xpath, out n))
+ {
+ foreach (XmlNode child in n.ChildNodes)
+ p.AppendChild(ret.ImportNode(child, true));
+ }
+ //else
+ // Console.Error.WriteLine("docNet: {0} not found", xpath);
+ }
+
+ string xmlClean(string s)
+ {
+// return s.Replace("&", "&amp;").Replace("{", "&lt;").Replace("}", "&gt;").Replace("<", "&lt;").Replace(">", "&gt;");
+ return s.Replace("{", "<").Replace("}", ">");
+ }
+
+ private void AddSignature(XmlElement p, string signtext, XmlDocument ret)
+ {
+ XmlElement sign = CreateElement(ret, "Signature");
+
+ try
+ {
+ sign.InnerXml = signtext.Replace("&", "&amp;").Replace("{", "&lt;").Replace("}", "&gt;").Replace("<", "&lt;").Replace(">", "&gt;");
+ }
+ catch (XmlException)
+ {
+ Console.Error.WriteLine(signtext);
+ }
+ p.AppendChild(sign);
+ }
+
+ private void addImplements(XmlElement p, Type t, XmlDocument ret)
+ {
+ foreach (Type ty in t.GetInterfaces())
+ {
+ XmlElement impl = CreateElement(ret, "Implements");
+
+ if (ty.Assembly == assembly)
+ {
+ impl.SetAttribute("refid", "T:" + canonicalTypeName(ty, null));
+ impl.SetAttribute("C5", "");
+ }
+ AddSignature(impl, prettyTypeName(ty), ret);
+ p.AppendChild(impl);
+ }
+ }
+
+ private void addBases(XmlElement p, Type t, XmlDocument ret)
+ {
+ Type ty = t.BaseType;
+
+ while (ty != null)
+ {
+ XmlElement @base = CreateElement(ret, "Bases");
+
+ if (ty.Assembly == assembly)
+ {
+ @base.SetAttribute("refid", "T:" + canonicalTypeName(ty, null));
+ @base.SetAttribute("C5", "");
+ }
+
+ AddSignature(@base, prettyTypeName(ty), ret);
+ p.PrependChild(@base);
+ ty = ty.BaseType;
+ }
+ }
+
+
+
+ private XmlElement CreateElement(XmlDocument ret, string name)
+ {
+ return ret.CreateElement(null, name, null);
+ }
+
+ private void VisitField(bool inherited, FieldInfo f, XmlElement type, XmlDocument refman)
+ {
+ if (f.Name.Equals("value__"))
+ return;
+ string refid = "F:" + canonicalTypeName(f.DeclaringType, null) + "." + f.Name;
+ //string xpath = "doc/members/member[@name = \"" + refid + "\"]";
+ XmlElement el = CreateElement(refman, "Field");
+
+ el.SetAttribute("Name", f.Name);
+ el.SetAttribute("refid", refid);
+ el.SetAttribute("Static", f.IsStatic.ToString());
+ el.SetAttribute("Declared", xmlClean(prettyTypeName(f.DeclaringType)));
+ el.SetAttribute("CDeclared", canonicalTypeName(f.DeclaringType, null));
+ el.SetAttribute("Type", xmlClean(prettyTypeName(f.FieldType)));
+ el.SetAttribute("Access", f.IsPublic ? "public" : (f.IsPrivate || f.IsAssembly ? "private" : "protected"));
+ if (f.DeclaringType.Assembly == assembly)
+ el.SetAttribute("C5", "");
+
+ if (inherited)
+ el.SetAttribute("Inherited", "");
+
+ AddSignature(el, /*prettyTypeName(f.FieldType) + " " +*/ f.Name, refman);
+ CopyCodeDoc(el, refid, refman);
+ //AddSummary(el, xpath + "/summary", ret, doc);
+ type.AppendChild(el);
+ }
+
+ private void VisitEvent(bool inherited, EventInfo e, XmlElement type, XmlDocument ret)
+ {
+ string refid = "E:" + canonicalTypeName(e.DeclaringType, null) + "." + e.Name;
+ //string xpath = "doc/members/member[@name = \"" + refid + "\"]";
+ XmlElement el = CreateElement(ret, "Event");
+
+ el.SetAttribute("Name", e.Name);
+ el.SetAttribute("refid", refid);
+ //el.SetAttribute("Static", f.IsStatic.ToString());
+ //TODO: check virtual and final values on adders/removers
+ //el.SetAttribute("Virtual", e..IsVirtual.ToString());
+ //el.SetAttribute("Final", e.IsFinal.ToString());
+ el.SetAttribute("Declared", xmlClean(prettyTypeName(e.DeclaringType)));
+ el.SetAttribute("CDeclared", canonicalTypeName(e.DeclaringType, null));
+ el.SetAttribute("Type", xmlClean(prettyTypeName(e.EventHandlerType)));
+ MethodInfo addMethod = e.GetAddMethod(true);
+ el.SetAttribute("Access", addMethod.IsPublic ? "public" : addMethod.IsFamily ? "protected" : "private");//NBNBNB! e.IsPublic ? "public" : (e.IsPrivate || e.IsAssembly ? "private" : "protected"));
+ if (e.DeclaringType.Assembly == assembly)
+ el.SetAttribute("C5", "");
+
+ if (inherited)
+ el.SetAttribute("Inherited", "");
+
+ AddSignature(el, /*prettyTypeName(e.EventHandlerType) + " " +*/ e.Name, ret);
+ CopyCodeDoc(el, refid, ret);
+ //AddSummary(el, xpath + "/summary", ret, doc);
+ type.AppendChild(el);
+ }
+
+
+ private void VisitProperty(bool inherited, PropertyInfo p, XmlElement type, XmlDocument ret)
+ {
+ string refid = "P:" + canonicalPropertyName(p);
+ string xpath = "doc/members/member[@name = \"" + refid + "\"]";
+ XmlElement el = CreateElement(ret, "Property");
+
+ el.SetAttribute("Name", p.Name);
+ el.SetAttribute("refid", refid);
+ el.SetAttribute("Access", "public");//TODO: check if reasonable
+ MethodInfo m = p.CanRead ? p.GetGetMethod() : p.GetSetMethod();
+ if (m != null)
+ {
+ el.SetAttribute("Static", m.IsStatic.ToString());
+ el.SetAttribute("Abstract", m.IsAbstract.ToString());
+ el.SetAttribute("Virtual", m.IsVirtual.ToString());
+ el.SetAttribute("Final", m.IsFinal.ToString());
+ }
+ //else
+ //Console.Error.WriteLine("%%%%% {0} | {1}", p, p.DeclaringType);
+ el.SetAttribute("Declared", xmlClean(prettyTypeName(p.DeclaringType)));
+ el.SetAttribute("CDeclared", canonicalTypeName(p.DeclaringType, null));
+ el.SetAttribute("Get", p.CanRead.ToString());
+ el.SetAttribute("Set", p.CanWrite.ToString());
+ el.SetAttribute("Type", xmlClean(prettyTypeName(p.PropertyType)));
+
+ if (p.DeclaringType.Assembly == assembly)
+ el.SetAttribute("C5", "");
+
+ if (inherited)
+ el.SetAttribute("Inherited", "");
+
+ if (p.Name.Equals("Item"))
+ AddSignature(el, prettyIndexerSignature(p), ret);
+ else
+ AddSignature(el, /*prettyTypeName(p.PropertyType) + " " +*/ p.Name, ret);
+
+ //AddSummary(el, xpath + "/summary", ret, doc);
+ CopyCodeDoc(el, refid, ret);
+ //AddValue(el, xpath + "/value", ret, doc);
+ VisitParameters(p.GetIndexParameters(), el, ret, xpath);
+ type.AppendChild(el);
+ }
+
+
+ private void VisitParameters(ParameterInfo[] pars, XmlElement n, XmlDocument ret, string xpath)
+ {
+ foreach (ParameterInfo p in pars)
+ {
+ XmlElement el = CreateElement(ret, "Parameter");
+
+ el.SetAttribute("Name", p.Name);
+ el.SetAttribute("Type", prettyTypeName(p.ParameterType));
+ //AddSummary(el, xpath + "/param[@name = \"" + p.Name + "\"]", ret, doc);
+ CopyCodeDoc(el, xpath + "/param[@name = \"" + p.Name + "\"]", ret);
+
+ n.AppendChild(el);
+ }
+ }
+
+
+ private void VisitConstructor(Type t, ConstructorInfo c, XmlElement type, XmlDocument ret)
+ {
+ Type declaringType = c.DeclaringType;
+ string refid = "M:" + canonicalTypeName(c.DeclaringType, null) + "." + "#ctor";
+
+ refid += canonicalParameters(c.GetParameters(), new string[]{});
+
+ string xpath = "doc/members/member[@name = \"" + refid + "\"]";
+ XmlElement el = CreateElement(ret, "Constructor");
+ el.SetAttribute("Foo", c.IsConstructor ? "Con" : "San");
+ el.SetAttribute("refid", refid);
+ el.SetAttribute("Declared", prettyTypeName(declaringType));
+ el.SetAttribute("CDeclared", canonicalTypeName(declaringType, null));
+ el.SetAttribute("Access", c.IsPublic ? "public" : (c.IsPrivate ? "private" : "protected"));
+ //el.SetAttribute("Access", c.IsPublic ? "public" : (c.IsPrivate || c.IsAssembly ? "private" : "protected"));
+ if (declaringType.Assembly == assembly)
+ el.SetAttribute("C5", "");
+ if (declaringType != t)
+ el.SetAttribute("Inherited", "");
+ AddSignature(el, prettyConstructorSignature(c), ret);
+ CopyCodeDoc(el, refid, ret);
+ //AddSummary(el, xpath + "/summary", ret, doc);
+ VisitParameters(c.GetParameters(), el, ret, xpath);
+ type.AppendChild(el);
+ }
+
+
+ private void VisitMethod(bool inherited, MethodInfo m, XmlElement type, XmlDocument ret)
+ {
+ if (m.Name.StartsWith("get_") || m.Name.StartsWith("set_") || m.Name.StartsWith("add_") || m.Name.StartsWith("remove_"))
+ return;
+ bool isOperator = m.Name.StartsWith("op_");
+
+ string refid = "M:" + canonicalMethodName(m);
+
+ string xpath = "doc/members/member[@name = \"" + refid + "\"]";
+ XmlElement el = CreateElement(ret, isOperator ? "Operator" : "Method");
+
+ string mangledName = m.Name;
+ if (isOperator)
+ {
+ switch (mangledName)
+ {
+ case "op_Equality": mangledName = "operator =="; break;
+ case "op_Inequality": mangledName = "operator !="; break;
+ default: throw new ApplicationException("unknown operatorname, " + mangledName);
+ }
+ }
+ el.SetAttribute("Name", mangledName);
+ el.SetAttribute("refid", refid);
+ el.SetAttribute("Static", m.IsStatic.ToString());
+ el.SetAttribute("Abstract", m.IsAbstract.ToString());
+ el.SetAttribute("Virtual", m.IsVirtual.ToString());
+ el.SetAttribute("Final", m.IsFinal.ToString());
+ el.SetAttribute("Declared", xmlClean(prettyTypeName(m.DeclaringType)));
+ el.SetAttribute("CDeclared", canonicalTypeName(m.DeclaringType, null));
+ el.SetAttribute("ReturnType", xmlClean(prettyTypeName(m.ReturnType)));
+ if (m.DeclaringType.Assembly == assembly)
+ el.SetAttribute("C5", "");
+ if (inherited)
+ el.SetAttribute("Inherited", "");
+ el.SetAttribute("Access", m.IsPublic ? "public" : (m.IsPrivate || m.IsAssembly ? "private" : "protected"));
+ el.SetAttribute("Sealed", m.IsFinal.ToString());
+ AddSignature(el, prettyMethodSignature(mangledName, m), ret);
+ CopyCodeDoc(el, refid, ret);
+ VisitParameters(m.GetParameters(), el, ret, xpath);
+
+ foreach (Type gp in m.GetGenericArguments())
+ foreach (Type gc in gp.GetGenericParameterConstraints())
+ if (gc != typeof(object))
+ {
+ XmlElement constraint = CreateElement(ret, "constraint");
+ constraint.SetAttribute("Value", prettyTypeName(gp) + " : " + xmlClean(prettyTypeName(gc)));
+ el.AppendChild(constraint);
+ }
+ type.AppendChild(el);
+ }
+
+ public XmlDocument GenerateDoc()
+ {
+ BindingFlags flags = BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic;
+
+ XmlDocument ret = new XmlDocument();
+ XmlElement root = CreateElement(ret, "Assembly");
+
+ root.SetAttribute("Name", assemblyName);
+
+ ret.AppendChild(root);
+
+ XmlElement type = null;
+ //string xpath = null;
+
+ foreach (Type t in assembly.GetTypes())
+ {
+ if (t.Name.StartsWith("DocNet"))
+ continue;
+
+ if (t.IsInterface)
+ {
+ type = CreateElement(ret, "Interface");
+ foreach (EventInfo e in t.GetEvents(flags))
+ VisitEvent(e.DeclaringType != t, e, type, ret);
+
+ foreach (PropertyInfo p in t.GetProperties(flags))
+ VisitProperty(false, p, type, ret);
+
+ foreach (MethodInfo m in t.GetMethods(flags))
+ VisitMethod(false, m, type, ret);
+ }
+ else if (t.IsValueType)
+ {
+ type = CreateElement(ret, "Struct");
+ foreach (FieldInfo f in t.GetFields(flags))
+ VisitField(f.DeclaringType != t, f, type, ret);
+
+ foreach (EventInfo e in t.GetEvents(flags))
+ VisitEvent(e.DeclaringType != t, e, type, ret);
+
+ foreach (PropertyInfo p in t.GetProperties(flags))
+ VisitProperty(p.DeclaringType != t, p, type, ret);
+
+ foreach (ConstructorInfo c in t.GetConstructors(flags))
+ VisitConstructor(t, c, type, ret);
+
+ foreach (MethodInfo m in t.GetMethods(flags))
+ VisitMethod(m.DeclaringType != t, m, type, ret);
+ }
+ else if (t.IsSubclassOf(typeof(Delegate)))
+ {
+ type = CreateElement(ret, "Delegate");
+ VisitMethod(false, t.GetMethod("Invoke"), type, ret);
+ }
+ else
+ { // Class
+ type = CreateElement(ret, "Class");
+ foreach (FieldInfo f in t.GetFields(flags))
+ VisitField(f.DeclaringType != t, f, type, ret);
+
+ foreach (EventInfo e in t.GetEvents(flags))
+ VisitEvent(e.DeclaringType != t, e, type, ret);
+
+ foreach (PropertyInfo p in t.GetProperties(flags))
+ VisitProperty(p.DeclaringType != t, p, type, ret);
+
+ foreach (ConstructorInfo c in t.GetConstructors(flags))
+ VisitConstructor(t, c, type, ret);
+
+ foreach (MethodInfo m in t.GetMethods(flags))
+ VisitMethod(m.DeclaringType != t, m, type, ret);
+ }
+
+ type.SetAttribute("Name", xmlClean(prettyTypeName(t)));
+ type.SetAttribute("Access", t.IsPublic || t.IsNestedPublic ? "public" : t.IsNestedFamily ? "protected" : "private");
+
+ string refid = "T:" + canonicalTypeName(t, null);
+
+ type.SetAttribute("refid", refid);
+ type.SetAttribute("C5", "");
+ AddSignature(type, prettyTypeName(t), ret);
+ addImplements(type, t, ret);
+ addBases(type, t, ret);
+
+ foreach (Type gp in t.GetGenericArguments())
+ {
+ if (gp.GenericParameterAttributes != GenericParameterAttributes.None)
+ {
+ XmlElement constraint = CreateElement(ret, "constraint");
+ string constraintText = null;
+ switch (gp.GenericParameterAttributes)
+ {
+ case GenericParameterAttributes.Contravariant:
+ break;
+ case GenericParameterAttributes.Covariant:
+ break;
+ case GenericParameterAttributes.DefaultConstructorConstraint:
+ constraintText = "new()";
+ break;
+ case GenericParameterAttributes.None:
+ break;
+ case GenericParameterAttributes.ReferenceTypeConstraint:
+ constraintText = "class";
+ break;
+ case GenericParameterAttributes.SpecialConstraintMask:
+ break;
+ case GenericParameterAttributes.NotNullableValueTypeConstraint:
+ constraintText = "struct";
+ break;
+ case GenericParameterAttributes.VarianceMask:
+ break;
+ }
+ constraint.SetAttribute("Value", String.Format("{0} : {1}", gp, constraintText));
+ type.AppendChild(constraint);
+ }
+ foreach (Type gc in gp.GetGenericParameterConstraints())
+ {
+ if (gc != typeof(object))
+ {
+ XmlElement constraint = CreateElement(ret, "constraint");
+ constraint.SetAttribute("Value", String.Format("{0} : {1}", prettyTypeName(gp), xmlClean(prettyTypeName(gc))));
+ type.AppendChild(constraint);
+ }
+ }
+ }
+
+ CopyCodeDoc(type, refid, ret);
+ root.AppendChild(type);
+ }
+
+ return ret;
+ }
+
+ C5.HashDictionary<Type, string> t2ptn = new C5.HashDictionary<Type, string>();
+ private string prettyTypeName(Type t)
+ {
+ string retval;
+ //if (!t2ptn.Find(t, out retval))
+ //{
+ int consumed = 0;
+ retval = prettyTypeName(t, ref consumed);
+ // t2ptn.Add(t, retval);
+ //}
+ return retval;
+ }
+
+ private string prettyTypeName(Type t, ref int consumed)
+ {
+ StringBuilder ret = new StringBuilder();
+
+ if (t.IsGenericParameter)
+ ret.Append(t.Name);
+ else if (t.IsArray)
+ ret.Append(prettyTypeName(t.GetElementType()) + "[]");
+ else if (t.IsByRef)
+ ret.Append("ref ").Append(prettyTypeName(t.GetElementType()));
+ else if (!t.IsGenericType)
+ ret.Append(t.IsNested ? prettyTypeName(t.DeclaringType, ref consumed) + "." + t.Name : t.FullName);
+ else
+ {
+ bool first = true;
+ StringBuilder gps = new StringBuilder();
+ Type[] gp = t.GetGenericArguments();
+
+ ret.Append(t.IsNested ? prettyTypeName(t.DeclaringType, ref consumed) : t.Namespace).Append(".").Append(t.Name);
+ if (consumed < gp.Length)
+ {
+ //TODO: fix this ugly hack to remove `n
+ ret.Remove(ret.Length - 2, 2);
+ //ret = ret.Substring(0, ret.Length - 2);
+ for (int i = consumed, length = gp.Length; i < length; i++)
+ {
+ Type ty = gp[i];
+
+ if (first) first = false;
+ else
+ gps.Append(",");
+
+ gps.Append(prettyTypeName(ty));
+ }
+
+ consumed = gp.Length;
+ ret.Append("{").Append(gps.ToString()).Append("}");
+ }
+ }
+
+ string retval = ret.ToString();
+
+ if (retval.StartsWith(defaultNamespace + "."))
+ retval = retval.Substring(defaultNamespace.Length + 1);
+
+ if (longtype2short.Contains(retval))
+ retval = longtype2short[retval];
+
+ return retval;
+ }
+
+ private string prettyParameters(ParameterInfo[] pars)
+ {
+ string ret = "";
+ bool first = true;
+
+ foreach (ParameterInfo p in pars)
+ {
+ if (first) first = false;
+ else
+ ret += ", ";
+ Type pt = p.ParameterType;
+ if (p.IsOut)
+ {
+ ret += "out ";
+ pt = pt.GetElementType();
+ }
+
+ ret += prettyTypeName(pt) + " " + p.Name;
+ }
+
+ return ret;
+ }
+
+ private string prettyMethodSignature(string name, MethodInfo m)
+ {
+ string gp = "";
+ if (m.IsGenericMethod)
+ {
+ Type[] gps = m.GetGenericArguments();
+ gp = "<";
+
+ for (int i = 0; i < gps.Length; i++)
+ gp += (i == 0 ? "" : ",") + gps[i].Name;
+
+ gp += ">";
+ }
+
+ return name + gp + "(" + prettyParameters(m.GetParameters()) + ")";
+ }
+
+ private string prettyConstructorSignature(ConstructorInfo c)
+ {
+ Type t = c.DeclaringType;
+
+ return prettyTypeName(t) + "(" + prettyParameters(c.GetParameters()) + ")";
+ }
+
+ private string prettyIndexerSignature(PropertyInfo p)
+ {
+ return /*prettyTypeName(p.PropertyType) + " " + */ "this[" + prettyParameters(p.GetIndexParameters()) + "]";
+ }
+
+
+ private string simpleTypeName(Type t)
+ {
+ return (t.IsNested ? simpleTypeName(t.DeclaringType) : t.Namespace) + "." + t.Name;
+ }
+
+
+ private string canonicalTypeName(Type t, string[] mgps)
+ {
+ string ret;
+
+ if (t.IsGenericParameter)
+ ret = "`" + t.GenericParameterPosition;
+ else if (t.IsArray)
+ ret = canonicalTypeName(t.GetElementType(), mgps) + "[]";
+ else if (t.IsByRef)
+ ret = canonicalTypeName(t.GetElementType(), mgps) + "@";
+ else
+ {
+ ret = simpleTypeName(t);
+ if (!t.IsGenericType)
+ ret += "";
+ else if (mgps == null)
+ ret += "";//"`" + t.GetGenericArguments().Length;
+ else
+ {
+ //TODO: fix this ugly hack to remove `n
+ ret = ret.Substring(0, ret.Length - 2);
+
+ bool first = true;
+ string gps = "";
+ Type[] gp = t.GetGenericArguments();
+
+ foreach (Type ty in gp)
+ {
+ if (first) first = false;
+ else
+ gps += ",";
+
+ if (ty.IsGenericParameter)
+ {
+ bool ismgp = false;
+
+ foreach (string s in mgps) if (s.Equals(ty.Name)) ismgp = true;
+
+ gps += (ismgp ? "``" : "`") + ty.GenericParameterPosition;
+ }
+ else
+ gps += canonicalTypeName(ty, mgps);
+ }
+
+ ret += "{" + gps + "}";
+ }
+ }
+
+ return ret;
+ }
+
+ private string canonicalMethodName(MethodInfo m)
+ {
+ string ret = canonicalTypeName(m.DeclaringType, null) + "." + m.Name;
+
+ string[] gmps;
+
+ if (m.IsGenericMethod)
+ {
+ Type[] gps = m.GetGenericArguments();
+
+ ret += "``" + gps.Length;
+ gmps = new string[gps.Length];
+ for (int i = 0; i < gps.Length; i++)
+ gmps[i] = gps[i].Name;
+ }
+ else
+ gmps = new string[]{};
+
+ ret += canonicalParameters(m.GetParameters(), gmps);
+ return ret;
+ }
+
+ private string canonicalPropertyName(PropertyInfo p)
+ {
+ string pname = canonicalTypeName(p.DeclaringType, null) + "." + p.Name;
+ ParameterInfo[] pars = p.GetIndexParameters();
+
+ if (pars.Length > 0)
+ pname += canonicalParameters(pars, new string[]{});
+
+ return pname;
+ }
+
+ private string canonicalParameters(ParameterInfo[] pars, string[] gmps)
+ {
+ if (pars.Length == 0) return "";
+
+ string ret = "";
+ bool first = true;
+
+ foreach (ParameterInfo p in pars)
+ {
+ if (first) first = false;
+ else
+ ret += ",";
+
+ ret += canonicalTypeName(p.ParameterType, gmps); ;
+ }
+
+ return "(" + ret + ")";
+ }
+
+
+
+ static void Main(string[] args)
+ {
+ if (args.Length != 2)
+ {
+ args = new string[] { @"C5.dll", @"C5.xml" };
+
+ }
+ {
+ Timer timer = new Timer();
+ timer.snap();
+ DocNet doc = new DocNet(args[0], args[1], "C5");
+ XmlDocument merged = doc.GenerateDoc();
+ Console.Error.WriteLine("Time merge: {0} ms", timer.snap());
+
+ System.Xml.Xsl.XslCompiledTransform overview = new System.Xml.Xsl.XslCompiledTransform();
+ overview.Load(@"overview.xslt");
+ overview.Transform(merged, new XmlTextWriter(new StreamWriter(@"docbuild\contents.htm")));
+ Console.Error.WriteLine("Time, overview: {0} ms", timer.snap());
+
+ StringBuilder megaDoc = new StringBuilder();
+ using (XmlWriter writer = XmlWriter.Create(megaDoc))
+ {
+ writer.WriteStartElement("hack");
+ System.Xml.Xsl.XslCompiledTransform trans = new System.Xml.Xsl.XslCompiledTransform();
+ trans.Load(@"trans.xslt");
+ trans.Transform(merged, writer);
+ writer.WriteEndElement();
+ writer.Close();
+ }
+ Console.Error.WriteLine("Time trans: {0} ms", timer.snap());
+ System.Xml.XPath.XPathDocument megaXml =
+ new System.Xml.XPath.XPathDocument(XmlReader.Create(new StringReader(megaDoc.ToString())));
+ System.Xml.XPath.XPathNodeIterator nodes = megaXml.CreateNavigator().Select("/hack/*");
+ string docfn = null;
+ foreach (System.Xml.XPath.XPathNavigator var in nodes)
+ {
+ if (var.Name == "filestart")
+ docfn = var.GetAttribute("name", "");
+ if (var.Name == "html")
+ {
+ Console.Error.Write(".");
+ XmlWriter w = new XmlTextWriter(new StreamWriter(@"docbuild\types\" + docfn));
+ var.WriteSubtree(w);
+ w.Close();
+ }
+ }
+ Console.Error.WriteLine();
+ Console.Error.WriteLine("Time split: {0} ms", timer.snap());
+ }
+ Console.Write("? ");
+ Console.Read();
+ }
+ }
+}
+
diff --git a/mcs/class/Mono.C5/1.0/doc/dodoc.cmd b/mcs/class/Mono.C5/1.0/doc/dodoc.cmd
new file mode 100644
index 00000000000..3ed5141a139
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/doc/dodoc.cmd
@@ -0,0 +1,2 @@
+del docbuild\types\*.htm
+bin\Debug\docNet.exe ..\C5\bin\Debug\C5.dll ..\C5\c5.xml
diff --git a/mcs/class/Mono.C5/1.0/doc/mkcurrent.cmd b/mcs/class/Mono.C5/1.0/doc/mkcurrent.cmd
new file mode 100644
index 00000000000..65cc5607136
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/doc/mkcurrent.cmd
@@ -0,0 +1,10 @@
+cd c:\src\c5\src\C5\docNet\docbuild
+
+copy ..\..\C5\bin\Debug\C5.dll W:\research\c5\current
+copy ..\..\C5\bin\Debug\C5.pdb W:\research\c5\current
+
+rem del "W:\research\c5\current\types\*.htm"
+
+xcopy /Q *.htm W:\research\c5\current /S/Y
+copy docnet.css W:\research\c5\current
+pause
diff --git a/mcs/class/Mono.C5/1.0/doc/overview.xslt b/mcs/class/Mono.C5/1.0/doc/overview.xslt
new file mode 100644
index 00000000000..e410cd2318e
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/doc/overview.xslt
@@ -0,0 +1,65 @@
+<?xml version="1.0" ?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:output encoding = "ISO-8859-1"/>
+ <xsl:template match="/">
+ <html>
+ <head>
+ <title>
+ <xsl:text>DocNet documentation for</xsl:text>
+ <xsl:value-of select="Assembly/@Name" /></title>
+ <link rel="stylesheet" type="text/css" href="docnet.css" />
+ </head>
+ <body>
+ <h3>Interfaces overview</h3>
+ <xsl:for-each select="/Assembly/Interface[@Access != 'private']">
+ <xsl:sort select="@Name" />
+ <xsl:call-template name="htmllink" />
+ <xsl:if test="position()!=last()">,<br/> </xsl:if>
+ </xsl:for-each>
+ <h3>Classes overview</h3>
+ <xsl:for-each select="/Assembly/Class[@Access != 'private']">
+ <xsl:sort select="@Name" />
+ <xsl:call-template name="htmllink" />
+ <xsl:if test="position()!=last()">,<br/> </xsl:if>
+ </xsl:for-each>
+ <h3>Value Types overview</h3>
+ <xsl:for-each select="/Assembly/Struct[@Access != 'private']">
+ <xsl:sort select="@Name" />
+ <xsl:call-template name="htmllink" />
+ <xsl:if test="position()!=last()">,<br/> </xsl:if>
+ </xsl:for-each>
+ <h3>Delegates overview</h3>
+ <xsl:for-each select="/Assembly/Delegate[@Access != 'private']">
+ <xsl:sort select="@Name" />
+ <xsl:call-template name="htmllink" />
+ <xsl:if test="position()!=last()">,<br/> </xsl:if>
+ </xsl:for-each>
+ </body>
+ </html>
+ </xsl:template>
+ <xsl:template match="Signature">
+ <code>
+ <xsl:value-of select="." />
+ </code>
+ </xsl:template>
+ <xsl:template name="htmllink">
+ <xsl:choose>
+ <xsl:when test="@refid">
+ <xsl:element name="a">
+ <xsl:attribute name="href">
+ <!--xsl:text>main.htm#</xsl:text>
+ <xsl:value-of select="@refid" /-->
+ <xsl:text>types/</xsl:text><xsl:value-of select="substring(@refid,3)" /><xsl:text>.htm</xsl:text>
+ </xsl:attribute>
+ <xsl:attribute name="target">
+ <xsl:text>main</xsl:text>
+ </xsl:attribute>
+ <xsl:apply-templates select="Signature" />
+ </xsl:element>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates select="Signature" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/mcs/class/Mono.C5/1.0/doc/tolatex.xslt b/mcs/class/Mono.C5/1.0/doc/tolatex.xslt
new file mode 100644
index 00000000000..0e929b9079b
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/doc/tolatex.xslt
@@ -0,0 +1,43 @@
+<?xml version="1.0" ?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <xsl:output encoding = "ISO-8859-1" omit-xml-declaration="yes" indent="no"/>
+ <xsl:strip-space elements="*"/>
+ <xsl:template match="table">
+ <xsl:text>\begin{tabular}{lc|*{15}{c}}\hline\hline&#10;</xsl:text>
+ <xsl:apply-templates></xsl:apply-templates>
+ <xsl:text>\hline\hline&#10;\end{tabular}&#10;</xsl:text>
+ </xsl:template>
+ <xsl:template match="tr">
+ <xsl:choose>
+ <xsl:when test="td/i">
+ <xsl:text>\hline&#10;%</xsl:text><xsl:value-of select="td/i/font"/><xsl:text>&#10;</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:for-each select="th">
+ <xsl:if test="position()!=1">\turned{</xsl:if>
+ <xsl:apply-templates/>
+ <xsl:if test="position()!=1">}</xsl:if>
+ <xsl:if test="position()!=last()"><xsl:text disable-output-escaping="yes" >&#10;&amp;&#32;</xsl:text></xsl:if>
+ </xsl:for-each>
+ <xsl:for-each select="td">
+ <xsl:if test="position()=1">\texttt{</xsl:if>
+ <xsl:if test="position()!=1">$</xsl:if>
+ <xsl:apply-templates/>
+ <xsl:if test="position()=1">}</xsl:if>
+ <xsl:if test="position()!=1">$</xsl:if>
+ <xsl:if test="position()!=last()"><xsl:text disable-output-escaping="yes" >&#32;&amp;&#32;</xsl:text></xsl:if>
+ </xsl:for-each>
+ <!---->\\&#10;<!---->
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <xsl:template match ="th">
+ <xsl:apply-templates/>
+ </xsl:template>
+ <xsl:template match ="td">
+ <xsl:apply-templates/>
+ </xsl:template>
+ <xsl:template match="font">
+ <xsl:apply-templates/>
+ </xsl:template>
+</xsl:stylesheet> \ No newline at end of file
diff --git a/mcs/class/Mono.C5/1.0/doc/trans.xslt b/mcs/class/Mono.C5/1.0/doc/trans.xslt
new file mode 100644
index 00000000000..526c177acb7
--- /dev/null
+++ b/mcs/class/Mono.C5/1.0/doc/trans.xslt
@@ -0,0 +1,591 @@
+<?xml version="1.0" ?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <xsl:output encoding = "ISO-8859-1"/>
+ <xsl:template match="/">
+ <xsl:apply-templates select="/Assembly/Interface" />
+ <xsl:apply-templates select="/Assembly/Class" />
+ <xsl:apply-templates select="/Assembly/Struct" />
+ <xsl:apply-templates select="/Assembly/Delegate" />
+ </xsl:template>
+ <xsl:template match="/Assembly/Interface">
+ <xsl:call-template name="file"/>
+ </xsl:template>
+ <xsl:template match="/Assembly/Class">
+ <xsl:call-template name="file"/>
+ </xsl:template>
+ <xsl:template match="/Assembly/Struct">
+ <xsl:call-template name="file"/>
+ </xsl:template>
+ <xsl:template match="/Assembly/Delegate">
+ <xsl:call-template name="file"/>
+ </xsl:template>
+ <xsl:template name="file">
+ <xsl:if test="@Access[.!='private']">
+ <xsl:text>&#13;&#10;</xsl:text>
+ <xsl:element name="filestart">
+ <xsl:attribute name="name">
+ <xsl:value-of select="substring(@refid,3)"/>
+ <xsl:text>.htm</xsl:text>
+ </xsl:attribute>
+ </xsl:element>
+ <xsl:text>&#13;&#10;</xsl:text>
+ <html >
+ <head>
+ <title>
+ <xsl:text>C5 doc: </xsl:text>
+ <xsl:value-of select="@Name" />
+ </title>
+ <link rel="stylesheet" type="text/css" href="../docnet.css" />
+ </head>
+ <xsl:element name="body">
+ <xsl:attribute name="onLoad">
+ <xsl:text>parent.document.title ='C5 doc: </xsl:text>
+ <xsl:value-of select="@Name" />
+ <xsl:text>'</xsl:text>
+ </xsl:attribute>
+ <h2>
+ <xsl:value-of select="name()"/>
+ <xsl:text>&#32;</xsl:text>
+ <xsl:call-template name="htmlname" />
+ </h2>
+ <xsl:apply-templates select="summary" />
+ <xsl:call-template name="typeparams" />
+ <xsl:call-template name="implements" />
+ <xsl:call-template name="implementedby" />
+ <xsl:call-template name="super" />
+ <xsl:apply-templates select="Bases" />
+ <xsl:call-template name="baseof" />
+ <xsl:call-template name="foverview" />
+ <xsl:call-template name="eoverview" />
+ <xsl:call-template name="poverview" />
+ <xsl:call-template name="coverview" />
+ <xsl:call-template name="moverview" />
+ <xsl:call-template name="ooverview" />
+ <xsl:call-template name="ftable" />
+ <xsl:call-template name="etable" />
+ <xsl:call-template name="ptable" />
+ <xsl:call-template name="ctable" />
+ <xsl:call-template name="mtable" />
+ <xsl:call-template name="otable" />
+ </xsl:element>
+ </html>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template name="implements">
+ <xsl:for-each select="Implements">
+ <xsl:sort select="@refid" />
+ <xsl:if test="position()=1">
+ <h3>Implements</h3>
+ </xsl:if>
+ <xsl:call-template name="htmllink" />
+ <xsl:if test="position()!=last()">, </xsl:if>
+ </xsl:for-each>
+ </xsl:template>
+ <xsl:template name="super">
+ <xsl:variable name="leRefid" select="@refid" />
+ <xsl:for-each select="/Assembly/Interface[Implements[@refid = $leRefid ] and @Access != 'private']">
+ <xsl:sort select="@Name" />
+ <xsl:if test="position()=1">
+ <h3>Super</h3>
+ </xsl:if>
+ <xsl:call-template name="htmllink" />
+ <xsl:if test="position()!=last()">, </xsl:if>
+ </xsl:for-each>
+ </xsl:template>
+ <xsl:template name="implementedby">
+ <xsl:variable name="leRefid" select="@refid" />
+ <xsl:for-each select="/Assembly/Class[Implements[@refid = $leRefid ] and @Access != 'private']">
+ <xsl:sort select="@Name" />
+ <xsl:if test="position()=1">
+ <h3>Implemented by</h3>
+ </xsl:if>
+ <xsl:call-template name="htmllink" />
+ <xsl:if test="position()!=last()">, </xsl:if>
+ </xsl:for-each>
+ </xsl:template>
+ <xsl:template match="Bases">
+ <xsl:if test="position()=1">
+ <h3>Bases</h3>
+ </xsl:if>
+ <xsl:call-template name="htmllink" />
+ <xsl:if test="position()!=last()">, </xsl:if>
+ </xsl:template>
+ <xsl:template name="baseof">
+ <xsl:variable name="leRefid" select="@refid" />
+ <xsl:for-each select="/Assembly/Class[Bases[@refid = $leRefid ] and @Access != 'private']">
+ <xsl:sort select="@Name" />
+ <xsl:if test="position()=1">
+ <h3>Base of</h3>
+ </xsl:if>
+ <xsl:call-template name="htmllink" />
+ <xsl:if test="position()!=last()">, </xsl:if>
+ </xsl:for-each>
+ </xsl:template>
+ <xsl:template match="param">
+ <tr>
+ <td valign="top">
+ <!--code-->
+ <xsl:value-of select="@name" />
+ <!--/code-->
+ <xsl:text>:</xsl:text>
+ </td>
+ <td valign="top">
+ <xsl:apply-templates/>
+ </td>
+ </tr>
+ </xsl:template>
+ <xsl:template match="returns">
+ <xsl:if test="current()[../@ReturnType!='void']">
+ <tr>
+ <td valign="top">
+ <b>Returns:</b>
+ </td>
+ <td valign="top">
+ <xsl:apply-templates/>
+ </td>
+ </tr>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template match="Signature">
+ <code>
+ <xsl:value-of select="." />
+ </code>
+ </xsl:template>
+ <xsl:template match="summary">
+ <xsl:apply-templates />
+ </xsl:template>
+ <xsl:template match="value">
+ <p>
+ <b>Value:</b>
+ <xsl:apply-templates />
+ </p>
+ </xsl:template>
+ <!-- templates for VS 2005 doc tags-->
+ <xsl:template match="exception">
+ <xsl:choose>
+ <xsl:when test="current()[name(..)='summary']">
+ <b>/Throws</b>
+ <xsl:value-of select="substring(@cref,3)" />
+ <xsl:apply-templates />
+ </xsl:when>
+ <xsl:otherwise>
+ <tr>
+ <td valign="top">
+ <xsl:variable name="leRefid" select="@cref" />
+ <xsl:variable name="leExcNode" select="/Assembly/Class[@refid = $leRefid and @Access != 'private']"/>
+ <xsl:choose>
+ <xsl:when test="$leExcNode">
+ <xsl:for-each select="$leExcNode">
+ <xsl:call-template name="htmllink" />
+ </xsl:for-each>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="substring(@cref,3)" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </td>
+ <td valign="top">
+ <xsl:apply-templates />
+ </td>
+ </tr>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <!--xsl:template match="code">
+ <code>
+ <xsl:apply-templates select="@* | node()" />
+ </code>
+ </xsl:template-->
+ <xsl:template match="item">
+ <li>
+ <xsl:apply-templates select="@* | node()" />
+ </li>
+ </xsl:template>
+ <!-- also do description and term tags, and other list types?-->
+ <xsl:template match="list">
+ <xsl:choose>
+ <xsl:when test="@type='ordered'">
+ <ol>
+ <xsl:apply-templates select="@* | node()" />
+ </ol>
+ </xsl:when>
+ <xsl:otherwise>
+ <ul>
+ <xsl:apply-templates select="@* | node()" />
+ </ul>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <xsl:template match="para">
+ <p>
+ <xsl:apply-templates select="@* | node()" />
+ </p>
+ </xsl:template>
+ <xsl:template match="seealso">
+ <xsl:text>See also</xsl:text>
+ <xsl:variable name="leRefid" select="@cref" />
+ <xsl:variable name="leNode" select="//*[@refid=$leRefid]" />
+ <xsl:variable name="leFile" select="substring(ancestor::*[@refid and not(@Declared)]/@refid,3)" />
+ <xsl:choose>
+ <xsl:when test ="substring(@cref,1,2) = 'T:'">
+ <xsl:element name="a">
+ <xsl:attribute name="href">
+ <xsl:value-of select="substring(@cref,3)" />
+ <xsl:text>.htm</xsl:text>
+ </xsl:attribute>
+ <xsl:value-of select="$leNode/Signature" />
+ </xsl:element>
+ </xsl:when>
+ <xsl:when test="$leNode/@CDeclared=$leFile">
+ <xsl:element name="a">
+ <xsl:attribute name="href">
+ #<xsl:value-of select="@cref" />
+ </xsl:attribute>
+ <xsl:value-of select="$leNode/Signature" />
+ </xsl:element>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:element name="a">
+ <xsl:attribute name="href">
+ <xsl:value-of select="$leNode/@CDeclared" />.htm#<xsl:value-of select="@cref" />
+ </xsl:attribute>
+ <xsl:value-of select="$leNode/@Declared" />.<xsl:value-of select="$leNode/Signature" />
+ </xsl:element>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <xsl:template match="see">
+ <!--xsl:text>See </xsl:text-->
+ <xsl:variable name="leRefid" select="@cref" />
+ <xsl:variable name="leNode" select="//*[@refid=$leRefid]" />
+ <xsl:variable name="leFile" select="substring(ancestor::*[@refid and not(@Declared)]/@refid,3)" />
+ <xsl:choose>
+ <xsl:when test ="substring(@cref,1,2) = 'T:'">
+ <xsl:element name="a">
+ <xsl:attribute name="href">
+ <xsl:value-of select="substring(@cref,3)" />
+ <xsl:text>.htm</xsl:text>
+ </xsl:attribute>
+ <xsl:value-of select="$leNode/Signature" />
+ </xsl:element>
+ </xsl:when>
+ <xsl:when test="$leNode/@CDeclared=$leFile">
+ <xsl:element name="a">
+ <xsl:attribute name="href">
+ <xsl:text>#</xsl:text>
+ <xsl:value-of select="@cref" />
+ </xsl:attribute>
+ <xsl:value-of select="$leNode/Signature" />
+ </xsl:element>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:element name="a">
+ <xsl:attribute name="href">
+ <xsl:value-of select="$leNode/@CDeclared" />.htm#<xsl:value-of select="@cref" />
+ </xsl:attribute>
+ <xsl:value-of select="$leNode/@Declared" />.<xsl:value-of select="$leNode/Signature" />
+ </xsl:element>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <xsl:template match="typeparam">
+ <tr>
+ <td valign="top">
+ <xsl:value-of select="@name" />
+ </td>
+ <td valign="top">
+ <xsl:apply-templates />
+ </td>
+ </tr>
+ </xsl:template>
+ <xsl:template match="constraint">
+ <tr>
+ <td valign="top"></td>
+ <td valign="top">
+ <xsl:value-of select="@Value" />
+ </td>
+ </tr>
+ </xsl:template>
+ <xsl:template match="@* | node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@* | node()" />
+ </xsl:copy>
+ </xsl:template>
+ <!-- end templates for VS 2005 doc tags -->
+ <xsl:template name="typeparams">
+ <xsl:if test="typeparam">
+ <table>
+ <tr>
+ <td>
+ <b>Type parameters:</b>
+ </td>
+ <td></td>
+ </tr>
+ <xsl:apply-templates select="typeparam"/>
+ <xsl:if test="constraint">
+ <tr>
+ <td>
+ <b>Constraints:</b>
+ </td>
+ <td></td>
+ </tr>
+ <xsl:apply-templates select="constraint"/>
+ </xsl:if>
+ </table>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template name="htmllink">
+ <xsl:choose>
+ <xsl:when test="@C5">
+ <xsl:element name="a">
+ <xsl:attribute name="href">
+ <xsl:choose>
+ <xsl:when test ="substring(@refid,1,2) = 'T:'">
+ <xsl:value-of select="substring(@refid,3)" />
+ <xsl:text>.htm</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="@CDeclared"/>.htm#<xsl:value-of select="@refid" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:attribute>
+ <xsl:apply-templates select="Signature" />
+ </xsl:element>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates select="Signature" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <xsl:template name="locallink">
+ <xsl:choose>
+ <xsl:when test="@refid">
+ <xsl:element name="a">
+ <xsl:attribute name="href">
+ <xsl:text>#</xsl:text>
+ <xsl:value-of select="concat(../@refid , '|',@refid)" />
+ </xsl:attribute>
+ <xsl:apply-templates select="Signature" />
+ </xsl:element>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates select="Signature" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <xsl:template name="htmlname">
+ <xsl:choose>
+ <xsl:when test="@refid">
+ <xsl:choose>
+ <xsl:when test ="not(@Declared)">
+ <!-- i.e. a type -->
+ <xsl:element name="a">
+ <xsl:attribute name="name">
+ <xsl:value-of select="@refid" />
+ </xsl:attribute>
+ <xsl:apply-templates select="Signature" />
+ </xsl:element>
+ </xsl:when>
+ <xsl:otherwise>
+ <!-- i.e. a member -->
+ <xsl:element name="a">
+ <xsl:attribute name="name">
+ <xsl:value-of select="concat(../@refid , '|',@refid)" />
+ </xsl:attribute>
+ <xsl:apply-templates select="Signature" />
+ </xsl:element>
+ <xsl:if test ="not(@Inherited)">
+ <!-- the canonical description -->
+ <xsl:element name="a">
+ <xsl:attribute name="name">
+ <xsl:value-of select="@refid" />
+ </xsl:attribute>
+ </xsl:element>
+ </xsl:if>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates select="Signature" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <xsl:template name="ftable">
+ <xsl:call-template name="table">
+ <xsl:with-param name="type">Field</xsl:with-param>
+ </xsl:call-template>
+ </xsl:template>
+ <xsl:template name="etable">
+ <xsl:call-template name="table">
+ <xsl:with-param name="type">Event</xsl:with-param>
+ </xsl:call-template>
+ </xsl:template>
+ <xsl:template name="ptable">
+ <xsl:call-template name="table">
+ <xsl:with-param name="type">Property</xsl:with-param>
+ </xsl:call-template>
+ </xsl:template>
+ <xsl:template name="ctable">
+ <xsl:call-template name="table">
+ <xsl:with-param name="type">Constructor</xsl:with-param>
+ </xsl:call-template>
+ </xsl:template>
+ <xsl:template name="mtable">
+ <xsl:call-template name="table">
+ <xsl:with-param name="type" select="'Method'"/>
+ </xsl:call-template>
+ </xsl:template>
+ <xsl:template name="otable">
+ <xsl:call-template name="table">
+ <xsl:with-param name="type" select="'Operator'"/>
+ </xsl:call-template>
+ </xsl:template>
+ <xsl:template name="table">
+ <xsl:param name="type" />
+ <xsl:param name="protection" />
+ <xsl:variable name="thenodes" select="*[name() = $type and @Access != 'private' and not(@Inherited)]" />
+ <xsl:if test="$thenodes">
+ <h3>
+ <xsl:value-of select="$type" />
+ <xsl:text> details</xsl:text>
+ </h3>
+ <table border="1">
+ <xsl:for-each select="$thenodes">
+ <xsl:sort select="@Name" />
+ <tr>
+ <td valign="top">
+ <xsl:if test="current()[@Virtual != 'True' and @Static != 'True']">
+ <code class="greenbg">N</code>
+ </xsl:if>
+ <xsl:if test="current()[@Final = 'True' and @Static != 'True']">
+ <code class="greenbg">F</code>
+ </xsl:if>
+ <xsl:if test="current()[@Abstract = 'True']">
+ <code class="greenbg">A</code>
+ </xsl:if>
+ <xsl:if test="current()[@Static = 'True']">
+ <code class="greenbg">S</code>
+ </xsl:if>
+ <xsl:if test="current()[@Access = 'protected']">
+ <code class="greenbg">P</code>
+ </xsl:if>
+ <code>
+ <xsl:text>&#32;</xsl:text>
+ <xsl:choose>
+ <xsl:when test="@ReturnType">
+ <xsl:value-of select="@ReturnType"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="@Type"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:text>&#32;</xsl:text>
+ </code>
+ <xsl:call-template name="htmlname" />
+ </td>
+ <td>
+ <!--xsl:if test="@Inherited">
+ <xsl:text>Inherited from </xsl:text>
+ <xsl:value-of select="@Declared"/>
+ <xsl:text>: </xsl:text>
+ <xsl:call-template name="htmllink" />
+ </xsl:if-->
+ <xsl:if test="not(@Inherited)">
+ <xsl:if test="@Get">
+ <b>Access: </b>
+ <xsl:if test="@Get='True' and @Set='True'">Read-Write</xsl:if>
+ <xsl:if test="@Get='True' and @Set='False'">Read-Only</xsl:if>
+ <xsl:if test="@Get='False' and @Set='True'">Write-Only</xsl:if>
+ <br/>
+ </xsl:if>
+ <xsl:apply-templates select="value" />
+ <xsl:apply-templates select="summary" />
+ <xsl:if test="exception">
+ <table>
+ <tr>
+ <td>
+ <b>Throws</b>
+ </td>
+ <td></td>
+ </tr>
+ <xsl:apply-templates select="exception" />
+ </table>
+ </xsl:if>
+ <xsl:call-template name="typeparams"/>
+ <xsl:if test="current()[@ReturnType != 'void'] or param">
+ <table>
+ <xsl:apply-templates select="returns" />
+ <xsl:if test="param">
+ <tr>
+ <td>
+ <b>Parameters:</b>
+ </td>
+ </tr>
+ <xsl:apply-templates select="param" />
+ </xsl:if>
+ </table>
+ </xsl:if>
+ </xsl:if>
+ </td>
+ </tr>
+ </xsl:for-each>
+ </table>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template name="foverview">
+ <xsl:call-template name="overview">
+ <xsl:with-param name="type">Field</xsl:with-param>
+ </xsl:call-template>
+ </xsl:template>
+ <xsl:template name="eoverview">
+ <xsl:call-template name="overview">
+ <xsl:with-param name="type">Event</xsl:with-param>
+ </xsl:call-template>
+ </xsl:template>
+ <xsl:template name="poverview">
+ <xsl:call-template name="overview">
+ <xsl:with-param name="type">Property</xsl:with-param>
+ </xsl:call-template>
+ </xsl:template>
+ <xsl:template name="coverview">
+ <xsl:call-template name="overview">
+ <xsl:with-param name="type">Constructor</xsl:with-param>
+ </xsl:call-template>
+ </xsl:template>
+ <xsl:template name="moverview">
+ <xsl:call-template name="overview">
+ <xsl:with-param name="type">Method</xsl:with-param>
+ </xsl:call-template>
+ </xsl:template>
+ <xsl:template name="ooverview">
+ <xsl:call-template name="overview">
+ <xsl:with-param name="type">Operator</xsl:with-param>
+ </xsl:call-template>
+ </xsl:template>
+ <xsl:template name="overview">
+ <xsl:param name="type" select="'[Unknown Locale]'" />
+ <xsl:for-each select="*[name() = $type and @Access != 'private']">
+ <xsl:sort select="@Name" />
+ <xsl:if test="position() = 1">
+ <h3>
+ <xsl:value-of select="$type" />
+ <xsl:text> overview</xsl:text>
+ </h3>
+ </xsl:if>
+ <xsl:choose>
+ <xsl:when test="@Inherited">
+ <xsl:call-template name="htmllink" />
+ <xsl:text>, </xsl:text>
+ <xsl:text>Inherited from </xsl:text>
+ <xsl:value-of select="@Declared"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="locallink" />
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:if test="position()!=last()">
+ ,<br/>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:template>
+</xsl:stylesheet>