private static void updateStateForPair(State state, int index, int pairCode, ICollection <State> result)
        {
            State stateNoBinary = state.endBinaryShift(index);

            // Possibility 1.  Latch to MODE_PUNCT, and then append this code
            result.Add(stateNoBinary.latchAndAppend(MODE_PUNCT, pairCode));
            if (state.Mode != MODE_PUNCT)
            {
                // Possibility 2.  Shift to MODE_PUNCT, and then append this code.
                // Every state except MODE_PUNCT (handled above) can shift
                result.Add(stateNoBinary.shiftAndAppend(MODE_PUNCT, pairCode));
            }
            if (pairCode == 3 || pairCode == 4)
            {
                // both characters are in DIGITS.  Sometimes better to just add two digits
                var digitState = stateNoBinary
                                 .latchAndAppend(MODE_DIGIT, 16 - pairCode) // period or comma in DIGIT
                                 .latchAndAppend(MODE_DIGIT, 1);            // space in DIGIT
                result.Add(digitState);
            }
            if (state.BinaryShiftByteCount > 0)
            {
                // It only makes sense to do the characters as binary if we're already
                // in binary mode.
                State binaryState = state.addBinaryShiftChar(index).addBinaryShiftChar(index + 1);
                result.Add(binaryState);
            }
        }
        // Return a set of states that represent the possible ways of updating this
        // state for the next character.  The resulting set of states are added to
        // the "result" list.
        private void updateStateForChar(State state, int index, ICollection <State> result)
        {
            char  ch = (char)(text[index] & 0xFF);
            bool  charInCurrentTable = CHAR_MAP[state.Mode][ch] > 0;
            State stateNoBinary      = null;

            for (int mode = 0; mode <= MODE_PUNCT; mode++)
            {
                int charInMode = CHAR_MAP[mode][ch];
                if (charInMode > 0)
                {
                    if (stateNoBinary == null)
                    {
                        // Only create stateNoBinary the first time it's required.
                        stateNoBinary = state.endBinaryShift(index);
                    }
                    // Try generating the character by latching to its mode
                    if (!charInCurrentTable || mode == state.Mode || mode == MODE_DIGIT)
                    {
                        // If the character is in the current table, we don't want to latch to
                        // any other mode except possibly digit (which uses only 4 bits).  Any
                        // other latch would be equally successful *after* this character, and
                        // so wouldn't save any bits.
                        var latchState = stateNoBinary.latchAndAppend(mode, charInMode);
                        result.Add(latchState);
                    }
                    // Try generating the character by switching to its mode.
                    if (!charInCurrentTable && SHIFT_TABLE[state.Mode][mode] >= 0)
                    {
                        // It never makes sense to temporarily shift to another mode if the
                        // character exists in the current mode.  That can never save bits.
                        var shiftState = stateNoBinary.shiftAndAppend(mode, charInMode);
                        result.Add(shiftState);
                    }
                }
            }
            if (state.BinaryShiftByteCount > 0 || CHAR_MAP[state.Mode][ch] == 0)
            {
                // It's never worthwhile to go into binary shift mode if you're not already
                // in binary shift mode, and the character exists in your current mode.
                // That can never save bits over just outputting the char in the current mode.
                var binaryState = state.addBinaryShiftChar(index);
                result.Add(binaryState);
            }
        }