static TableFragment ExtractTransitionTable(ConfigTable table, CharSet[] charSets, int[] charClassMap, Dictionary <Graph.State, int> stateMap, Statistics statistics)
        {
            var fragments = new List <TableFragment>();

            foreach (var fromState in table.Graph.States)
            {
                int[] transitionsList = null;

                for (var i = 0; i < charSets.Length; i++)
                {
                    var toState = NextState(fromState, charSets[charClassMap[i]]);

                    if (toState != null)
                    {
                        if (transitionsList == null)
                        {
                            transitionsList = new int[charSets.Length];
                        }

                        transitionsList[i] = stateMap[toState] + 1;
                    }
                }

                if (transitionsList != null)
                {
                    fragments.Add(new TableFragment(transitionsList, stateMap[fromState]));
                }
                else
                {
                    statistics.StatesTerminal++;
                }
            }

            return(TableFragment.Combine(fragments));
        }
        public void Skip_NoExcess()
        {
            var fragment1 = new TableFragment(new int[] { 1, 1, 2, 2 }, 0);
            var fragment2 = new TableFragment(new int[] { 2 }, 1, 2);

            var combined = TableFragment.Combine(new TableFragment[]
            {
                fragment1,
                fragment2,
            });

            Assert.That(combined.Skip, Is.EqualTo(0));
            Assert.That(combined, Is.EquivalentTo(new int[] { 1, 1, 2, 2 }));
            Assert.That(combined.GetOffset(0), Is.EqualTo(0));
            Assert.That(combined.GetOffset(1), Is.EqualTo(1));
        }
        public void Skip_WithExcess()
        {
            var fragment1 = new TableFragment(new int[] { 1, 1, 2, 2 }, 0);
            var fragment2 = new TableFragment(new int[] { 2, 2, 3 }, 1, 0);
            var fragment3 = new TableFragment(new int[] { 3 }, 2, 5);

            var combined = TableFragment.Combine(new TableFragment[]
            {
                fragment1,
                fragment2,
                fragment3,
            });

            Assert.That(combined.Skip, Is.EqualTo(1));
            Assert.That(combined, Is.EquivalentTo(new int[] { 1, 1, 2, 2, 3 }));
            Assert.That(combined.GetOffset(0), Is.EqualTo(0));
            Assert.That(combined.GetOffset(1), Is.EqualTo(2));
            Assert.That(combined.GetOffset(2), Is.EqualTo(-1));
        }
        public void Combine()
        {
            var fragment1 = new TableFragment(new int[] { 1, 2, 3, -1 }, 0);
            var fragment2 = new TableFragment(new int[] { 1, 2, 3, -1 }, 1);
            var fragment3 = new TableFragment(new int[] { -1, -1, 2, -1 }, 2);
            var fragment4 = new TableFragment(new int[] { -1, 1, -1, -1 }, 3);

            var combined = TableFragment.Combine(new TableFragment[]
            {
                fragment1,
                fragment2,
                fragment3,
                fragment4,
            });

            Assert.That(combined.Skip, Is.EqualTo(0));
            Assert.That(combined, Is.EquivalentTo(new int[] { 1, 2, 3, -1, 1, -1, -1, 2, -1 }));
            Assert.That(combined.GetOffset(0), Is.EqualTo(0));
            Assert.That(combined.GetOffset(1), Is.EqualTo(0));
            Assert.That(combined.GetOffset(2), Is.EqualTo(5));
            Assert.That(combined.GetOffset(3), Is.EqualTo(3));
            Assert.That(combined.GetOffset(4), Is.EqualTo(null));
        }
        static CompressedBlob ExtractTransitionTableBlob(Config config, Statistics statistics, TableData data)
        {
            var graph              = config.Graph.Graph;
            var actionsList        = new int[data.StateMap.Count];
            var lastGotoStateIndex = data.StateMap.Count;

            var fragments = new List <TableFragment>();

            foreach (var state in graph.States)
            {
                var index         = data.StateMap[state];
                var transitionRow = ExtractTransitionRow(data, state);
                var gotoRow       = ExtractGotoRow(data, state);

                if (transitionRow.Fragment == null)
                {
                    actionsList[index] = transitionRow.ShortCircuitReduction;
                    statistics.StatesShortCircuited++;

                    if (gotoRow != null)
                    {
                        statistics.StatesWithGotos++;
                    }
                }
                else
                {
                    fragments.Add(transitionRow.Fragment);

                    if (transitionRow.HasReduction && transitionRow.HasShift)
                    {
                        statistics.StatesWithSRConflicts++;
                    }

                    if (gotoRow != null)
                    {
                        statistics.StatesWithGotos++;
                    }
                    else if (!transitionRow.HasReduction || !transitionRow.HasShift)
                    {
                        statistics.StatesOther++;
                    }
                }

                if (gotoRow != null)
                {
                    fragments.Add(gotoRow);
                    statistics.NonTerminalColumns = Math.Max(statistics.NonTerminalColumns, gotoRow.Count);
                    lastGotoStateIndex            = data.StateMap[state] + 1;
                }
            }

            var combined = TableFragment.Combine(fragments);

            var offsetSectionLen = graph.States.Count + lastGotoStateIndex;

            Array.Resize(ref actionsList, offsetSectionLen + combined.Count);

            for (var i = 0; i < graph.States.Count << 1; i++)
            {
                var offset = combined.GetOffset(i);

                if (offset.HasValue)
                {
                    actionsList[i] = offset.Value + offsetSectionLen;
                }
            }

            combined.CopyTo(actionsList, offsetSectionLen);

            var actionsBlob = CompressedBlob.Compress(config.Manager.TableCompression, ElementSizeStrategy.Get(config.Manager.ElementSize), actionsList);

            statistics.ActionsRunTime       = actionsList.Length;
            statistics.ActionsAssemblyBytes = actionsBlob.Bytes;
            statistics.GotoOffsetsLen       = lastGotoStateIndex;
            return(actionsBlob);
        }
        void CheckIntegrity(int[][] table, int expectedLen)
        {
            var fragments = new List <TableFragment>();

            for (var s = 0; s < table.Length; s++)
            {
                var row = table[s];
                if (row == null)
                {
                    continue;
                }

                fragments.Add(new TableFragment(row, s));
            }

            var compound = TableFragment.Combine(fragments);

            var builder = new StringBuilder();

            for (var s = 0; s < table.Length; s++)
            {
                var offset = compound.GetOffset(s);
                var row    = table[s];

                if (row == null)
                {
                    if (offset >= 0)
                    {
                        builder.Append("row[");
                        builder.Append(s);
                        builder.Append("] should be null but was ");
                        builder.Append(offset);
                        builder.AppendLine();
                    }
                }
                else if (!offset.HasValue)
                {
                    builder.Append("row[");
                    builder.Append(s);
                    builder.Append("] should be non-null but was null");
                    builder.AppendLine();
                }
                else
                {
                    for (var c = 0; c < row.Length; c++)
                    {
                        var expected = row[c];
                        var actual   = compound[offset.Value + c];

                        if (expected != actual)
                        {
                            builder.Append("row[");
                            builder.Append(s);
                            builder.Append("][");
                            builder.Append(c);
                            builder.Append("] should be ");
                            builder.Append(expected);
                            builder.Append(" but was ");
                            builder.Append(actual);
                            builder.AppendLine();
                        }
                    }
                }
            }

            Assert.That(builder.ToString(), Is.EqualTo(string.Empty));
            Assert.That(compound.Count, Is.EqualTo(expectedLen));
        }