Пример #1
0
    public void Equality()
    {
        // mortals are not congruent or equal
        var s1 = new LifetimeSource();
        var s2 = new LifetimeSource();
        var a  = new Func <Lifetime>[] {
            () => Lifetime.Immortal,
            () => Lifetime.Dead,
            () => s1.Lifetime,
            () => s2.Lifetime
        };

        for (var i = 0; i < a.Length; i++)
        {
            for (var j = 0; j < a.Length; j++)
            {
                a[i]().IsCongruentTo(a[j]()).AssertEquals(i == j);
                a[i]().Equals(a[j]()).AssertEquals(i == j);
                if (i == j)
                {
                    a[i]().GetHashCode().AssertEquals(a[j]().GetHashCode());
                }
            }
        }

        // but mortals become congruent when set to the same phase
        s1.EndLifetime();
        s2.EndLifetime();
        s1.Lifetime.IsCongruentTo(s2.Lifetime).AssertIsTrue();
    }
Пример #2
0
    public void AsCancellationToken()
    {
        ((CancellationToken)Lifetime.Immortal).CanBeCanceled.AssertIsFalse();
        ((CancellationToken)Lifetime.Dead).IsCancellationRequested.AssertIsTrue();

        // cancelled on death
        var doomed           = new LifetimeSource();
        CancellationToken dt = doomed.Lifetime;

        dt.CanBeCanceled.AssertIsTrue();
        dt.IsCancellationRequested.AssertIsFalse();
        doomed.EndLifetime();
        dt.IsCancellationRequested.AssertIsTrue();
        // already cancelled when already dead
        ((CancellationToken)doomed.Lifetime).IsCancellationRequested.AssertIsTrue();

        // hangs on immortal
        var blessed          = new LifetimeSource();
        CancellationToken bt = blessed.Lifetime;

        bt.CanBeCanceled.AssertIsTrue();
        bt.IsCancellationRequested.AssertIsFalse();
        blessed.ImmortalizeLifetime();
        bt.IsCancellationRequested.AssertIsFalse();
        // knows can't be cancelled when already immortal
        ((CancellationToken)blessed.Lifetime).CanBeCanceled.AssertIsFalse();

        // hangs on limbo
        InvalidCallbackMaker.AssertNotCollectedAfter(action => {
            var r = new LifetimeSource();
            CancellationToken ct = r.Lifetime;
            ct.Register(action);
            return(ct);
        });
    }
    public void CurrentAndFutureItems()
    {
        var source = new LifetimeSource();
        var p1     = new Perishable <int>(1, source.Lifetime);
        var p2     = new Perishable <int>(1, Lifetime.Immortal);
        var p      = new PerishableCollection <int>();

        var li0 = new List <Perishable <int> >();

        p.CurrentAndFutureItems().Subscribe(e => {
            li0.Add(e);
            e.Lifetime.WhenDead(() => li0.Remove(e));
        });
        li0.AssertSequenceEquals();

        p.Add(p1);
        li0.AssertSequenceEquals(p1);

        var li1 = new List <Perishable <int> >();

        p.CurrentAndFutureItems().Subscribe(e => {
            li1.Add(e);
            e.Lifetime.WhenDead(() => li1.Remove(e));
        });
        li1.AssertSequenceEquals(p1);

        p.Add(p2.Value, p2.Lifetime);
        li0.AssertSequenceEquals(p1, p2);
        li1.AssertSequenceEquals(p1, p2);

        source.EndLifetime();
        li0.AssertSequenceEquals(p2);
        li1.AssertSequenceEquals(p2);
    }
