public void Assert_Coherency_Swap()
        {
            const int NumIterations = 3_000_000;

            var atomicIntA = new LockFreeInt32(0);
            var atomicIntB = new LockFreeInt32(0);
            var runner     = NewRunner(new DummyImmutableVal(0, 0));

            runner.GlobalSetUp        = (_, __) => { atomicIntA.Set(0); atomicIntB.Set(0); };
            runner.AllThreadsTearDown = target => {
                FastAssertEqual(NumIterations, target.Value.Alpha);
                FastAssertEqual(NumIterations, target.Value.Bravo);
            };
            runner.ExecuteContinuousSingleWriterCoherencyTests(
                target => {
                var newA     = atomicIntA.IncrementAndGet();
                var newB     = atomicIntB.IncrementAndGet();
                var newValue = new DummyImmutableVal(newA, newB);
                var prev     = target.Swap(newValue);
                FastAssertEqual(prev.Alpha, newA - 1);
                FastAssertEqual(prev.Bravo, newB - 1);
            },
                NumIterations,
                target => target.Value,
                (prev, cur) => {
                FastAssertTrue(prev.Alpha <= cur.Alpha);
                FastAssertTrue(prev.Bravo <= cur.Bravo);
            }
                );
            runner.GlobalSetUp        = null;
            runner.AllThreadsTearDown = null;
        }
        public void Assert_Coherency_Set()
        {
            const int NumIterations = 1_000_000;
            var       atomicIntA    = new LockFreeInt32(0);
            var       atomicIntB    = new LockFreeInt32(0);

            // void Set(T newValue, out T previousValue);
            var runner = NewRunner(new DummyImmutableVal(0, 0));

            runner.GlobalSetUp        = (_, __) => { atomicIntA.Set(0); atomicIntB.Set(0); };
            runner.AllThreadsTearDown = target => {
                FastAssertEqual(NumIterations, target.Value.Alpha);
                FastAssertEqual(NumIterations, target.Value.Bravo);
            };
            runner.ExecuteContinuousSingleWriterCoherencyTests(
                target => {
                target.Set(
                    new DummyImmutableVal(atomicIntA.IncrementAndGet(), atomicIntB.DecrementAndGet()),
                    out var prevValue
                    );
                FastAssertEqual(atomicIntA.Value - 1, prevValue.Alpha);
                FastAssertEqual(atomicIntB.Value + 1, prevValue.Bravo);
            },
                NumIterations,
                target => target.Value,
                (prev, cur) => {
                FastAssertTrue(prev.Alpha <= cur.Alpha);
                FastAssertTrue(prev.Bravo >= cur.Alpha);
            }
                );
            runner.GlobalSetUp        = null;
            runner.AllThreadsTearDown = null;

            // T Set(Func<T, T> valueMapFunc);
            runner.AllThreadsTearDown = target => {
                FastAssertEqual(NumIterations, target.Value.Alpha);
                FastAssertEqual(-NumIterations, target.Value.Bravo);
            };
            runner.ExecuteFreeThreadedTests(
                target => {
                var curVal = target.Value;
                var newVal = target.Set(t => new DummyImmutableVal(t.Alpha + 1, t.Bravo - 1));
                FastAssertTrue(curVal.Alpha < newVal.Alpha);
                FastAssertTrue(curVal.Bravo > newVal.Bravo);
            },
                NumIterations
                );
            runner.AllThreadsTearDown = null;

            // T Set(Func<T, T> valueMapFunc, out T previousValue);
            runner.AllThreadsTearDown = target => {
                FastAssertEqual(NumIterations, target.Value.Alpha);
                FastAssertEqual(-NumIterations, target.Value.Bravo);
            };
            runner.ExecuteFreeThreadedTests(
                target => {
                var curVal = target.Value;
                var newVal = target.Set(t => new DummyImmutableVal(t.Alpha + 1, t.Bravo - 1), out var prevVal);
                FastAssertTrue(curVal.Alpha < newVal.Alpha);
                FastAssertTrue(curVal.Bravo > newVal.Bravo);
                FastAssertEqual(newVal.Alpha - 1, prevVal.Alpha);
                FastAssertEqual(newVal.Bravo + 1, prevVal.Bravo);
            },
                NumIterations
                );
            runner.AllThreadsTearDown = null;
        }