/// <summary> /// Remove the specified key from the collection. /// </summary> public bool Remove(TKey key) { Shield.AssertInTransaction(); var keeper = PrepareWrite(key); if (keeper != null) { var res = !keeper.Empty; keeper.Empty = true; keeper.Value = default; return(res); } var old = CurrentTransactionOldValue(key); if (old == null || old.Empty) { return(false); } var locals = _localDict.Value; locals.Items[key] = new ItemKeeper { Empty = true }; locals.HasChanges = true; return(true); }
/// <summary> /// Gets or sets the item with the specified key. /// If there are many with the same key, acts on the first one it finds! /// </summary> public TValue this[TKey key] { get { return(Shield.InTransaction(() => { var n = FindInternal(key); if (n == null) { throw new KeyNotFoundException(); } return n.Value.Value; })); } set { Shield.AssertInTransaction(); // replaces the first occurrence... var n = FindInternal(key); if (n == null) { Add(key, value); } else { n.Modify((ref Node nInner) => nInner.Value = value); } } }
private void RemoveInternal(Shielded <Node> node) { Shield.AssertInTransaction(); // find the first follower in the right subtree (arbitrary choice..) Shielded <Node> follower; if (node.Value.Right == null) { follower = node; } else { follower = node.Value.Right; while (follower.Value.Left != null) { follower = follower.Value.Left; } // loosing the node value right now! node.Modify((ref Node n) => { var f = follower.Value; n.Key = f.Key; n.Value = f.Value; }); } DeleteOneChild(follower); OnRemove(); }
/// <summary> /// Remove the specified item from the sequence. /// </summary> public bool Remove(T item, IEqualityComparer <T> comp = null) { Shield.AssertInTransaction(); if (comp == null) { comp = EqualityComparer <T> .Default; } var curr = _head; ItemKeeper previous = null; while (curr.Value != null) { if (comp.Equals(item, curr.Value.Value)) { if (curr.Value.Next.Value == null) { _tail.Value = previous; } Skip(curr); return(true); } else { previous = curr; curr = curr.Value.Next; } } return(false); }
/// <summary> /// Remove the item at the given index. /// </summary> public void RemoveAt(int index) { Shield.AssertInTransaction(); if (index == 0) { if (_head.Value == null) { throw new IndexOutOfRangeException(); } Skip(_head); if (_head.Value == null) { _tail.Value = null; } } else { // slightly more tricky, in case we need to change _tail var r = RefToIndex(index - 1).Value; Skip(r.Next); if (r.Next.Value == null) { _tail.Value = r; } } }
/// <summary> /// Remove from the sequence all items that satisfy the given predicate. /// Returns the number of removed items in an out param, guaranteed to /// equal actual number of removed items even if the condition lambda throws. /// </summary> public void RemoveAll(Func <T, bool> condition, out int removed) { Shield.AssertInTransaction(); var curr = _head; var tail = _tail.Value; ItemKeeper previous = null; removed = 0; while (curr.Value != null) { if (condition(curr.Value.Value)) { removed++; if (tail == curr.Value) { _tail.Value = previous; if (previous == null) { _head.Value = null; break; } } Skip(curr); } else { previous = curr; curr = curr.Value.Next; } } }
/// <summary> /// Removes all items, but one by one. /// </summary> public void Clear() { Shield.AssertInTransaction(); foreach (var key in Keys) { Remove(key); } }
/// <summary> /// Add the specified key and value to the dictionary. /// </summary> /// <exception cref="ArgumentException">Thrown if the key is already present in the dictionary.</exception> public void Add(TKey key, TItem value) { Shield.AssertInTransaction(); if (ContainsKey(key)) { throw new ArgumentException("The given key is already present in the dictionary."); } this[key] = value; }
/// <summary> /// Get an enumerator for the dictionary contents. Iterating over this dictionary /// does not conflict with other transactions that are adding new items, so it /// is not fully safe. For read-only transactions, however, no problem. /// </summary> public IEnumerator <KeyValuePair <TKey, TItem> > GetEnumerator() { Shield.AssertInTransaction(); var keys = _localDict.HasValue ? _dict.Keys.Union(_localDict.Value.Items.Keys, _comparer) : _dict.Keys; foreach (var key in keys) { var v = Read(key); if (v == null || v.Empty) { continue; } yield return(new KeyValuePair <TKey, TItem>(key, v.Value)); } }
private void InsertInternal(TKey key, TValue item) { Shield.AssertInTransaction(); Shielded <Node> parent = null; var targetLoc = _head.Value; int comparison = 0; while (targetLoc != null) { parent = targetLoc; if ((comparison = _comparer.Compare(targetLoc.Value.Key, key)) > 0) { targetLoc = targetLoc.Value.Left; } else { targetLoc = targetLoc.Value.Right; } } var shN = new Shielded <Node>(new Node() { //Color = Color.Red, // the default anyway. Parent = parent, Key = key, Value = item }, _owner); if (parent != null) { if (comparison > 0) { parent.Modify((ref Node p) => p.Left = shN); } else { parent.Modify((ref Node p) => p.Right = shN); } } else { _head.Value = shN; } InsertProcedure(shN); OnInsert(); }
/// <summary> /// Enumerate all key-value pairs, whose keys are in the given range, but in descending /// key order. The range is inclusive, both from and to are included in the result (if /// the tree contains those keys). If from is smaller than to, the enumerable will not /// return anything. For forward enumeration you must explicitly use <see cref="Range"/>. /// </summary> public IEnumerable <KeyValuePair <TKey, TValue> > RangeDescending(TKey from, TKey to) { if (_comparer.Compare(from, to) < 0) { yield break; } Shield.AssertInTransaction(); Stack <Shielded <Node> > centerStack = new Stack <Shielded <Node> >(); var curr = _head.Value; while (curr != null) { while (curr.Value.Right != null && _comparer.Compare(curr.Value.Key, from) <= 0) { centerStack.Push(curr); curr = curr.Value.Right; } if (_comparer.Compare(curr.Value.Key, to) < 0) { yield break; } if (_comparer.Compare(curr.Value.Key, from) <= 0) { yield return(new KeyValuePair <TKey, TValue>(curr.Value.Key, curr.Value.Value)); } while (curr.Value.Left == null && centerStack.Count > 0) { curr = centerStack.Pop(); if (_comparer.Compare(curr.Value.Key, to) >= 0) { yield return(new KeyValuePair <TKey, TValue>(curr.Value.Key, curr.Value.Value)); } else { yield break; } } curr = curr.Value.Left; } }
/// <summary> /// Enumerates only over the nodes in the range. Borders included. /// </summary> private IEnumerable <Shielded <Node> > RangeInternal(TKey from, TKey to) { if (_comparer.Compare(from, to) > 0) { yield break; } Shield.AssertInTransaction(); Stack <Shielded <Node> > centerStack = new Stack <Shielded <Node> >(); var curr = _head.Value; while (curr != null) { while (curr.Value.Left != null && _comparer.Compare(curr.Value.Key, from) >= 0) { centerStack.Push(curr); curr = curr.Value.Left; } if (_comparer.Compare(curr.Value.Key, to) > 0) { yield break; } if (_comparer.Compare(curr.Value.Key, from) >= 0) { yield return(curr); } while (curr.Value.Right == null && centerStack.Count > 0) { curr = centerStack.Pop(); if (_comparer.Compare(curr.Value.Key, to) <= 0) { yield return(curr); } else { yield break; } } curr = curr.Value.Right; } }
/// <summary> /// Get an enumerator for the sequence. Although it is just a read, it must be /// done in a transaction since concurrent changes would make the result unstable. /// However, if you just read the first item (e.g. by calling Any or First), that /// will work out of transaction too. /// </summary> public IEnumerator <T> GetEnumerator() { var curr = _head.Value; if (curr == null) { yield break; } yield return(curr.Value); Shield.AssertInTransaction(); curr = curr.Next; while (curr != null) { yield return(curr.Value); curr = curr.Next; } }
/// <summary> /// Gets an enumerator for all the key-value pairs in the tree. /// </summary> public IEnumerator <KeyValuePair <TKey, TValue> > GetEnumerator() { Shield.AssertInTransaction(); Stack <Shielded <Node> > centerStack = new Stack <Shielded <Node> >(); var curr = _head.Value; while (curr != null) { while (curr.Value.Left != null) { centerStack.Push(curr); curr = curr.Value.Left; } yield return(new KeyValuePair <TKey, TValue>(curr.Value.Key, curr.Value.Value)); while (curr.Value.Right == null && centerStack.Count > 0) { curr = centerStack.Pop(); yield return(new KeyValuePair <TKey, TValue>(curr.Value.Key, curr.Value.Value)); } curr = curr.Value.Right; } }