// runs, updates and commits itself, all in one. public void Run(IEnumerable <IShielded> trigger) { Shield.InTransaction(() => { var oldItems = _items.Value; if (oldItems == null || !oldItems.Overlaps(trigger)) { return; // not subscribed anymore.. } bool test = false; var testItems = Shield.IsolatedRun(() => test = Test()); if (test) { Trans(); } // _locals will have value if Trans() called Dispose on "itself". if (!_locals.HasValue && !testItems.SetEquals(oldItems)) { if (!testItems.Any()) { // get rid of all entries first. Remover(oldItems); throw new InvalidOperationException( "A conditional test function must access at least one shielded field."); } _items.Value = testItems; UpdateEntries(); } }); }
/// <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); } } }
/// <summary> /// Executes the function in a transaction, and returns its final result. /// Transactions may, in case of conflicts, get repeated from beginning. Your /// delegate should be ready for this. If you wish to do IO or similar /// operations, which should not be repeated, pass them to /// <see cref="Shield.SideEffect"/>. Nesting InTransaction calls is allowed, /// the nested transactions are treated as normal parts of the outer transaction. /// </summary> public static T InTransaction <T>(Func <T> act) { T retVal = default(T); Shield.InTransaction(() => { retVal = act(); }); return(retVal); }
public void Dispose() { Shield.InTransaction(() => { _items.Value = null; UpdateEntries(); }); }
/// <summary> /// Checks both the key and value, which may be useful due to the tree supporting multiple /// entries with the same key. /// </summary> public bool Contains(KeyValuePair <TKey, TValue> item) { var valueComp = EqualityComparer <TValue> .Default; return(Shield.InTransaction(() => RangeInternal(item.Key, item.Key).Any(n => valueComp.Equals(n.Value.Value, item.Value)))); }
/// <summary> /// Copy the dictionary contents to an array. Involves enumerating, might not get all /// items which should have been visible at the time of your commit. This does not /// affect read-only transactions, or those writers that do not logically depend on /// seeing all items. /// </summary> public void CopyTo(KeyValuePair <TKey, TItem>[] array, int arrayIndex) { Shield.InTransaction(() => { foreach (KeyValuePair <TKey, TItem> kvp in this) { array[arrayIndex++] = kvp; } }); }
/// <summary> /// Copy the sequence to an array. /// </summary> /// <param name="array">The array to copy to.</param> /// <param name="arrayIndex">Index in the array where to begin the copy.</param> public void CopyTo(T[] array, int arrayIndex) { Shield.InTransaction(() => { foreach (var v in this) { array[arrayIndex++] = v; } }); }
/// <summary> /// Try to get any one of the values stored under the given key. There may be multiple items /// under the same key! /// </summary> public bool TryGetValue(TKey key, out TValue value) { bool res = false; value = Shield.InTransaction(() => { var n = FindInternal(key); res = n != null; return(res ? n.Value.Value : default(TValue)); }); return(res); }
public CommitSubscription(CommitSubscriptionContext context, Func <bool> test, Action trans) { Context = context; Test = test; Trans = trans; Shield.InTransaction(() => { var items = Shield.IsolatedRun(() => Test()); if (!items.Any()) { throw new InvalidOperationException( "Test function must access at least one shielded field."); } _items.Value = items; UpdateEntries(); }); }
/// <summary> /// Search the sequence for the given item. /// </summary> /// <returns>The index of the item in the sequence, or -1 if not found.</returns> public int IndexOf(T item, IEqualityComparer <T> comp = null) { if (comp == null) { comp = EqualityComparer <T> .Default; } return(Shield.InTransaction(() => { var curr = _head; int i = 0; while (curr.Value != null && !comp.Equals(curr.Value.Value, item)) { i++; curr = curr.Value.Next; } return curr.Value == null ? -1 : i; })); }
private Shielded <Node> FindInternal(TKey key) { return(Shield.InTransaction(() => { var curr = _head.Value; int comparison; while (curr != null && (comparison = _comparer.Compare(curr.Value.Key, key)) != 0) { if (comparison > 0) { curr = curr.Value.Left; } else { curr = curr.Value.Right; } } return curr; })); }
private Shielded <ItemKeeper> RefToIndex(int index, bool plusOne = false) { return(Shield.InTransaction(() => { if (index < 0) { throw new IndexOutOfRangeException(); } var curr = _head; for (; index > 0; index--) { if (curr.Value == null) { throw new IndexOutOfRangeException(); } curr = curr.Value.Next; } if (!plusOne && curr.Value == null) { throw new IndexOutOfRangeException(); } return curr; })); }