/// <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(); }
/// <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 newValueA = await f(x, y, Box <A> .GetValue(value)); var newValue = Box <A> .New(newValueA); if (!validator(Box <A> .GetValue(newValue))) { return(false); } if (Interlocked.CompareExchange(ref value, newValue, current) == current) { Change?.Invoke(newValueA); 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);