Пример #4
0
    public void Max()
    {
        Lifetime.Dead.Max(Lifetime.Dead).IsDead.AssertIsTrue();
        Lifetime.Dead.Max(Lifetime.Immortal).IsImmortal.AssertIsTrue();
        Lifetime.Immortal.Max(Lifetime.Dead).IsImmortal.AssertIsTrue();
        Lifetime.Immortal.Max(Lifetime.Immortal).IsImmortal.AssertIsTrue();

        var s1 = new LifetimeSource();
        var s2 = new LifetimeSource();
        var s3 = new LifetimeSource();
        var m1 = s1.Lifetime.Max(s2.Lifetime);
        var m2 = s1.Lifetime.Max(s3.Lifetime);
        var m3 = s2.Lifetime.Max(s3.Lifetime);
        var t1 = m1.WhenDeadTask();
        var t2 = m2.WhenDeadTask();
        var t3 = m3.WhenDeadTask();

        // equality optimization
        s1.Lifetime.Max(s1.Lifetime).AssertEquals(s1.Lifetime);
        m1.Max(m1).AssertEquals(m1);
        // dead optimization
        s1.Lifetime.Max(Lifetime.Dead).AssertEquals(s1.Lifetime);
        Lifetime.Dead.Max(m1).AssertEquals(m1);

        // when one becomes immortal, max becomes immortal
        (m1.IsImmortal || m1.IsDead).AssertIsFalse();
        (m2.IsImmortal || m2.IsDead).AssertIsFalse();
        s1.ImmortalizeLifetime();
        m1.IsImmortal.AssertIsTrue();
        m2.IsImmortal.AssertIsTrue();

        // when one becomes dead, max is unaffected
        s2.EndLifetime();

        // when both become dead, max is dead
        (m3.IsImmortal || m3.IsDead).AssertIsFalse();
        t3.AssertNotCompleted();
        s3.EndLifetime();
        m3.IsDead.AssertIsTrue();
        t3.AssertRanToCompletion();

        Task.WhenAny(t1, t2).AssertNotCompleted();

        // limbo allows collection
        InvalidCallbackMaker.AssertCollectedAfter(a => {
            var r1    = new LifetimeSource();
            var r2    = new LifetimeSource();
            var r3    = new LifetimeSource();
            var life1 = r1.Lifetime.Max(r2.Lifetime);
            var life2 = r1.Lifetime.Max(r3.Lifetime);
            var life3 = r2.Lifetime.Max(r3.Lifetime);
            life1.WhenDead(a);
            life2.WhenDead(a);
            life3.WhenDead(a);
            r1.EndLifetime(); // one dead has no effect on max going to limbo
            return(Tuple.Create(life1, life2, life3));
        });
    }
Пример #5
0
    public void LifetimeDeathReentrancy()
    {
        var r  = new LifetimeSource();
        var r2 = new LifetimeSource();

        r.Lifetime.WhenDead(r2.EndLifetime, r2.Lifetime);
        r.Lifetime.WhenDead(r.EndLifetime);
        r.EndLifetime();
    }
    public void ToPerishableCollectionWithLifetime()
    {
        var source           = new LifetimeSource();
        var collectionSource = new LifetimeSource();
        var p1 = new Perishable <int>(1, source.Lifetime);
        var p2 = new Perishable <int>(1, Lifetime.Immortal);
        var p  = new PerishableCollection <int>();
        var q  = p.CurrentAndFutureItems().ToPerishableCollection(collectionSource.Lifetime);

        q.CurrentItems().AssertSequenceEquals();

        p.Add(p1);
        q.CurrentItems().AssertSequenceEquals(p1);

        collectionSource.EndLifetime();

        p.Add(p2.Value, p2.Lifetime);
        q.CurrentItems().AssertSequenceEquals(p1);

        source.EndLifetime();

        source.EndLifetime();
        q.CurrentItems().AssertSequenceEquals();
    }
