コード例 #1
0
        public void Test01b()
        {
            string[][] successors = new string[][]
            {
                /* 0 */ new string[] { }, // 0 has no successors
                /* 1 */ new string[] { },
                /* 2 */ new string[] { "3" },
                /* 3 */ new string[] { "1" },
                /* 4 */ new string[] { "0", "1" },
                /* 5 */ new string[] { "0", "2" },
            };

            Func <string, IEnumerable <string> > succF = x => successors[int.Parse(x)];
            var sorted = TopologicalSort.IterativeSort <string>(new[] { "4", "5" }, i => succF(i).ToImmutableArray());

            AssertTopologicallySorted(sorted, succF, "Test01");
            Assert.Equal(6, sorted.Length);
            AssertEx.Equal(new[] { "4", "5", "2", "3", "1", "0" }, sorted);
        }
コード例 #2
0
        public void Test01()
        {
            int[][] successors = new int[][]
            {
                /* 0 */ new int[] { }, // 0 has no successors
                /* 1 */ new int[] { },
                /* 2 */ new int[] { 3 },
                /* 3 */ new int[] { 1 },
                /* 4 */ new int[] { 0, 1, 0, 1 }, // tolerate duplicate edges
                /* 5 */ new int[] { 0, 2 },
            };

            Func <int, IEnumerable <int> > succF = x => successors[x];
            var sorted = TopologicalSort.IterativeSort <int>(new[] { 4, 5 }, i => succF(i).ToImmutableArray());

            AssertTopologicallySorted(sorted, succF, "Test01");
            Assert.Equal(6, sorted.Length);
            AssertEx.Equal(new[] { 4, 5, 2, 3, 1, 0 }, sorted);
        }
コード例 #3
0
        public void TestCycle()
        {
            int[][] successors = new int[][]
            {
                /* 0 */ new int[] { },
                /* 1 */ new int[] { 2, 4 },
                /* 2 */ new int[] { },
                /* 3 */ new int[] { 2, 5 },
                /* 4 */ new int[] { 2, 3 },
                /* 5 */ new int[] { 2, 1 },
                /* 6 */ new int[] { 2, 7 },
                /* 7 */ new int[] { }
            };

            // 1 -> 4 -> 3 -> 5 -> 1
            Assert.Throws <ArgumentException>(() =>
            {
                var sorted = TopologicalSort.IterativeSort <int>(new[] { 1 }, x => successors[x].ToImmutableArray());
            });
        }
コード例 #4
0
        public void Test02()
        {
            int[][] successors = new int[][]
            {
                /* 0 */ new int[] { },
                /* 1 */ new int[] { 2, 4 },
                /* 2 */ new int[] { },
                /* 3 */ new int[] { 2, 5 },
                /* 4 */ new int[] { 2, 3 },
                /* 5 */ new int[] { 2, },
                /* 6 */ new int[] { 2, 7 },
                /* 7 */ new int[] { }
            };

            Func <int, IEnumerable <int> > succF = x => successors[x];
            var sorted = TopologicalSort.IterativeSort <int>(new[] { 1, 6 }, i => succF(i).ToImmutableArray());

            AssertTopologicallySorted(sorted, succF, "Test02");
            Assert.Equal(7, sorted.Length);
            AssertEx.Equal(new[] { 1, 4, 3, 5, 6, 7, 2 }, sorted);
        }
