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 State digit_state = stateNoBinary .latchAndAppend(MODE_DIGIT, 16 - pairCode) // period or comma in DIGIT .latchAndAppend(MODE_DIGIT, 1); // space in DIGIT result.Add(digit_state); } 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); } }
/// <summary> /// Returns true if "this" state is better (or equal) to be in than "that" /// state under all possible circumstances. /// </summary> public bool isBetterThanOrEqualTo(State other) { int mySize = this.bitCount + (HighLevelEncoder.LATCH_TABLE[this.mode][other.mode] >> 16); if (other.binaryShiftByteCount > 0 && (this.binaryShiftByteCount == 0 || this.binaryShiftByteCount > other.binaryShiftByteCount)) { mySize += 10; // Cost of entering Binary Shift mode. } return mySize <= other.bitCount; }
// 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. State latch_state = stateNoBinary.latchAndAppend(mode, charInMode); result.Add(latch_state); } // 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. State shift_state = stateNoBinary.shiftAndAppend(mode, charInMode); result.Add(shift_state); } } } 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. State binaryState = state.addBinaryShiftChar(index); result.Add(binaryState); } }
/// <summary> /// Create a new state representing this state, but an additional character /// output in Binary Shift mode. /// </summary> public State addBinaryShiftChar(int index) { Token token = this.token; int mode = this.mode; int bitCount = this.bitCount; if (this.mode == HighLevelEncoder.MODE_PUNCT || this.mode == HighLevelEncoder.MODE_DIGIT) { //assert binaryShiftByteCount == 0; int latch = HighLevelEncoder.LATCH_TABLE[mode][HighLevelEncoder.MODE_UPPER]; token = token.add(latch & 0xFFFF, latch >> 16); bitCount += latch >> 16; mode = HighLevelEncoder.MODE_UPPER; } int deltaBitCount = (binaryShiftByteCount == 0 || binaryShiftByteCount == 31) ? 18 : (binaryShiftByteCount == 62) ? 9 : 8; State result = new State(token, mode, binaryShiftByteCount + 1, bitCount + deltaBitCount); if (result.binaryShiftByteCount == 2047 + 31) { // The string is as long as it's allowed to be. We should end it. result = result.endBinaryShift(index + 1); } return result; }