Пример #7
0
    public void LifetimeDeathConcurrency()
    {
        var repeats = 5;

        foreach (var _ in Enumerable.Range(0, repeats))
        {
            var n             = 0;
            var source        = new LifetimeSource();
            var threadCount   = 4;
            var callbackCount = 3000;
            TestUtil.ConcurrencyTest(
                threadCount,
                callbackCount,
                repeatedWork: (t, i) => source.Lifetime.WhenDead(() => Interlocked.Increment(ref n)),
                finalWork: t => source.EndLifetime());
            n.AssertEquals(callbackCount * threadCount);
        }
    }
    public void CurrentAndFutureItems_EndingDuringEnumerationDoesNotLockup()
    {
        var s = new LifetimeSource();
        var p = new PerishableCollection <int>();

        for (var i = 0; i < 1000; i++)
        {
            p.Add(i, Lifetime.Immortal);
        }

        var t = Task.Factory.StartNew(
            () => p.CurrentAndFutureItems().Subscribe(
                item => s.EndLifetime(),
                s.Lifetime));

        t.Wait(TimeSpan.FromMilliseconds(100));
        t.AssertRanToCompletion();
    }
    public void CurrentItems()
    {
        var source = new LifetimeSource();
        var p1     = new Perishable <int>(1, source.Lifetime);
        var p2     = new Perishable <int>(1, Lifetime.Immortal);
        var p      = new PerishableCollection <int>();

        p.CurrentItems().AssertSequenceEquals();

        p.Add(p1);
        p.CurrentItems().AssertSequenceEquals(p1);

        p.Add(p2.Value, p2.Lifetime);
        p.CurrentItems().AssertSequenceEquals(p1, p2);

        source.EndLifetime();
        p.CurrentItems().AssertSequenceEquals(p2);
    }
Пример #10
0
    public void Status()
    {
        // status of constants
        Lifetime.Immortal.IsMortal.AssertIsFalse();
        Lifetime.Immortal.IsImmortal.AssertIsTrue();
        Lifetime.Immortal.IsDead.AssertIsFalse();
        Lifetime.Dead.IsMortal.AssertIsFalse();
        Lifetime.Dead.IsImmortal.AssertIsFalse();
        Lifetime.Dead.IsDead.AssertIsTrue();

        // state before transition
        var mortal = new LifetimeSource();

        mortal.Lifetime.IsMortal.AssertIsTrue();
        mortal.Lifetime.IsImmortal.AssertIsFalse();
        mortal.Lifetime.IsDead.AssertIsFalse();

        // transition to dead
        var doomed = new LifetimeSource();

        doomed.EndLifetime();
        doomed.Lifetime.IsMortal.AssertIsFalse();
        doomed.Lifetime.IsImmortal.AssertIsFalse();
        doomed.Lifetime.IsDead.AssertIsTrue();

        // transition to immortal
        var blessed = new LifetimeSource();

        blessed.ImmortalizeLifetime();
        blessed.Lifetime.IsMortal.AssertIsFalse();
        blessed.Lifetime.IsImmortal.AssertIsTrue();
        blessed.Lifetime.IsDead.AssertIsFalse();

        // transition to immortal via limbo
        var limbo = new LimboLife();

        limbo.Dispose();
        GC.Collect();
        limbo.Lifetime.IsMortal.AssertIsFalse();
        limbo.Lifetime.IsImmortal.AssertIsTrue();
        limbo.Lifetime.IsDead.AssertIsFalse();
    }
    public void ObserveNonPerishedCount()
    {
        var li1 = new List <int>();

        new[] { new Perishable <int>(1, Lifetime.Immortal), new Perishable <int>(2, Lifetime.Immortal) }
        .ToObservable()
        .ObserveNonPerishedCount(completeWhenSourceCompletes: true)
        .Subscribe(li1.Add, () => li1.Add(-1));
        li1.AssertSequenceEquals(0, 1, 2, -1);

        var source = new LifetimeSource();
        var li2    = new List <int>();

        new[] { new Perishable <int>(1, source.Lifetime), new Perishable <int>(2, source.Lifetime) }
        .ToObservable()
        .ObserveNonPerishedCount(completeWhenSourceCompletes: false)
        .Subscribe(li2.Add, () => li2.Add(-1));
        li2.AssertSequenceEquals(0, 1, 2);
        source.EndLifetime();
        li2.AssertSequenceEquals(0, 1, 2, 1, 0, -1);
    }
