public void TestEmptyListOperations() { FWList <int> a = new FWList <int>(); FWList <int> b = new FWList <int>(); a.AddRange(b); a.InsertRange(0, b); a.RemoveRange(0, 0); Assert.That(!a.Remove(0)); Assert.That(a.IsEmpty); Assert.That(a.WithoutFirst(0).IsEmpty); a.Add(1); Assert.That(a.WithoutFirst(1).IsEmpty); 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.First); Assert.That(b.IsEmpty); }
/*/// <summary>Maps a list to another list of the same length.</summary> * /// <param name="map">A function that transforms each item in the list.</param> * /// <returns>The list after the map function is applied to each item. The * /// original VList structure is not modified.</returns> * public FWList<Out> Select<Out>(Func<T, Out> map) * { * FWList<Out> newList = new FWList<Out>(); * VListBlock<T>.Select<Out>(Block, LocalCount, map, newList); * return newList; * }*/ /// <summary>Transforms a list (combines filtering with selection and more).</summary> /// <param name="x">Method to apply to each item in the list</param> /// <returns>A list formed from transforming all items in the list</returns> /// <remarks>See the documentation of FVList.Transform() for more information.</remarks> public FWList <T> Transform(VListTransformer <T> x) { FWList <T> newList = new FWList <T>(); VListBlock <T> .Transform(Block, LocalCount, x, false, newList); return(newList); }
/// <summary>Maps a list to another list of the same length.</summary> /// <param name="map">A function that transforms each item in the list.</param> /// <returns>The list after the map function is applied to each item. The /// original RVList structure is not modified.</returns> public FWList <Out> Select <Out>(Func <T, Out> map) { FWList <Out> newList = new FWList <Out>(); VListBlock <T> .Select <Out>(Block, LocalCount, map, newList); return(newList); }
public void TestInsertRemove() { FWList <int> list = new FWList <int>(); for (int i = 0; i <= 12; i++) { list.Insert(i, i); } ExpectList(list, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12); for (int i = 1; i <= 6; i++) { list.RemoveAt(i); } ExpectList(list, 0, 2, 4, 6, 8, 10, 12); Assert.AreEqual(0, list.Pop()); list.Insert(5, -2); ExpectList(list, 2, 4, 6, 8, 10, -2, 12); list.Insert(5, -1); ExpectList(list, 2, 4, 6, 8, 10, -1, -2, 12); list.Remove(-1); list.Remove(12); list[list.Count - 1] = 12; ExpectList(list, 2, 4, 6, 8, 10, 12); // Make sure FWList.Clear doesn't disturb FVList FVList <int> v = list.WithoutFirst(4); list.Clear(); ExpectList(list); ExpectList(v, 10, 12); // Some simple InsertRange calls where some immutable items must be // converted to mutable FVList <int> oneTwo = new FVList <int>(1, 2); FVList <int> threeFour = new FVList <int>(3, 4); list = oneTwo.ToFWList(); list.InsertRange(1, threeFour); ExpectList(list, 1, 3, 4, 2); list = threeFour.ToFWList(); list.InsertRange(2, oneTwo); ExpectList(list, 3, 4, 1, 2); // More tests... list.RemoveRange(0, 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.ToFVList(); list.RemoveRange(5, 4); ExpectList(list, 1, 2, 3, 4, 5); ExpectList(v, 1, 2, 3, 4, 5, 6, 7, 8, 9); }
/// <summary>Maps a list to another list of the same length.</summary> /// <param name="map">A function that transforms each item in the list.</param> /// <returns>The list after the map function is applied to each item. The /// original VList structure is not modified.</returns> /// <remarks> /// This method is called "Smart" because of what happens if the map /// doesn't do anything. If the map function returns the first N items /// unmodified (the items at the tail of the FWList), those N items are /// typically not copied, but shared between the existing list and the /// new one. /// </remarks> public FWList <T> SmartSelect(Func <T, T> map) { FWList <T> newList = new FWList <T>(); if (LocalCount != 0) { Block.SmartSelect(LocalCount, map, newList); } return(newList); }
/// <summary>Applies a filter to a list, to exclude zero or more /// items.</summary> /// <param name="keep">A function that chooses which items to include /// (exclude items by returning false).</param> /// <returns>The list after filtering has been applied. The original VList /// structure is not modified.</returns> /// <remarks> /// If the predicate keeps the first N items it is passed (which are the /// last or "tail" items in a FWList), those N items are typically not /// copied, but shared between the existing list and the new one. /// </remarks> public FWList <T> SmartWhere(Func <T, bool> keep) { FWList <T> newList = new FWList <T>(); if (LocalCount != 0) { Block.Where(LocalCount, keep, newList); } return(newList); }
/// <summary>Applies a filter to a list, to exclude zero or more /// items.</summary> /// <param name="keep">A function that chooses which items to include /// (exclude items by returning false).</param> /// <returns>The list after filtering has been applied. The original RVList /// structure is not modified.</returns> /// <remarks> /// If the predicate keeps the first N items it is passed (which are the /// last or "tail" items in a FWList), those N items are typically not /// copied, but shared between the existing list and the new one. /// </remarks> public FWList <T> Where(Predicate <T> keep) { FWList <T> newList = new FWList <T>(); if (LocalCount != 0) { Block.Where(LocalCount, keep, newList); } return(newList); }
/// <summary>Filters and maps a list with a user-defined function.</summary> /// <param name="filter">A function that chooses which items to include /// in a new list, and what to change them to.</param> /// <returns>The list after filtering has been applied. The original list /// structure is not modified.</returns> /// <remarks> /// This is a smart function. If the filter does not modify the first N /// items it is passed (which are the last items in a FWList), those N items /// are typically not copied, but shared between the existing list and the /// new one. /// </remarks> public FWList <T> WhereSelect(Func <T, Maybe <T> > filter) { FWList <T> newList = new FWList <T>(); if (LocalCount != 0) { Block.WhereSelect(LocalCount, filter, newList); } return(newList); }
public void TestFork() { FWList <int> A = new FWList <int>(); A.AddRange(new int[] { 5, 6, 7 }); FWList <int> B = A.Clone(); A.Push(4); ExpectList(B, 5, 6, 7); ExpectList(A, 4, 5, 6, 7); B.Push(-4); ExpectList(B, -4, 5, 6, 7); Assert.That(A.WithoutFirst(2) == B.WithoutFirst(2)); }
public void TestMutabilification() { // Make a single block mutable FVList <int> v = new FVList <int>(0, 1); FWList <int> w = v.ToFWList(); ExpectList(w, 0, 1); w[0] = 2; ExpectList(w, 2, 1); ExpectList(v, 0, 1); // Make another block, make the front block mutable, then the block-of-2 v.Push(-1); w = v.ToFWList(); w[0] = 3; ExpectList(w, 3, 0, 1); Assert.That(w.WithoutFirst(1) == v.WithoutFirst(1)); w[1] = 2; ExpectList(w, 3, 2, 1); Assert.That(w.WithoutFirst(1) != v.WithoutFirst(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 FVList <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, 0, 1, 2, 3, 4, 5, 6); // 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.ToFWList(); w.AddRange(new int[] { 5, 4, 3, 2, 1 }); Assert.AreEqual(w.Count, 12); ExpectList(w, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6); // Indices: 0 1 2 3 4 5 6 7 8 9 10 11 // Blocks: block A | B | C| D| E| F| G| H Assert.AreEqual(8, w.BlockChainLength); Assert.AreEqual(4, w.LocalCount); w[8] = -3; ExpectList(w, 5, 4, 3, 2, 1, 0, 1, 2, -3, 4, 5, 6); // Blocks: block A | block I | F| G| H Assert.AreEqual(5, w.BlockChainLength); }
public void RandomTest() { int seed = Environment.TickCount; Random r = new Random(seed); int action, index, iteration = 0, i = -1; FWList <int> wlist = new FWList <int>(); List <int> list = new List <int>(); // Perform a series of random operations on FWList: // - Calling the setter // - RemoveAt // - Add to front // - Insert // - Making part of the list immutable try { for (iteration = 0; iteration < 100; iteration++) { action = r.Next(5); int range = list.Count + (action >= 2 ? 1 : 0); if (range == 0) { iteration--; continue; } index = r.Next(range); switch (action) { case 0: list.RemoveAt(index); wlist.RemoveAt(index); break; case 1: list[index] = iteration; wlist[index] = iteration; break; case 2: list.Insert(0, iteration); wlist.Add(iteration); break; case 3: list.Insert(index, iteration); wlist.Insert(index, iteration); break; case 4: FVList <int> v = wlist.WithoutFirst(index); if (r.Next(2) == 0) { v.Add(index); } break; } Assert.AreEqual(list.Count, wlist.Count); for (i = 0; i < list.Count; i++) { Assert.AreEqual(list[i], wlist[i]); } } } catch (Exception e) { Console.WriteLine("{0} with seed {1} at iteration {2}, i={3}", e.GetType().Name, seed, iteration, i); throw; } }
public void TestFalseOwnership() { // This test tries to make sure a FWList doesn't get confused about what // blocks it owns. It's possible for a FWList to share a partially-mutable // block that contains mutable items with another FWList, but only one // FWList owns the items. // Case 1: two WLists point to the same block but only one owns it: // // block 0 // owned by A // |____3| block 1 // |____2| unowned // A,B--->|Imm_1|--->|Imm_1| // |____0| |____0| // // (The location of "Imm" in each block denotes the highest immutable // item; this diagram shows there are two immutable items in each // block) FWList <int> A = new FWList <int>(4); for (int i = 0; i < 4; i++) { A[i] = i; } FWList <int> B = A.Clone(); // B can't add to the second block because it's not the owner, so a // third block is created when we Add(1). B.Add(1); A.Add(-1); ExpectList(A, -1, 0, 1, 2, 3); ExpectList(B, 1, 0, 1, 2, 3); Assert.AreEqual(2, A.BlockChainLength); Assert.AreEqual(3, B.BlockChainLength); // Case 2: two WLists point to different blocks but they share a common // tail, where one list owns part of the tail and the other does not: // // block 0 // owned by B // |____8| // |____7| // |____6| // |____5| block 1 // |____4| owned by A // |____3| A |____3| block 2 // |____2| | |____2| unowned // |____1|---+---->|Imm_1|---->|Imm_1| // B--->|____0| |____0| |____0| // mutable // // Actually the previous test puts us in just this state. // // I can't think of a test that uses the public interface to detect bugs // in this case. The most important thing is that B._block.PriorIsOwned // returns false. Assert.That(B.IsOwner && !B.Block.PriorIsOwned); Assert.That(A.IsOwner); Assert.That(B.Block.Prior == A.WithoutFirst(1)); }
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. FWList <int> list = new FWList <int>(); Assert.That(list.IsEmpty); // create VListBlockOfTwo list = new FWList <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, 3, 2, 1); FVList <int> snap = list.ToFVList(); ExpectList(snap, 3, 2, 1); // AddRange(), Push(), Pop() list.Push(4); list.AddRange(new int[] { 6, 5 }); ExpectList(list, 6, 5, 4, 3, 2, 1); Assert.AreEqual(list.Pop(), 6); ExpectList(list, 5, 4, 3, 2, 1); list.RemoveRange(0, 2); ExpectList(list, 3, 2, 1); // Double the list list.AddRange(list); ExpectList(list, 3, 2, 1, 3, 2, 1); list.RemoveRange(0, 3); // Fill a third block list.AddRange(new int[] { 9, 8, 7, 6, 5, 4 }); list.AddRange(new int[] { 14, 13, 12, 11, 10 }); ExpectList(list, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1); // Remove(), enumerator list.Remove(14); list.Remove(13); list.Remove(12); list.Remove(11); ExpectListByEnumerator(list, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1); // 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.First == 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, 3, 2, 1); }