/// <summary> /// Atomically updates the value by passing the old value to `f` and updating /// the atom with the result. Note: `f` may be called multiple times, so it /// should be free of side-effects. /// </summary> /// <param name="f">Function to update the atom</param> /// <returns>`true` if new-value passes any validation and was successfully set. `false` /// will only be returned if the `validator` fails.</returns> public bool Swap(Func <M, A, A> f) { f = f ?? throw new ArgumentNullException(nameof(f)); var retries = maxRetries; while (retries > 0) { retries--; var current = value; var newValueA = f(metadata, Box <A> .GetValue(value)); var newValue = Box <A> .New(newValueA); if (!validator(newValueA)) { return(false); } if (Interlocked.CompareExchange(ref value, newValue, current) == current) { Change?.Invoke(newValueA); return(true); } SpinWait sw = default; sw.SpinOnce(); } throw new DeadlockException(); }
Atom(M metadata, A value, Func <A, bool> validator) { this.value = Box <A> .New(value); this.metadata = metadata; this.validator = validator; }
/// <summary> /// Atomically updates the value by passing the old value to `f` and updating /// the atom with the result. Note: `f` may be called multiple times, so it /// should be free of side-effects. /// </summary> /// <param name="x">Additional value to pass to `f`</param> /// <param name="y">Additional value to pass to `f`</param> /// <param name="f">Function to update the atom</param> /// <returns>`true` if new-value passes any validation and was successfully set. `false` /// will only be returned if the `validator` fails.</returns> public async Task <bool> SwapAsync <X, Y>(X x, Y y, Func <X, Y, A, Task <A> > f) { f = f ?? throw new ArgumentNullException(nameof(f)); var retries = maxRetries; while (retries > 0) { retries--; var current = value; var newValue = Box.New(await f(x, y, value.Value)); if (!validator(newValue.Value)) { return(false); } if (Interlocked.CompareExchange(ref value, newValue, current) == current) { Change?.Invoke(newValue.Value); return(true); } SpinWait sw = default; sw.SpinOnce(); } throw new DeadlockException(); }
/// <summary> /// Atomically updates the value by passing the old value to `f` and updating /// the atom with the result. Note: `f` may be called multiple times, so it /// should be free of side-effects. /// </summary> /// <param name="f">Function to update the atom</param> /// <returns>Option in a Some state, with the result of the invocation of `f`, if the swap succeeded /// and its validation passed. None otherwise</returns> public Option <A> Swap(Func <M, A, A> f) { f = f ?? throw new ArgumentNullException(nameof(f)); SpinWait sw = default; while (true) { var current = value; var newValueA = f(metadata, Box <A> .GetValue(value)); var newValue = Box <A> .New(newValueA); if (!validator(newValueA)) { return(default);
Atom(A value, Func <A, bool> validator) { this.value = Box.New(value); this.validator = validator; }