You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucenenet.apache.org by ni...@apache.org on 2016/11/10 11:33:16 UTC

[05/58] [abbrv] lucenenet git commit: Added TreeSet and TreeDictionary from C5 to the Support namespace

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/5f198526/src/Lucene.Net.Tests/core/Support/C5/Events.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests/core/Support/C5/Events.cs b/src/Lucene.Net.Tests/core/Support/C5/Events.cs
new file mode 100644
index 0000000..f0f5082
--- /dev/null
+++ b/src/Lucene.Net.Tests/core/Support/C5/Events.cs
@@ -0,0 +1,893 @@
+\ufeff/*
+ Copyright (c) 2003-2016 Niels Kokholm, Peter Sestoft, and Rasmus Lystr�m
+ 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 Lucene.Net.Support.C5;
+using NUnit.Framework;
+using SCG = System.Collections.Generic;
+
+namespace Lucene.Net.Support.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, MemoryType memoryType)
+        {
+            this.collection = list;
+            listenTo = testSpec;
+            seen = new CollectionEventList<TItem>(EqualityComparer<TItem>.Default, memoryType);
+        }
+
+        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;
+        }
+        public virtual void Listenable()
+        {
+            Assert.AreEqual(EventTypeEnum.Basic, collection.ListenableEvents);
+            Assert.AreEqual(EventTypeEnum.None, collection.ActiveEvents);
+            listen();
+            Assert.AreEqual(listenTo, collection.ActiveEvents);
+        }
+
+        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)});
+        }
+
+        public void AddAll()
+        {
+            for (int i = 0; i < 10; i++)
+            {
+                collection.Add(10 * i + 5);
+            }
+            listen();
+            collection.AddAll(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(new int[] { });
+            seen.Check(new CollectionEvent<int>[] { });
+        }
+
+    }
+
+    public class CollectionTester<U> : ExtensibleTester<U> where U : ICollection<int>
+    {
+        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>[] { });
+        }
+
+        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)
+        });
+        }
+
+        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)
+        });
+        }
+
+        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)});
+        }
+
+        public void RemoveAll()
+        {
+            for (int i = 0; i < 10; i++)
+            {
+                collection.Add(10 * i + 5);
+            }
+            listen();
+            collection.RemoveAll(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(new int[] { 200, 300 });
+            seen.Check(new CollectionEvent<int>[] { });
+        }
+
+        public void RetainAll()
+        {
+            for (int i = 0; i < 10; i++)
+            {
+                collection.Add(10 * i + 5);
+            }
+            listen();
+            collection.RetainAll(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(new int[] { 32, 187, 45, 62, 75, 82, 95, 2 });
+            seen.Check(new CollectionEvent<int>[] { });
+        }
+
+        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>[] { });
+        }
+
+        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>
+    {
+        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)});
+        }
+
+        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>
+    {
+        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),
+      });
+        }
+
+        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>[] { });
+        }
+
+        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;
+        }
+
+        public override void Listenable()
+        {
+            Assert.AreEqual(EventTypeEnum.All, collection.ListenableEvents);
+            Assert.AreEqual(EventTypeEnum.None, collection.ActiveEvents);
+            listen();
+            Assert.AreEqual(listenTo, collection.ActiveEvents);
+        }
+        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)
+          });
+        }
+
+        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)
+          });
+        }
+
+        public void InsertAll()
+        {
+            collection.Add(4); collection.Add(56); collection.Add(8);
+            listen();
+            collection.InsertAll(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(1, new int[] { });
+            seen.Check(new CollectionEvent<int>[] { });
+        }
+
+        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)
+          });
+        }
+
+        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)});
+        }
+
+        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)});
+        }
+
+        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)});
+        }
+
+        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>[] { });
+        }
+
+
+        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>[] { });
+        }
+
+        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>[] { });
+        }
+
+        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>[] { });
+        }
+
+        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;
+        }
+
+        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;
+        }
+
+        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;
+        }
+
+        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(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(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)
+      });
+        }
+
+        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;
+        }
+
+        public virtual void Listenable()
+        {
+            Assert.AreEqual(EventTypeEnum.Basic, collection.ListenableEvents);
+            Assert.AreEqual(EventTypeEnum.None, collection.ActiveEvents);
+            listen();
+            Assert.AreEqual(listenTo, collection.ActiveEvents);
+        }
+
+        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)});
+        }
+
+
+
+    }
+
+}
+
+
+

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/5f198526/src/Lucene.Net.Tests/core/Support/C5/GenericCollectionTester.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests/core/Support/C5/GenericCollectionTester.cs b/src/Lucene.Net.Tests/core/Support/C5/GenericCollectionTester.cs
new file mode 100644
index 0000000..12b4360
--- /dev/null
+++ b/src/Lucene.Net.Tests/core/Support/C5/GenericCollectionTester.cs
@@ -0,0 +1,87 @@
+\ufeff/*
+ Copyright (c) 2003-2016 Niels Kokholm, Peter Sestoft, and Rasmus Lystr�m
+ 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.Reflection;
+using Lucene.Net.Support.C5;
+using NUnit.Framework;
+using SCG = System.Collections.Generic;
+
+namespace Lucene.Net.Support.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(Func<U> factory, MemoryType memoryType = MemoryType.Normal)
+        {
+            foreach (MethodInfo minfo in testMethods)
+            {
+                foreach (W testSpec in GetSpecs())
+                {
+                    SetUp(factory(), testSpec, memoryType);
+                    //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, MemoryType memoryType);
+        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, MemoryType memoryType)
+        {
+            SetUp(collection, memoryType);
+        }
+
+        public abstract void SetUp(object collection, MemoryType memoryType);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/5f198526/src/Lucene.Net.Tests/core/Support/C5/HashBag.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests/core/Support/C5/HashBag.cs b/src/Lucene.Net.Tests/core/Support/C5/HashBag.cs
new file mode 100644
index 0000000..dbfec88
--- /dev/null
+++ b/src/Lucene.Net.Tests/core/Support/C5/HashBag.cs
@@ -0,0 +1,658 @@
+\ufeff/*
+ Copyright (c) 2003-2016 Niels Kokholm, Peter Sestoft, and Rasmus Lystr�m
+ 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 Lucene.Net.Support.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 default item equalityComparer.
+        /// </summary>
+		public HashBag(MemoryType memoryType = MemoryType.Normal) : this(EqualityComparer<T>.Default, memoryType) { }
+
+        /// <summary>
+        /// Create a hash bag with an external item equalityComparer.
+        /// </summary>
+        /// <param name="itemequalityComparer">The external item equalityComparer.</param>
+		/// <param name = "memoryType"></param>
+		public HashBag(SCG.IEqualityComparer<T> itemequalityComparer, MemoryType memoryType = MemoryType.Normal)
+            : base(itemequalityComparer, memoryType)
+        {
+            if (memoryType != MemoryType.Normal)
+                throw new Exception("HashBag doesn't still support Safe and Strict memory type.");
+
+            dict = new HashSet<KeyValuePair<T, int>>(new KeyValuePairEqualityComparer<T, int>(itemequalityComparer), memoryType);
+        }
+
+        /// <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 equalitySCG.Comparer</param>
+		/// <param name = "memoryType"></param>
+		public HashBag(int capacity, SCG.IEqualityComparer<T> itemequalityComparer, MemoryType memoryType = MemoryType.Normal)
+            : base(itemequalityComparer, memoryType)
+        {
+            if (memoryType != MemoryType.Normal)
+                throw new Exception("HashBag doesn't still support Safe and Strict memory type.");
+
+            dict = new HashSet<KeyValuePair<T, int>>(capacity, new KeyValuePairEqualityComparer<T, int>(itemequalityComparer), memoryType);
+        }
+
+
+        /// <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 equalitySCG.Comparer</param>
+		/// <param name = "memoryType"></param>
+		public HashBag(int capacity, double fill, SCG.IEqualityComparer<T> itemequalityComparer, MemoryType memoryType = MemoryType.Normal)
+            : base(itemequalityComparer, memoryType)
+        {
+            if (memoryType != MemoryType.Normal)
+                throw new Exception("HashBag doesn't still support Safe and Strict memory type.");
+
+            dict = new HashSet<KeyValuePair<T, int>>(capacity, fill, new KeyValuePairEqualityComparer<T, int>(itemequalityComparer), memoryType);
+        }
+
+        #endregion
+
+        #region IEditableCollection<T> Members
+
+        /// <summary>
+        /// The complexity of the Contains operation
+        /// </summary>
+        /// <value>Always returns Speed.Constant</value>
+        public virtual Speed ContainsSpeed { 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>
+        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>
+        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>
+        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>
+        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>
+        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 of an item from the bag
+        /// </summary>
+        /// <param name="item">The item to remove</param>
+        /// <returns>True if item was (found and) removed </returns>
+        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>
+        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>
+        /// <param name="items">The items to remove.</param>
+        public virtual void RemoveAll(SCG.IEnumerable<T> items)
+        {
+#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 (T 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>
+        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>
+        /// <param name="items">The items to retain</param>
+        public virtual void RetainAll(SCG.IEnumerable<T> items)
+        {
+            updatecheck();
+
+            HashBag<T> res = new HashBag<T>(itemequalityComparer);
+
+            foreach (T 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>
+        /// <returns>True if all items are found.</returns>
+        public virtual bool ContainsAll(SCG.IEnumerable<T> items)
+        {
+            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>
+        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>
+        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>
+        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>
+        public override void CopyTo(T[] array, int index)
+        {
+            if (index < 0 || 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>
+        public virtual bool AllowsDuplicates { 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>
+        public virtual bool Add(T item)
+        {
+            updatecheck();
+            add(ref item);
+            if (ActiveEvents != 0)
+                raiseForAdd(item);
+            return true;
+        }
+
+        /// <summary>
+        /// Add an item to this bag.
+        /// </summary>
+        /// <param name="item">The item to add.</param>
+        void SCG.ICollection<T>.Add(T item)
+        {
+            Add(item);
+        }
+
+        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>
+        /// <param name="items">The items to add</param>
+        public virtual void AddAll(SCG.IEnumerable<T> items)
+        {
+            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>
+        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 Diagnostics
+        /// <summary>
+        /// Test internal structure of data (invariants)
+        /// </summary>
+        /// <returns>True if pass</returns>
+        public virtual bool Check()
+        {
+            bool retval = dict.Check();
+            int count = 0;
+
+            foreach (KeyValuePair<T, int> p in dict)
+                count += p.Value;
+
+            if (count != size)
+            {
+                Logger.Log(string.Format("count({0}) != size({1})", count, size));
+                retval = false;
+            }
+
+            return retval;
+        }
+        #endregion
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/5f198526/src/Lucene.Net.Tests/core/Support/C5/Sorting.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests/core/Support/C5/Sorting.cs b/src/Lucene.Net.Tests/core/Support/C5/Sorting.cs
new file mode 100644
index 0000000..58a16ae
--- /dev/null
+++ b/src/Lucene.Net.Tests/core/Support/C5/Sorting.cs
@@ -0,0 +1,235 @@
+\ufeff/*
+ Copyright (c) 2003-2016 Niels Kokholm, Peter Sestoft, and Rasmus Lystr�m
+ 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 Lucene.Net.Support.C5
+{
+    /// <summary>
+    /// A utility class with functions for sorting arrays with respect to an IComparer&lt;T&gt;
+    /// </summary>
+    [Serializable]
+    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>
+        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>
+        public static void IntroSort<T>(T[] array)
+        {
+            new Sorter<T>(array, SCG.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>
+        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>
+        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);
+        }
+
+        [Serializable]
+        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