/// <summary> /// Inserts a sequence at the specified index, pushing the element at the index forward. /// </summary> /// <param name="index"> The index. </param> /// <param name="items"> The sequence of items to insert. Very fast if the sequence is also an <see cref="ImmList{T}" />.</param> /// <returns> </returns> /// <exception cref="ArgumentOutOfRangeException">Thrown if the index doesn't exist.</exception> /// <exception cref="ArgumentNullException">Thrown if the IEnumerable is null.</exception> public ImmList <T> InsertRange(int index, IEnumerable <T> items) { items.CheckNotNull("items"); index.CheckIsBetween("index", -Root.Measure - 1, Root.Measure); index = index < 0 ? index + Length + 1 : index; if (index == 0) { return(AddFirstRange(items)); } if (index == Root.Measure) { return(AddLastRange(items)); } var list = items as ImmList <T>; if (list != null) { return(InsertList(index, list)); } FingerTree <T> .FTree <Leaf <T> > part1, part2; Root.Split(index, out part1, out part2, Lineage.Immutable); int len; var i = 0; var arr = items.ToArrayFast(out len); var lineage = Lineage.Mutable(); var middle = FingerTree <T> .FTree <Leaf <T> > .Construct(arr, ref i, len, lineage); return(part1.AddLastList(middle, Lineage.Immutable).AddLastList(part2, Lineage.Immutable).Wrap()); }
/// <summary> /// Provided for testing purposes only. Is too inefficient to be used in practice. /// </summary> /// <param name="index"></param> /// <param name="value"></param> /// <returns></returns> public ImmVector <T> Insert(int index, T value) { index = index < 0 ? index + Length + 1 : index; if (index == Length) { return(AddLast(value)); } if (index == 0) { return(AddFirstRange(new[] { value })); } var lineage = Lineage.Mutable(); var take = Root.Take(index - 1, lineage); take = take.Add(value, lineage); var arr = new T[Length - index]; CopyTo(arr, index, 0, Length - index); var len = arr.Length; var s = 0; var ret = take.AddRange(arr, lineage, 6, ref s, ref len); #if ASSERTS ret.Length.AssertEqual(Length + 1); #endif return(ret); }
/// <summary> /// Returns the set-theoretic union between this set and a set-like collection. /// </summary> /// <param name="other">A sequence of values. This operation is much faster if it's a set compatible with this one.</param> /// <returns></returns> public override ImmSortedSet <T> Union(IEnumerable <T> other) { other.CheckNotNull("other"); var set = other as ImmSortedSet <T>; if (set != null && IsCompatibleWith(set)) { return(Union(set)); } //this trick can't really be repeated with a non-ordered set... //or least I haven't figured it out yet. Basically, converts the sequence into an array, sorts it on its own //And then builds a tree out of it. Then it unions it with the main tree. This improves performance by a fair bit //Even if the data structure isn't an array already. int len; var arr = other.ToArrayFast(out len); Array.Sort(arr, 0, len, Comparer); arr.RemoveDuplicatesInSortedArray((a, b) => Comparer.Compare(a, b) == 0, ref len); var lineage = Lineage.Mutable(); var node = OrderedAvlTree <T, bool> .Node.FromSortedArraySet(arr, 0, len - 1, Comparer, lineage); var newRoot = node.Union(Root, null, lineage); return(newRoot.Wrap(Comparer)); }
/// <summary> /// removes the minimal key-value pair from this map. /// </summary> /// <returns></returns> public ImmSortedMap <TKey, TValue> RemoveMin() { if (Root.IsEmpty) { throw Errors.Is_empty; } return(Root.RemoveMin(Lineage.Mutable()).WrapMap(Comparer)); }
/// <summary> /// Removes the maximal element from the set. /// </summary> /// <returns></returns> public ImmSortedSet <T> RemoveMax() { if (Root.IsEmpty) { throw Errors.Is_empty; } return(Root.RemoveMax(Lineage.Mutable()).Wrap(Comparer)); }
/// <summary> /// Adds a new item to the set, or does nothing if the item already exists. /// </summary> /// <param name="item">The item to add.</param> /// <returns></returns> public override ImmSortedSet <T> Add(T item) { var ret = Root.Root_Add(item, true, Comparer, false, Lineage.Mutable()); if (ret == null) { return(this); } return(ret.Wrap(Comparer)); }
/// <summary> /// Removes an item from the set, or does nothing if the item does not exist. /// </summary> /// <param name="item">The item to remove.</param> /// <returns></returns> public override ImmSortedSet <T> Remove(T item) { var ret = Root.AvlRemove(item, Lineage.Mutable()); if (ret == null) { return(this); } return(ret.Wrap(Comparer)); }
/// <summary> /// Removes an item from the set, or does nothing if the item does not exist. /// </summary> /// <param name="item">The item to remove.</param> /// <returns></returns> public override ImmSet <T> Remove(T item) { var ret = Root.Root_Remove(item, Lineage.Mutable()); if (ret == null) { return(this); } return(ret.Wrap(EqualityComparer)); }
/// <summary> /// Removes a key from the map, or does nothing if the key does not exist. /// </summary> /// <param name="key">The key to remove.</param> /// <returns></returns> public override ImmSortedMap <TKey, TValue> Remove(TKey key) { var removed = Root.AvlRemove(key, Lineage.Mutable()); if (removed == null) { return(this); } return(removed.WrapMap(Comparer)); }
/// <summary> /// Adds a new item to the set, or does nothing if the item already exists. /// </summary> /// <param name="item">The item to add.</param> /// <returns></returns> public override ImmSet <T> Add(T item) { var res = Root.Root_Add(item, true, Lineage.Mutable(), EqualityComparer, false); if (res == null) { return(this); } return(res.Wrap(EqualityComparer)); }
/// <summary> /// Removes the specified key from the map, or does nothing if the key doesn't exist. /// </summary> /// <param name="k">The key.</param> /// <returns></returns> public override ImmMap <TKey, TValue> Remove(TKey k) { var removed = _root.Root_Remove(k, Lineage.Mutable()); if (removed == null) { return(this); } return(removed.WrapMap(_equality)); }
/// <summary> /// Removes several keys from this key-value map. /// </summary> /// <param name="keys">A sequence of keys to remove. Can be much faster if it's a set compatible with this map.</param> /// <returns></returns> public override ImmMap <TKey, TValue> RemoveRange(IEnumerable <TKey> keys) { keys.CheckNotNull("keys"); var set = keys as ImmSet <TKey>; if (set != null && _equality.Equals(set.EqualityComparer)) { return(_root.Except(set.Root, Lineage.Mutable()).WrapMap(_equality)); } return(base.RemoveRange(keys)); }
/// <summary> /// Inserts a sequence of elements at the specified index. /// </summary> /// <param name="index">The index at which to insert. The element at this index is pushed forward.</param> /// <param name="items">The items to insert. Faster if an array or a known collection type.</param> /// <returns></returns> public ImmVector <T> InsertRange(int index, IEnumerable <T> items) { index.CheckIsBetween("index", -Root.Length - 1, Root.Length); items.CheckNotNull("items"); index = index < 0 ? index + Root.Length + 1: index; if (index == 0) { return(AddFirstRange(items)); } if (index == Length) { return(AddLastRange(items)); } #if ASSERTS var oldLast = Last; var oldFirst = First; #endif var start = Root.Take(index - 1, Lineage.Immutable); var lineage = Lineage.Mutable(); var len = 0; var s = 0; var oldLength = Length; var arrInsert = items.ToArrayFast(out len); if (len == 0) { return(this); } var arrAfter = new T[oldLength - index]; CopyTo(arrAfter, index, 0, oldLength - index); var arrLength = len; if (len == 0) { return(this); } if (oldLength + len >= MaxCapacity) { throw Errors.Capacity_exceeded(); } start = start.AddRange(arrInsert, lineage, 6, ref s, ref len); len = oldLength - index; s = 0; start = start.AddRange(arrAfter, lineage, 6, ref s, ref len); ImmVector <T> ret = start; #if ASSERTS ret.Length.AssertEqual(oldLength + arrLength); ret.RecursiveLength().AssertEqual(ret.Length); ret.Last.AssertEqual(oldLast); ret.First.AssertEqual(oldFirst); ret[index].AssertEqual(arrInsert[0]); ret[index + arrLength - 1].AssertEqual(arrInsert[arrLength - 1]); #endif return(ret); }
/// <summary> /// Subtracts the key-value pairs in the specified map from this one, applying the subtraction function on each key shared between the maps. /// </summary> /// <param name="other">A sequence of key-value pairs. This operation is much faster if it's a map compatible with this one.</param> /// <param name="subtraction">Optionally, a subtraction function that generates the value in the resulting key-value map. Otherwise, key-value pairs are always removed.</param> /// <remarks> /// Subtraction over maps is anaologous to Except over sets. /// If the subtraction function is not specified (or is null), the operation simply subtracts all the keys present in the other map from this one. /// If a subtraction function is supplied, the operation invokes the function on each key-value pair shared with the other map. If the function returns a value, /// that value is used in the return map. If the function returns None, the key is removed from the return map. /// </remarks> public override ImmSortedMap <TKey, TValue> Subtract <TValue2>(IEnumerable <KeyValuePair <TKey, TValue2> > other, ValueSelector <TKey, TValue, TValue2, Optional <TValue> > subtraction = null) { other.CheckNotNull("other"); var map = other as ImmSortedMap <TKey, TValue2>; if (map != null && Comparer.Equals(map.Comparer)) { return(Root.Except(map.Root, Lineage.Mutable(), subtraction).WrapMap(Comparer)); } return(base.Subtract(other, subtraction)); }
protected override ImmMap <TKey, TValue> Set(TKey k, TValue v, bool overwrite) { var r = _root.Root_Add(k, v, Lineage.Mutable(), _equality, overwrite); if (r == null && !overwrite) { throw Errors.Key_exists(k); } if (r == null) { return(this); } return(r.WrapMap(_equality)); }
protected override ImmSortedMap <TKey, TValue> Set(TKey key, TValue value, bool overwrite) { var ret = Root.Root_Add(key, value, Comparer, overwrite, Lineage.Mutable()); if (ret == null && !overwrite) { throw Errors.Key_exists(key); } if (ret == null) { return(this); } return(ret.WrapMap(Comparer)); }
/// <summary> /// Removes the element at some index from the list. /// </summary> /// <param name="index"> The index to remove. </param> /// <exception cref="ArgumentOutOfRangeException">Thrown if the index does not exist in the list.</exception> /// <returns> </returns> public ImmList <T> RemoveAt(int index) { index.CheckIsBetween("index", -Root.Measure, Root.Measure - 1); index = index < 0 ? index + Root.Measure : index; var ret = Root.RemoveAt(index, Lineage.Mutable()).Wrap(); #if ASSERTS if (Root.Measure > index + 1) { ret[index].AssertEqual(this[index + 1]); } ret.Root.Measure.AssertEqual(Root.Measure - 1); #endif return(ret); }
/// <summary> /// <para>Joins the specified sequence or list to the beginning of this list.</para> /// <para>⚡ O(m)</para> /// </summary> /// <param name="items"> The items to add. Very fast if the sequence is also an <see cref="ImmList{T}" />.</param> /// <returns> </returns> /// <exception cref="ArgumentNullException">Thrown if the argument is null.</exception> public ImmList <T> AddFirstRange(IEnumerable <T> items) { items.CheckNotNull("items"); var list = items as ImmList <T>; if (list != null) { return(AddFirstList(list)); } var lineage = Lineage.Mutable(); int len; var arr = items.ToArrayFast(out len); var index = 0; var tree = FingerTree <T> .FTree <Leaf <T> > .Construct(arr, ref index, len, lineage); return(tree.AddLastList(Root, lineage).Wrap()); }
/// <summary> /// Copies data from an array.. /// </summary> /// <param name="arr">The arr.</param> /// <param name="startIndex">The start index.</param> /// <param name="count">The count.</param> /// <exception cref="ArgumentNullException">Thrown if the array is null.</exception> /// <exception cref="InvalidOperationException">Thrown if the collection exceeds its capacity.</exception> private ImmVector <T> CopyFrom(T[] arr, int startIndex, int count) { arr.CheckNotNull("arr"); startIndex.CheckIsBetween("startIndex", -arr.Length, arr.Length - 1); startIndex = startIndex < 0 ? arr.Length + startIndex : startIndex; count.CheckIsBetween("count", 0, arr.Length - startIndex); if (Root.Length + arr.Length >= MaxCapacity) { throw Errors.Capacity_exceeded(); } var lineage = Lineage.Mutable(); var ret = Root.AddRange(arr, lineage, 6, ref startIndex, ref count); return(ret); }
/// <summary> /// Sets the value of the item at the specified index. /// </summary> /// <param name="index"> The index of the item to update. </param> /// <param name="item"> The new value of the item. </param> /// <returns> </returns> /// <exception cref="ArgumentOutOfRangeException">Thrown if the index doesn't exist.</exception> public ImmList <T> Update(int index, T item) { index.CheckIsBetween("index", -Root.Measure, Root.Measure - 1); index = index < 0 ? index + Root.Measure : index; if (index == 0) { return(RemoveFirst().AddFirst(item)); } if (index == Root.Measure - 1) { return(RemoveLast().AddLast(item)); } var ret = Root.Update(index, item, Lineage.Mutable()).Wrap(); ret[index].AssertEqual(item); ret.Root.Measure.AssertEqual(Root.Measure); return(ret); }
/// <summary> /// Inserts an item at the specified index, pushing the element at the index forward. /// </summary> /// <param name="index"> The index before which to insert the item. </param> /// <param name="item"> The item to insert. </param> /// <returns> </returns> /// <exception cref="ArgumentOutOfRangeException">Thrown if the index doesn't exist.</exception> public ImmList <T> Insert(int index, T item) { index.CheckIsBetween("index", -Root.Measure - 1, Root.Measure); index = index < 0 ? Root.Measure + index + 1 : index; if (index == Root.Measure) { return(AddLast(item)); } if (index == 0) { return(AddFirst(item)); } var newRoot = Root.Insert(index, item, Lineage.Mutable()); var ret = newRoot.Wrap(); ret[index].AssertEqual(item); ret.Root.Measure.AssertEqual(Root.Measure + 1); return(ret); }
/// <summary> /// Merges the two maps, applying the selector function for keys appearing in both maps. /// </summary> /// <param name="other">The other.</param> /// <param name="collision"> /// The collision resolution function. If null, the values in the other map overwrite the values in this map. /// </param> /// <remarks> /// The merge operation is analogous to a union operation over sets. /// /// This operation returns all key-value pairs present in either map. If a key is shared between both maps, the collision resolution function is applied to determine the value in the result map. /// </remarks> public override ImmSortedMap <TKey, TValue> Merge(IEnumerable <KeyValuePair <TKey, TValue> > other, ValueSelector <TKey, TValue, TValue, TValue> collision = null) { other.CheckNotNull("other"); var map = other as ImmSortedMap <TKey, TValue>; if (map != null && IsCompatibleWith(map)) { return(Merge(map, collision)); } int len; var arr = other.ToArrayFast(out len); var cmp = Comparers.KeyComparer <KeyValuePair <TKey, TValue>, TKey>(x => x.Key, Comparer); Array.Sort(arr, 0, len, cmp); arr.RemoveDuplicatesInSortedArray((a, b) => Comparer.Compare(a.Key, b.Key) == 0, ref len); var lineage = Lineage.Mutable(); var node = OrderedAvlTree <TKey, TValue> .Node.FromSortedArray(arr, 0, len - 1, Comparer, lineage); var newRoot = Root.Union(node, collision, lineage); return(newRoot.WrapMap(Comparer)); }
ImmList <T> InsertList(int index, ImmList <T> list) { index.CheckIsBetween("index", -Root.Measure - 1, Root.Measure); list.CheckNotNull("list"); index = index < 0 ? Root.Measure + index + 1 : index; if (index == 0) { return(list.AddLastRange(this)); } if (index == Root.Measure) { return(AddLastRange(list)); } var lineage = Lineage.Mutable(); FingerTree <T> .FTree <Leaf <T> > part1, part2; Root.Split(index, out part1, out part2, Lineage.Immutable); part1 = part1.AddLastList(list.Root, Lineage.Immutable); var result = part1.AddLastList(part2, Lineage.Immutable); return(result.Wrap()); }
/// <summary> /// Provided for testing purposes only. Is too inefficient to be used in practice. /// </summary> /// <param name="index"></param> /// <returns></returns> private ImmVector <T> RemoveAt(int index) { index = index < 0 ? index + Length : index; if (index == 0) { return(Skip(1)); } if (index == Length - 1) { return(RemoveLast()); } index.CheckIsBetween("index", 0, Length - 1); var lineage = Lineage.Mutable(); var take = Root.Take(index - 1, lineage); var arr = new T[Length - index - 1]; CopyTo(arr, index + 1, 0, Length - index - 1); var len = arr.Length; var s = 0; var ret = take.AddRange(arr, lineage, 6, ref s, ref len); return(ret); }
/// <summary> /// Adds a sequence of items to the end of the collection. /// </summary> /// <param name="items">A sequence of items to add. Faster if the sequence is an array or a known collection type.</param> /// <exception cref="ArgumentNullException">Thrown if the argument is null.</exception> /// <exception cref="InvalidOperationException">Thrown if the collection exceeds its capacity.</exception> /// <remarks>This member performs a lot better when the specified sequence is an array.</remarks> public ImmVector <T> AddLastRange(IEnumerable <T> items) { items.CheckNotNull("items"); #if ASSERTS var expected = Length; var oldLast = TryLast; #endif var len = 0; var s = 0; if (IsEmpty) { var asVector = items as ImmVector <T>; if (asVector != null) { return(asVector); } } var arr = items.ToArrayFast(out len); var oldLen = len; if (Root.Length + len >= MaxCapacity) { throw Errors.Capacity_exceeded(); } ImmVector <T> ret = Root.AddRange(arr, Lineage.Mutable(), 6, ref s, ref len); #if ASSERTS ret.Length.AssertEqual(expected + oldLen); if (arr.Length > 0 && oldLen > 0) { ret.Last.AssertEqual(arr[oldLen - 1]); } else if (oldLast.IsSome) { ret.Last.AssertEqual(oldLast.Value); } #endif return(ret); }
ImmMap <TKey, TValue> Except <TValue2>(ImmMap <TKey, TValue2> other, ValueSelector <TKey, TValue, TValue2, Optional <TValue> > subtraction = null) { other.CheckNotNull("other"); return(_root.Except(other._root, Lineage.Mutable(), subtraction).WrapMap(_equality)); }
protected override ImmMap <TKey, TValue> Difference(ImmMap <TKey, TValue> other) { other.CheckNotNull("other"); return(_root.SymDifference(other._root, Lineage.Mutable()).WrapMap(_equality)); }
protected override ImmSet <T> Difference(ImmSet <T> other) { return(Root.SymDifference(other.Root, Lineage.Mutable()).Wrap(EqualityComparer)); }
protected override ImmSet <T> Union(ImmSet <T> other) { return(Root.Union(other.Root, Lineage.Mutable()).Wrap(EqualityComparer)); }
protected override ImmSet <T> Intersect(ImmSet <T> other) { return(Root.Intersect(other.Root, Lineage.Mutable(), null).Wrap(EqualityComparer)); }