コード例 #5
0
        /// <summary>
        /// Build the decision dag, giving an error if some cases are subsumed and a warning if the switch expression is not exhaustive.
        /// </summary>
        /// <param name="node"></param>
        /// <param name="boundInputExpression"></param>
        /// <param name="switchArms"></param>
        /// <param name="decisionDag"></param>
        /// <param name="diagnostics"></param>
        /// <returns>true if there was a non-exhaustive warning reported</returns>
        private bool CheckSwitchExpressionExhaustive(
            SwitchExpressionSyntax node,
            BoundExpression boundInputExpression,
            ImmutableArray <BoundSwitchExpressionArm> switchArms,
            out BoundDecisionDag decisionDag,
            out LabelSymbol defaultLabel,
            DiagnosticBag diagnostics)
        {
            defaultLabel = new GeneratedLabelSymbol("default");
            decisionDag  = DecisionDagBuilder.CreateDecisionDagForSwitchExpression(this.Compilation, node, boundInputExpression, switchArms, defaultLabel, diagnostics);
            var reachableLabels = decisionDag.ReachableLabels;

            foreach (BoundSwitchExpressionArm arm in switchArms)
            {
                if (!reachableLabels.Contains(arm.Label))
                {
                    diagnostics.Add(ErrorCode.ERR_SwitchArmSubsumed, arm.Pattern.Syntax.Location);
                }
            }

            if (!reachableLabels.Contains(defaultLabel))
            {
                // switch expression is exhaustive; no default label needed.
                defaultLabel = null;
                return(false);
            }

            // We only report exhaustive warnings when the default label is reachable through some series of
            // tests that do not include a test in which the value is known to be null.  Handling paths with
            // nulls is the job of the nullable walker.
            foreach (var n in TopologicalSort.IterativeSort <BoundDecisionDagNode>(new[] { decisionDag.RootNode }, nonNullSuccessors))
            {
                if (n is BoundLeafDecisionDagNode leaf && leaf.Label == defaultLabel)
                {
                    diagnostics.Add(ErrorCode.WRN_SwitchExpressionNotExhaustive, node.SwitchKeyword.GetLocation());
                    return(true);
                }
            }

            return(false);

            ImmutableArray <BoundDecisionDagNode> nonNullSuccessors(BoundDecisionDagNode n)
            {
                switch (n)
                {
                case BoundTestDecisionDagNode p:
                    switch (p.Test)
                    {
                    case BoundDagNonNullTest t:         // checks that the input is not null
                        return(ImmutableArray.Create(p.WhenTrue));

                    case BoundDagExplicitNullTest t:         // checks that the input is null
                        return(ImmutableArray.Create(p.WhenFalse));

                    default:
                        return(BoundDecisionDag.Successors(n));
                    }

                default:
                    return(BoundDecisionDag.Successors(n));
                }
            }
        }
コード例 #6
0
        public void TestRandom(int seed)
        {
            int    numberOfNodes = 100;
            Random random        = new Random(seed);

            // First, we produce a list of integers representing a possible (reversed)
            // topological sort of the graph we will construct
            var possibleSort = Enumerable.Range(0, numberOfNodes).ToArray();

            shuffle(possibleSort);

            // Then we produce a set of edges that is consistent with that possible topological sort
            int[][] successors = new int[numberOfNodes][];
            for (int i = numberOfNodes - 1; i >= 0; i--)
            {
                successors[possibleSort[i]] = randomSubset((int)Math.Sqrt(i), i);
            }

            // Perform a topological sort and check it.
            Func <int, IEnumerable <int> > succF = x => successors[x];
            var sorted = TopologicalSort.IterativeSort <int>(Enumerable.Range(0, numberOfNodes).ToArray(), i => succF(i).ToImmutableArray());

            Assert.Equal(numberOfNodes, sorted.Length);
            AssertTopologicallySorted(sorted, succF, $"TestRandom(seed: {seed})");

            // Now we modify the graph to add an edge from the last node to the first node, which
            // probably induces a cycle.  Since the graph is random, it is possible that this does
            // not induce a cycle. However, by the construction of the graph it is almost certain
            // that a cycle is induced. Nevertheless, to avoid flakiness in the tests, we do not
            // test with actual random graphs, but with graphs based on pseudo-random sequences using
            // random seeds hardcoded into the tests. That way we are testing on the same graphs each
            // time.
            successors[possibleSort[0]] = successors[possibleSort[0]].Concat(new int[] { possibleSort[numberOfNodes - 1] }).ToArray();

            Assert.Throws <ArgumentException>(() =>
            {
                TopologicalSort.IterativeSort <int>(Enumerable.Range(0, numberOfNodes).ToArray(), i => succF(i).ToImmutableArray());
            });

            // where
            void shuffle(int[] data)
            {
                int length = data.Length;

                for (int t = 0; t < length - 1; t++)
                {
                    int r = random.Next(t, length);
                    if (t != r)
                    {
                        var tmp = data[t];
                        data[t] = data[r];
                        data[r] = tmp;
                    }
                }
            }

            int[] randomSubset(int count, int limit)
            {
                // We don't worry about duplicate values. That's all part of the test,
                // as the topological sort should tolerate duplicate edges.
                var result = new int[count];

                for (int i = 0; i < count; i++)
                {
                    result[i] = possibleSort[random.Next(0, limit)];
                }

                return(result);
            }
        }