Пример #12
0
    public void WhenSet()
    {
        // called when immortal?
        var blessed        = new LifetimeSource();
        var preBlessedLife = blessed.Lifetime.WhenDeadTask();

        blessed.ImmortalizeLifetime();
        var bt = new[] {
            Lifetime.Immortal.WhenDeadTask(),
            blessed.Lifetime.WhenDeadTask(),
            preBlessedLife
        };

        Task.WhenAny(bt).AssertNotCompleted();

        // called when dead?
        var doomed        = new LifetimeSource();
        var preDoomedLife = doomed.Lifetime.WhenDeadTask();

        doomed.EndLifetime();
        var dt = new[] {
            preDoomedLife,
            doomed.Lifetime.WhenDeadTask(),
            Lifetime.Dead.WhenDeadTask()
        };

        Task.WhenAll(dt).AssertRanToCompletion();

        // never called from limbo
        var limboed      = new LimboLife();
        var preLimboLife = limboed.Lifetime.WhenDeadTask();

        limboed.Dispose();
        Task.WhenAny(
            preLimboLife,
            limboed.Lifetime.WhenDeadTask()
            ).AssertNotCompleted();
    }
Пример #13
0
    public static void Main()
    {
        "=== Hit 'Enter' to advance ===".WriteLine();
        Break();

        ///////////////////////////////////////////////////
        "Manually inspecting a lifetime as it is killed:".WriteLine();
        var lifesource1 = new LifetimeSource();

        "Life #1: {0}".WriteLine(lifesource1);
        "Ending Life #1".WriteLine();
        lifesource1.EndLifetime();
        "Life #1: {0}".WriteLine(lifesource1);
        Break();

        ///////////////////////////////////////////////////
        "Manually inspecting a lifetime as it is immortalized:".WriteLine();
        var lifesource2 = new LifetimeSource();

        "Life #2: {0}".WriteLine(lifesource2);
        "Immortalizing Life #2".WriteLine();
        lifesource2.ImmortalizeLifetime();
        "Life #2: {0}".WriteLine(lifesource2);
        Break();

        ///////////////////////////////////////////////////
        "Using callbacks to inspect a lifetime as it is killed:".WriteLine();
        var lifesource3 = new LifetimeSource();

        "Life #3: {0}".WriteLine(lifesource3);
        "Registering WhenDead Life #3 (before)".WriteLine();
        lifesource3.Lifetime.WhenDead(() => "WhenDead Life #3 (before)".WriteLine());
        "Ending Life #3".WriteLine();
        lifesource3.EndLifetime();
        "Life #3: {0}".WriteLine(lifesource3);
        "Registering WhenDead Life #3 (after)".WriteLine();
        lifesource3.Lifetime.WhenDead(() => "WhenDead Life #3 (after)".WriteLine());
        Break();

        ///////////////////////////////////////////////////
        "Using conditional callbacks:".WriteLine();
        var lifesource4 = new LifetimeSource();
        var lifesource5 = new LifetimeSource();

        "Life #4: {0}".WriteLine(lifesource4);
        "Life #5: {0}".WriteLine(lifesource5);
        "Registering WhenDead 4 (requires 5)".WriteLine();
        lifesource4.Lifetime.WhenDead(
            () => "Running WhenDead 4 (requires 5)".WriteLine(),
            lifesource5.Lifetime);
        "Registering WhenDead 5 (requires 4)".WriteLine();
        lifesource5.Lifetime.WhenDead(
            () => "Running WhenDead 5 (requires 4)".WriteLine(),
            lifesource4.Lifetime);
        "Ending Life #4".WriteLine();
        lifesource4.EndLifetime();
        "Life #4: {0}".WriteLine(lifesource4);
        "Ending Life #5".WriteLine();
        lifesource5.EndLifetime();
        "Life #5: {0}".WriteLine(lifesource5);
        Break();

        ///////////////////////////////////////////////////
        CallbackGarbageTest(
            "Immortal Lifetime collectable callback test:",
            () => new LifetimeSource().Lifetime,
            (e, a) => e.WhenDead(a));
        ///////////////////////////////////////////////////
        var lifetimeMortal = new LifetimeSource();

        CallbackGarbageTest(
            "Conditioned-on-dying Lifetime collectable callback test:",
            () => lifetimeMortal.Lifetime,
            (e, a) => {
            var r = new LifetimeSource();
            e.WhenDead(a, r.Lifetime);
            r.EndLifetime();
        });
        GC.KeepAlive(lifetimeMortal);
        ///////////////////////////////////////////////////
        CallbackGarbageTest(
            "Immortal CancellationToken collectable callback test:",
            () => new CancellationTokenSource().Token,
            (e, a) => e.Register(a));

        ///////////////////////////////////////////////////
        "Garbage collection of a lifetime's source:".WriteLine();
        var lifesource6 = new LifetimeSource();
        var life6       = lifesource6.Lifetime;

        "Life #6: {0}".WriteLine(life6);
        "Allowing garbage collection of Life #6's source".WriteLine();
        lifesource6 = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
        "Life #6: {0}".WriteLine(life6);
        Break();

        ///////////////////////////////////////////////////
        "=== Hit 'Enter' to close ===".WriteLine();
        Break();
    }
        private void SetupEnergyAndTime(Game game, double energyLossForCutting, double energyGainPerConnectorBroken)
        {
            var elapsed = TimeSpan.Zero;
            var living  = new LifetimeSource();

            living.Lifetime.WhenDead(() => {
                if (Best == elapsed)
                {
                    LabelTitle.Text       = "New High Score! Try Again?";
                    LabelTitle.Foreground = new SolidColorBrush(Colors.Green);
                }
                else
                {
                    LabelTitle.Text       = "Game Over! Try Again?";
                    LabelTitle.Foreground = new SolidColorBrush(Colors.Red);
                }
                MenuPanel.Visibility = Visibility.Visible;
            }, game.Life);

            // show energy status
            var gains     = 0.0;
            var loses     = 0.0;
            var energy    = 50.0;
            var maxEnergy = 50.0;

            game.LoopActions.Add(step => {
                // energy decays faster and faster over time
                var t   = step.TimeStep.TotalSeconds;
                energy -= t * Math.Log(elapsed.TotalSeconds / 15 + 1).Max(1);

                // quickly decrease the size of the red/blue bars that show changes
                gains -= t * 5;
                loses -= t * 5;
                gains *= Math.Pow(0.01, t);
                loses *= Math.Pow(0.01, t);

                // keep everything reasonable
                gains  = gains.Clamp(0, 10);
                loses  = loses.Clamp(0, 10);
                energy = energy.Clamp(0, maxEnergy);

                // "draw" energy
                var w           = canvas.ActualWidth;
                BarEnergy.Fill  = new SolidColorBrush(Colors.Yellow.LerpTo(Colors.Green, (energy * 2 / maxEnergy).Clamp(0, 1)));
                BarLoses.Width  = ((energy + loses) / maxEnergy * w).Clamp(0, w);
                BarGains.Width  = (energy / maxEnergy * w).Clamp(0, w);
                BarEnergy.Width = ((energy - gains) / maxEnergy * w).Clamp(0, w);

                // hit 0 energy? game over
                if (energy == 0)
                {
                    living.EndLifetime();
                }
            }, game.Life);

            // track energy changes due to connectors dying
            game.Connectors.CurrentAndFutureItems().Subscribe(e => e.Lifetime.WhenDead(() => {
                // breaking connectors gain you some energy
                if (living.Lifetime.IsMortal)
                {
                    energy += energyGainPerConnectorBroken;
                }
                gains += energyGainPerConnectorBroken;

                // but making cuts costs energy
                if (e.Value.CutPoint != null)
                {
                    energy -= energyLossForCutting;
                    loses  += energyLossForCutting;
                }
            }), game.Life);

            // track times
            game.LoopActions.Add(step => {
                // advance time
                if (living.Lifetime.IsMortal)
                {
                    elapsed += step.TimeStep;
                }
                Best = Best.Max(elapsed);

                // show time
                TimeLabel.Text = String.Format("Time: {0:0.0}s", elapsed.TotalSeconds);

                // show best time (green when making best time)
                TimeBest.Background = new SolidColorBrush(
                    Best == elapsed
                    ? Color.FromArgb(128, 0, 255, 0)
                    : Colors.Transparent);
                TimeBest.Text = String.Format("Best: {0:0.0}s", Best.TotalSeconds);
            }, game.Life);
        }
Пример #15
0
 public void Dispose()
 {
     _source.EndLifetime();
 }