public void TestSublistProblem() { // This problem affects FVList.PreviousIn(), RVList.NextIn(), // AddRange(list, excludeSubList), RVList.Enumerator when used with a // range. // Normally this works fine: RVList <int> subList = new RVList <int>(), list; subList.AddRange(new int[] { 1, 2, 3, 4, 5, 6, 7 }); list = subList; list.Add(8); Assert.That(subList.NextIn(list).Last == 8); // But try it a second time and the problem arises, without some special // code in VListBlock<T>.FindNextBlock() that has been added to // compensate. I call the problem copy-causing-sharing-failure. You see, // right now subList is formed from three blocks: a size-8 block that // contains {7}, a size-4 block {3, 4, 5, 6} and a size-2 block {1, 2}. // But the size-8 block actually has two items {7, 8} and when we // attempt to add 9, a new array must be created. It might waste a lot // of memory to make a new block {9} that links to the size-8 block that // contains {7}, so instead a new size-8 block {7, 9} is created that // links directly to {3, 4, 5, 6}. That way, the block {7, 8} can be // garbage-collected if it is no longer in use. But a side effect is // that subList no longer appears to be a part of list. The fix is to // notice that list (block {7, 9}) and subList (block that contains {7}) // have the same prior list, {3, 4, 5, 6}, and that the remaining // item(s) in subList (just one item, {7}, in this case) are also // present in list. list = subList; list.Add(9); Assert.AreEqual(9, subList.NextIn(list).Last); }
public void TestEmptyListOperations() { RVList <int> a = new RVList <int>(); RVList <int> b = new RVList <int>(); a.AddRange(b); a.InsertRange(0, b); a.RemoveRange(0, 0); Assert.That(!a.Remove(0)); Assert.That(a.IsEmpty); a.Add(1); b.AddRange(a); ExpectList(b, 1); b.RemoveAt(0); Assert.That(b.IsEmpty); b.InsertRange(0, a); ExpectList(b, 1); b.RemoveRange(0, 1); Assert.That(b.IsEmpty); b.Insert(0, a[0]); ExpectList(b, 1); b.Remove(a.Last); Assert.That(b.IsEmpty); AssertThrows <InvalidOperationException>(delegate() { a.NextIn(b); }); }
public void TestInsertRemove() { RWList <int> list = new RWList <int>(); for (int i = 0; i <= 12; i++) { list.Insert(0, i); } ExpectList(list, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); for (int i = 1; i <= 6; i++) { list.RemoveAt(i); } ExpectList(list, 12, 10, 8, 6, 4, 2, 0); Assert.AreEqual(0, list.Pop()); list.Insert(1, -2); ExpectList(list, 12, -2, 10, 8, 6, 4, 2); list.Insert(2, -1); ExpectList(list, 12, -2, -1, 10, 8, 6, 4, 2); Assert.That(list.Remove(-1)); Assert.That(list.Remove(12)); list[0] = 12; ExpectList(list, 12, 10, 8, 6, 4, 2); // Make sure RWList.Clear doesn't disturb FVList RVList <int> v = list.WithoutLast(4); list.Clear(); ExpectList(list); ExpectList(v, 12, 10); // Some simple InsertRange calls where some immutable items must be // converted to mutable RVList <int> oneTwo = new RVList <int>(1, 2); RVList <int> threeFour = new RVList <int>(3, 4); list = oneTwo.ToRWList(); list.InsertRange(1, threeFour); ExpectList(list, 1, 3, 4, 2); list = threeFour.ToRWList(); list.InsertRange(0, oneTwo); ExpectList(list, 1, 2, 3, 4); // More tests... list.RemoveRange(2, 2); ExpectList(list, 1, 2); list.InsertRange(2, new int[] { 3, 3, 4, 4, 4, 5, 6, 7, 8, 9 }); ExpectList(list, 1, 2, 3, 3, 4, 4, 4, 5, 6, 7, 8, 9); list.RemoveRange(3, 3); ExpectList(list, 1, 2, 3, 4, 5, 6, 7, 8, 9); v = list.ToRVList(); list.RemoveRange(5, 4); ExpectList(list, 1, 2, 3, 4, 5); ExpectList(v, 1, 2, 3, 4, 5, 6, 7, 8, 9); }
/// <summary>Returns whether the two list references are the same. /// Does not compare the contents of the lists.</summary> public override bool Equals(object rhs_) { try { RVList <T> rhs = (RVList <T>)rhs_; return(this == rhs); } catch (InvalidCastException) { return(false); } }
public void TestMutabilification() { // Make a single block mutable RVList <int> v = new RVList <int>(1, 0); RWList <int> w = v.ToRWList(); ExpectList(w, 1, 0); w[1] = 2; ExpectList(w, 1, 2); ExpectList(v, 1, 0); // Make another block, make the front block mutable, then the block-of-2 v.Push(-1); w = v.ToRWList(); w[2] = 3; ExpectList(w, 1, 0, 3); Assert.That(w.WithoutLast(1) == v.WithoutLast(1)); w[1] = 2; ExpectList(w, 1, 2, 3); Assert.That(w.WithoutLast(1) != v.WithoutLast(1)); // Now for a more complicated case: create a long immutable chain by // using a nasty access pattern, add a mutable block in front, then // make some of the immutable blocks mutable. This will cause several // immutable blocks to be consolidated into one mutable block, // shortening the chain. v = new RVList <int>(6); v = v.Add(-1).Tail.Add(5).Add(-1).Tail.Add(4).Add(-1).Tail.Add(3); v = v.Add(-1).Tail.Add(2).Add(-1).Tail.Add(1).Add(-1).Tail.Add(0); ExpectList(v, 6, 5, 4, 3, 2, 1, 0); // At this point, every block in the chain has only one item (it's // a linked list!) and the capacity of each block is 2. Assert.AreEqual(7, v.BlockChainLength); w = v.ToRWList(); w.AddRange(new int[] { 1, 2, 3, 4, 5 }); Assert.AreEqual(w.Count, 12); ExpectList(w, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5); // Indices: 0 1 2 3 4 5 6 7 8 9 10 11 // Blocks: H| G| F| E| D| C| B | block A (front of chain) Assert.AreEqual(8, w.BlockChainLength); Assert.AreEqual(4, w.LocalCount); w[3] = -3; ExpectList(w, 6, 5, 4, -3, 2, 1, 0, 1, 2, 3, 4, 5); // Indices: 0 1 2 3 4 5 6 7 8 9 10 11 // Blocks: H| G| F| block I | block A (front of chain) Assert.AreEqual(5, w.BlockChainLength); }
void TestAddRangePair() { RVList <int> list = new RVList <int>(); RVList <int> list2 = new RVList <int>(); list2.AddRange(new int[] { 1, 2, 3, 4 }); list.AddRange(list2, list2.WithoutLast(1)); list.AddRange(list2, list2.WithoutLast(2)); list.AddRange(list2, list2.WithoutLast(3)); list.AddRange(list2, list2.WithoutLast(4)); ExpectList(list, 1, 2, 3, 1, 2, 1); AssertThrows <InvalidOperationException>(delegate() { list2.AddRange(list2.WithoutLast(1), list2); }); AssertThrows <InvalidOperationException>(delegate() { list2.AddRange(RVList <int> .Empty, list2); }); }
public void TestToArray() { RVList <int> list = new RVList <int>(); int[] array = list.ToArray(); Assert.AreEqual(array.Length, 0); array = list.Add(1).ToArray(); ExpectList(array, 1); array = list.Add(2).ToArray(); ExpectList(array, 1, 2); array = list.Add(3).ToArray(); ExpectList(array, 1, 2, 3); array = list.AddRange(new int[] { 4, 5, 6, 7, 8 }).ToArray(); ExpectList(array, 1, 2, 3, 4, 5, 6, 7, 8); }
public void TestInsertRemove() { RVList <int> list = new RVList <int>(9); RVList <int> list2 = new RVList <int>(10, 11); list.Insert(0, 12); list.Insert(1, list2[1]); list.Insert(2, list2[0]); ExpectList(list, 12, 11, 10, 9); for (int i = 0; i < 9; i++) { list.Insert(4, i); } ExpectList(list, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); list2 = list; for (int i = 1; i <= 6; i++) { list2.RemoveAt(i); } ExpectList(list2, 12, 10, 8, 6, 4, 2, 0); ExpectList(list, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); // unchanged Assert.AreEqual(0, list2.Pop()); list2.Insert(5, -2); ExpectList(list2, 12, 10, 8, 6, 4, -2, 2); list2.Insert(5, -1); ExpectList(list2, 12, 10, 8, 6, 4, -1, -2, 2); // Test changing items list = list2; for (int i = 0; i < list.Count; i++) { list[i] = i; } ExpectList(list, 0, 1, 2, 3, 4, 5, 6, 7); ExpectList(list2, 12, 10, 8, 6, 4, -1, -2, 2); list2.Clear(); ExpectList(list2); Assert.AreEqual(5, list[5]); }
public void TestInsertRemoveRange() { RVList <int> oneTwo = new RVList <int>(1, 2); RVList <int> threeFour = new RVList <int>(3, 4); RVList <int> list = oneTwo; RVList <int> list2 = threeFour; ExpectList(list, 1, 2); list.InsertRange(1, threeFour); ExpectList(list, 1, 3, 4, 2); list2.InsertRange(2, oneTwo); ExpectList(list2, 3, 4, 1, 2); list.RemoveRange(1, 2); ExpectList(list, 1, 2); list2.RemoveRange(2, 2); ExpectList(list2, 3, 4); list.RemoveRange(0, 2); ExpectList(list); list2.RemoveRange(1, 1); ExpectList(list2, 3); list = oneTwo; list.AddRange(threeFour); ExpectList(list, 1, 2, 3, 4); list.InsertRange(1, list); ExpectList(list, 1, 1, 2, 3, 4, 2, 3, 4); list.RemoveRange(1, 1); list.RemoveRange(4, 3); ExpectList(list, 1, 2, 3, 4); list.RemoveRange(0, 4); ExpectList(list); list2.InsertRange(0, list); list2.InsertRange(1, list); ExpectList(list2, 3); }
public void SimpleTests() { // Tests simple adds and removes from the front of the list. It // makes part of its tail immutable, but doesn't make it mutable // again. Also, we test operations that don't modify the list. RWList <int> list = new RWList <int>(); Assert.That(list.IsEmpty); // create VListBlockOfTwo list = new RWList <int>(10, 20); ExpectList(list, 10, 20); // Add() list.Clear(); list.Add(1); Assert.That(!list.IsEmpty); list.Add(2); Assert.AreEqual(1, list.BlockChainLength); list.Add(3); Assert.AreEqual(2, list.BlockChainLength); ExpectList(list, 1, 2, 3); RVList <int> snap = list.ToRVList(); ExpectList(snap, 1, 2, 3); // AddRange(), Push(), Pop() list.Push(4); list.AddRange(new int[] { 5, 6 }); ExpectList(list, 1, 2, 3, 4, 5, 6); Assert.AreEqual(list.Pop(), 6); ExpectList(list, 1, 2, 3, 4, 5); list.RemoveRange(3, 2); ExpectList(list, 1, 2, 3); // Double the list list.AddRange(list); ExpectList(list, 1, 2, 3, 1, 2, 3); list.RemoveRange(3, 3); // Fill a third block list.AddRange(new int[] { 4, 5, 6, 7, 8, 9 }); list.AddRange(new int[] { 10, 11, 12, 13, 14 }); ExpectList(list, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14); // Remove(), enumerator list.Remove(14); list.Remove(13); list.Remove(12); list.Remove(11); ExpectListByEnumerator(list, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // IndexOutOfRangeException AssertThrows <IndexOutOfRangeException>(delegate() { int i = list[-1]; }); AssertThrows <IndexOutOfRangeException>(delegate() { int i = list[10]; }); AssertThrows <IndexOutOfRangeException>(delegate() { list.Insert(-1, -1); }); AssertThrows <IndexOutOfRangeException>(delegate() { list.Insert(list.Count + 1, -1); }); AssertThrows <IndexOutOfRangeException>(delegate() { list.RemoveAt(-1); }); AssertThrows <IndexOutOfRangeException>(delegate() { list.RemoveAt(list.Count); }); // Front, Contains, IndexOf Assert.That(list.Last == 10); Assert.That(list.Contains(9)); Assert.That(list[list.IndexOf(2)] == 2); Assert.That(list[list.IndexOf(9)] == 9); Assert.That(list[list.IndexOf(7)] == 7); Assert.That(list.IndexOf(-1) == -1); // snap is still the same ExpectList(snap, 1, 2, 3); }
public RVList <T> NextIn(RVList <T> largerList) { return(VListBlock <T> .BackUpOnce(this, largerList)); }
public void TestExampleTransforms() { // These examples are listed in the documentation of FVList.Transform(). // There are more Transform() tests in VListTests() and RWListTests(). RVList <int> list = new RVList <int>(new int[] { -1, 2, -2, 13, 5, 8, 9 }); RVList <int> output; output = list.Transform((int i, ref int n) => { // Keep every second item return((i % 2) == 1 ? XfAction.Keep : XfAction.Drop); }); ExpectList(output, 2, 13, 8); output = list.Transform((int i, ref int n) => { // Keep odd numbers return((n % 2) != 0 ? XfAction.Keep : XfAction.Drop); }); ExpectList(output, -1, 13, 5, 9); output = list.Transform((int i, ref int n) => { // Keep and square all odd numbers if ((n % 2) != 0) { n *= n; return(XfAction.Change); } else { return(XfAction.Drop); } }); ExpectList(output, 1, 169, 25, 81); output = list.Transform((int i, ref int n) => { // Increase each item by its index n += i; return(i == 0 ? XfAction.Keep : XfAction.Change); }); ExpectList(output, -1, 3, 0, 16, 9, 13, 15); list = new RVList <int>(new int[] { 1, 2, 3 }); output = list.Transform(delegate(int i, ref int n) { return(i >= 0 ? XfAction.Repeat : XfAction.Keep); }); ExpectList(output, 1, 1, 2, 2, 3, 3); output = list.Transform(delegate(int i, ref int n) { if (i >= 0) { return(XfAction.Repeat); } n *= 10; return(XfAction.Change); }); ExpectList(output, 1, 10, 2, 20, 3, 30); output = list.Transform(delegate(int i, ref int n) { if (i >= 0) { n *= 10; return(XfAction.Repeat); } return(XfAction.Keep); }); ExpectList(output, 10, 1, 20, 2, 30, 3); output = list.Transform(delegate(int i, ref int n) { n *= 10; if (n > 1000) { return(XfAction.Drop); } return(XfAction.Repeat); }); ExpectList(output, 10, 100, 1000, 20, 200, 30, 300); }
public void SimpleTests() { // In this simple test, I only add and remove items from the back // of an RVList, but forking is also tested. RVList <int> list = new RVList <int>(); Assert.That(list.IsEmpty); // Adding to VListBlockOfTwo list = new RVList <int>(10, 20); ExpectList(list, 10, 20); list = new RVList <int>(); list.Add(1); Assert.That(!list.IsEmpty); list.Add(2); ExpectList(list, 1, 2); // A fork in VListBlockOfTwo. Note that list2 will use two VListBlocks // here but list will only use one. RVList <int> list2 = list.WithoutLast(1); list2.Add(3); ExpectList(list, 1, 2); ExpectList(list2, 1, 3); // Try doubling list2 list2.AddRange(list2); ExpectList(list2, 1, 3, 1, 3); // list now uses two arrays list.Add(4); ExpectList(list, 1, 2, 4); // Try doubling list using a different overload of AddRange() list.AddRange((IList <int>)list); ExpectList(list, 1, 2, 4, 1, 2, 4); list = list.WithoutLast(3); ExpectList(list, 1, 2, 4); // Remove(), Pop() Assert.AreEqual(3, list2.Pop()); ExpectList(list2, 1, 3, 1); Assert.That(!list2.Remove(0)); Assert.AreEqual(1, list2.Pop()); Assert.That(list2.Remove(3)); ExpectList(list2, 1); Assert.That(list2.Remove(1)); ExpectList(list2); AssertThrows <Exception>(delegate() { list2.Pop(); }); // Add many, SubList(). This will fill 3 arrays (sizes 8, 4, 2) and use // 1 element of a size-16 array. Oh, and test the enumerator. for (int i = 5; i <= 16; i++) { list.Add(i); } ExpectList(list, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); list2 = list.WithoutLast(6); ExpectListByEnumerator(list2, 1, 2, 4, 5, 6, 7, 8, 9, 10); AssertThrows <IndexOutOfRangeException>(delegate() { int i = list[-1]; }); AssertThrows <IndexOutOfRangeException>(delegate() { int i = list[15]; }); // IndexOf, contains Assert.That(list.Contains(11)); Assert.That(!list2.Contains(11)); Assert.That(list[list.IndexOf(2)] == 2); Assert.That(list[list.IndexOf(1)] == 1); Assert.That(list[list.IndexOf(15)] == 15); Assert.That(list.IndexOf(3) == -1); // PreviousIn(), Back RVList <int> list3 = list2; Assert.AreEqual(11, (list3 = list3.NextIn(list)).Last); Assert.AreEqual(12, (list3 = list3.NextIn(list)).Last); Assert.AreEqual(13, (list3 = list3.NextIn(list)).Last); Assert.AreEqual(14, (list3 = list3.NextIn(list)).Last); Assert.AreEqual(15, (list3 = list3.NextIn(list)).Last); Assert.AreEqual(16, (list3 = list3.NextIn(list)).Last); AssertThrows <Exception>(delegate() { list3.NextIn(list); }); // Next Assert.AreEqual(10, (list3 = list3.WithoutLast(6)).Last); Assert.AreEqual(9, (list3 = list3.Tail).Last); Assert.AreEqual(8, (list3 = list3.Tail).Last); Assert.AreEqual(7, (list3 = list3.Tail).Last); Assert.AreEqual(6, (list3 = list3.Tail).Last); Assert.AreEqual(5, (list3 = list3.Tail).Last); Assert.AreEqual(4, (list3 = list3.Tail).Last); Assert.AreEqual(2, (list3 = list3.Tail).Last); Assert.AreEqual(1, (list3 = list3.Tail).Last); Assert.That((list3 = list3.Tail).IsEmpty); // list2 is still the same ExpectList(list2, 1, 2, 4, 5, 6, 7, 8, 9, 10); // ==, !=, Equals(), AddRange(a, b) Assert.That(!list2.Equals("hello")); list3 = list2; Assert.That(list3.Equals(list2)); Assert.That(list3 == list2); // This AddRange forks the list. List2 ends up with block sizes 8 (3 // used), 8 (3 used), 4, 2. list2.AddRange(list2, list2.WithoutLast(3)); ExpectList(list2, 1, 2, 4, 5, 6, 7, 8, 9, 10, 8, 9, 10); Assert.That(list3 != list2); // List3 is a sublist of list, but list2 no longer is Assert.That(list3.NextIn(list).Last == 11); AssertThrows <InvalidOperationException>(delegate() { list2.NextIn(list); }); list2 = list2.WithoutLast(3); Assert.That(list3 == list2); }
public Enumerator(RVList <T> list, RVList <T> subList) : this(new FVList <T>(list._block, list._localCount), new FVList <T>(subList._block, subList._localCount)) { }
public RVList <T> AddRange(RVList <T> list, RVList <T> excludeSubList) { this = VListBlock <T> .AddRange(_block, _localCount, list.ToFVList(), excludeSubList.ToFVList()).ToRVList(); return(this); }
public RVList <T> AddRange(RVList <T> list) { return(AddRange(list, new RVList <T>())); }
public Enumerator(RVList <T> list) { _tail = (FVList <T>)list; _current = default(T); }
public RVList(RVList <T> list) { this = list; }