NgramContext.java revision bbd6a26be025bc419e342e32d86629c4ebd68dd8
183c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi/*
283c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi * Copyright (C) 2014 The Android Open Source Project
383c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi *
483c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi * Licensed under the Apache License, Version 2.0 (the "License");
583c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi * you may not use this file except in compliance with the License.
683c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi * You may obtain a copy of the License at
783c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi *
883c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi *      http://www.apache.org/licenses/LICENSE-2.0
983c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi *
1083c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi * Unless required by applicable law or agreed to in writing, software
1183c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi * distributed under the License is distributed on an "AS IS" BASIS,
1283c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1383c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi * See the License for the specific language governing permissions and
1483c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi * limitations under the License.
1583c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi */
1683c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi
1783c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagipackage com.android.inputmethod.latin;
1883c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi
1986f36003fd4397143bd37938dda029e5707634afYohei Yukawaimport android.text.TextUtils;
20e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi
21bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagiimport com.android.inputmethod.annotations.UsedForTesting;
22e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagiimport com.android.inputmethod.latin.utils.StringUtils;
23e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi
2486f36003fd4397143bd37938dda029e5707634afYohei Yukawaimport java.util.Arrays;
2586f36003fd4397143bd37938dda029e5707634afYohei Yukawa
26a790c5b68324da41428aeb68594d43ca5632f66dKeisuke Kuroyanagi/**
27a790c5b68324da41428aeb68594d43ca5632f66dKeisuke Kuroyanagi * Class to represent information of previous words. This class is used to add n-gram entries
28a790c5b68324da41428aeb68594d43ca5632f66dKeisuke Kuroyanagi * into binary dictionaries, to get predictions, and to get suggestions.
29a790c5b68324da41428aeb68594d43ca5632f66dKeisuke Kuroyanagi */
3083c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagipublic class PrevWordsInfo {
31e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    public static final PrevWordsInfo EMPTY_PREV_WORDS_INFO =
32e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            new PrevWordsInfo(WordInfo.EMPTY_WORD_INFO);
331c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi    public static final PrevWordsInfo BEGINNING_OF_SENTENCE =
341c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi            new PrevWordsInfo(WordInfo.BEGINNING_OF_SENTENCE);
351adca93381d261a6070be2721dbf8b8abafbfe01Keisuke Kuroyanagi
36e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    /**
37e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi     * Word information used to represent previous words information.
38e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi     */
39e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    public static class WordInfo {
40e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        public static final WordInfo EMPTY_WORD_INFO = new WordInfo(null);
41e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        public static final WordInfo BEGINNING_OF_SENTENCE = new WordInfo();
42e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi
4386f36003fd4397143bd37938dda029e5707634afYohei Yukawa        // This is an empty char sequence when mIsBeginningOfSentence is true.
4486f36003fd4397143bd37938dda029e5707634afYohei Yukawa        public final CharSequence mWord;
45e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        // TODO: Have sentence separator.
46e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        // Whether the current context is beginning of sentence or not. This is true when composing
47e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        // at the beginning of an input field or composing a word after a sentence separator.
48e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        public final boolean mIsBeginningOfSentence;
49e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi
50e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        // Beginning of sentence.
51e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        public WordInfo() {
52e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            mWord = "";
53e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            mIsBeginningOfSentence = true;
54e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        }
55e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi
5686f36003fd4397143bd37938dda029e5707634afYohei Yukawa        public WordInfo(final CharSequence word) {
57e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            mWord = word;
58e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            mIsBeginningOfSentence = false;
59e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        }
60e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi
61e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        public boolean isValid() {
62e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            return mWord != null;
63e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        }
641c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi
651c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi        @Override
661c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi        public int hashCode() {
671c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi            return Arrays.hashCode(new Object[] { mWord, mIsBeginningOfSentence } );
681c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi        }
691c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi
701c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi        @Override
711c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi        public boolean equals(Object o) {
721c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi            if (this == o) return true;
731c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi            if (!(o instanceof WordInfo)) return false;
741c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi            final WordInfo wordInfo = (WordInfo)o;
751c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi            if (mWord == null || wordInfo.mWord == null) {
761c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi                return mWord == wordInfo.mWord
771c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi                        && mIsBeginningOfSentence == wordInfo.mIsBeginningOfSentence;
781c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi            }
7986f36003fd4397143bd37938dda029e5707634afYohei Yukawa            return TextUtils.equals(mWord, wordInfo.mWord)
801c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi                    && mIsBeginningOfSentence == wordInfo.mIsBeginningOfSentence;
811c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi        }
82e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    }
8383c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi
84e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    // The words immediately before the considered word. EMPTY_WORD_INFO element means we don't
85e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    // have any context for that previous word including the "beginning of sentence context" - we
86e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    // just don't know what to predict using the information. An example of that is after a comma.
87e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    // For simplicity of implementation, elements may also be EMPTY_WORD_INFO transiently after the
88e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    // WordComposer was reset and before starting a new composing word, but we should never be
89e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    // calling getSuggetions* in this situation.
90bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi    private final WordInfo[] mPrevWordsInfo;
91bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi    private final int mPrevWordsCount;
9217f326b7458c2bde2569e283a96e703755485328Keisuke Kuroyanagi
93e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    // Construct from the previous word information.
94bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi    public PrevWordsInfo(final WordInfo... prevWordsInfo) {
95bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        mPrevWordsInfo = prevWordsInfo;
96bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        mPrevWordsCount = prevWordsInfo.length;
97e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    }
98e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi
99bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi    // Construct from WordInfo array and size. The caller shouldn't change prevWordsInfo after
100bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi    // calling this method.
101bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi    private PrevWordsInfo(final PrevWordsInfo prevWordsInfo, final int prevWordsCount) {
102bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        if (prevWordsInfo.mPrevWordsCount < prevWordsCount) {
103bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi            throw new IndexOutOfBoundsException("prevWordsInfo.mPrevWordsCount ("
104bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi                    + prevWordsInfo.mPrevWordsCount + ") is smaller than prevWordsCount ("
105bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi                    + prevWordsCount + ")");
106bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        }
107bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        mPrevWordsInfo = prevWordsInfo.mPrevWordsInfo;
108bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        mPrevWordsCount = prevWordsCount;
109e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    }
110e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi
111e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    // Create next prevWordsInfo using current prevWordsInfo.
112e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    public PrevWordsInfo getNextPrevWordsInfo(final WordInfo wordInfo) {
1134466464c24d6c6523f170f56b7e65e43ceb699e2Keisuke Kuroyanagi        final int nextPrevWordCount = Math.min(Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM,
114bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi                mPrevWordsCount + 1);
1154466464c24d6c6523f170f56b7e65e43ceb699e2Keisuke Kuroyanagi        final WordInfo[] prevWordsInfo = new WordInfo[nextPrevWordCount];
116e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        prevWordsInfo[0] = wordInfo;
117bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        System.arraycopy(mPrevWordsInfo, 0, prevWordsInfo, 1, nextPrevWordCount - 1);
118e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        return new PrevWordsInfo(prevWordsInfo);
11983c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi    }
1201adca93381d261a6070be2721dbf8b8abafbfe01Keisuke Kuroyanagi
1211adca93381d261a6070be2721dbf8b8abafbfe01Keisuke Kuroyanagi    public boolean isValid() {
122bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        return mPrevWordsCount > 0 && mPrevWordsInfo[0].isValid();
123bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi    }
124bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi
125bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi    public boolean isBeginningOfSentenceContext() {
126bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        return mPrevWordsCount > 0 && mPrevWordsInfo[0].mIsBeginningOfSentence;
127bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi    }
128bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi
129bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi    // n is 1-indexed.
130bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi    // TODO: Remove
131bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi    public CharSequence getNthPrevWord(final int n) {
132bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        if (n <= 0 || n > mPrevWordsCount) {
133bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi            return null;
134bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        }
135bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        return mPrevWordsInfo[n - 1].mWord;
136bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi    }
137bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi
138bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi    // n is 1-indexed.
139bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi    @UsedForTesting
140bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi    public boolean isNthPrevWordBeginningOfSontence(final int n) {
141bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        if (n <= 0 || n > mPrevWordsCount) {
142bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi            return false;
143bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        }
144bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        return mPrevWordsInfo[n - 1].mIsBeginningOfSentence;
145e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    }
146e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi
147e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    public void outputToArray(final int[][] codePointArrays,
148e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            final boolean[] isBeginningOfSentenceArray) {
149bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        for (int i = 0; i < mPrevWordsCount; i++) {
150e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            final WordInfo wordInfo = mPrevWordsInfo[i];
151e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            if (wordInfo == null || !wordInfo.isValid()) {
152e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi                codePointArrays[i] = new int[0];
153e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi                isBeginningOfSentenceArray[i] = false;
154e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi                continue;
155e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            }
156e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            codePointArrays[i] = StringUtils.toCodePointArray(wordInfo.mWord);
157e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            isBeginningOfSentenceArray[i] = wordInfo.mIsBeginningOfSentence;
158e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        }
1591adca93381d261a6070be2721dbf8b8abafbfe01Keisuke Kuroyanagi    }
160dfca51726e9dc9a35f462dee39331823eafa07c9Keisuke Kuroyanagi
161ddfaeff544c77b1d42857ebf34ca2545e8868e13Keisuke Kuroyanagi    public PrevWordsInfo getTrimmedPrevWordsInfo(final int maxPrevWordCount) {
162bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        final int newSize = Math.min(maxPrevWordCount, mPrevWordsCount);
163bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        return new PrevWordsInfo(this /* prevWordsInfo */, newSize);
164ddfaeff544c77b1d42857ebf34ca2545e8868e13Keisuke Kuroyanagi    }
165ddfaeff544c77b1d42857ebf34ca2545e8868e13Keisuke Kuroyanagi
1664466464c24d6c6523f170f56b7e65e43ceb699e2Keisuke Kuroyanagi    public int getPrevWordCount() {
167bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        return mPrevWordsCount;
1684466464c24d6c6523f170f56b7e65e43ceb699e2Keisuke Kuroyanagi    }
1694466464c24d6c6523f170f56b7e65e43ceb699e2Keisuke Kuroyanagi
170dfca51726e9dc9a35f462dee39331823eafa07c9Keisuke Kuroyanagi    @Override
1711c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi    public int hashCode() {
172845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi        // Just for having equals().
173845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi        return mPrevWordsInfo[0].hashCode();
1741c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi    }
1751c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi
1761c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi    @Override
1771c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi    public boolean equals(Object o) {
1781c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi        if (this == o) return true;
1791c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi        if (!(o instanceof PrevWordsInfo)) return false;
1801c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi        final PrevWordsInfo prevWordsInfo = (PrevWordsInfo)o;
181845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi
182bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        final int minLength = Math.min(mPrevWordsCount, prevWordsInfo.mPrevWordsCount);
183845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi        for (int i = 0; i < minLength; i++) {
184845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi            if (!mPrevWordsInfo[i].equals(prevWordsInfo.mPrevWordsInfo[i])) {
185845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi                return false;
186845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi            }
187845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi        }
188bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        final WordInfo[] longerWordsInfo;
189bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        final int longerWordsInfoCount;
190bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        if (mPrevWordsCount > prevWordsInfo.mPrevWordsCount) {
191bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi            longerWordsInfo = mPrevWordsInfo;
192bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi            longerWordsInfoCount = mPrevWordsCount;
193bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        } else {
194bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi            longerWordsInfo = prevWordsInfo.mPrevWordsInfo;
195bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi            longerWordsInfoCount = prevWordsInfo.mPrevWordsCount;
196bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        }
197bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        for (int i = minLength; i < longerWordsInfoCount; i++) {
198845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi            if (longerWordsInfo[i] != null
199845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi                    && !WordInfo.EMPTY_WORD_INFO.equals(longerWordsInfo[i])) {
200845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi                return false;
201845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi            }
202845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi        }
203845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi        return true;
2041c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi    }
2051c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi
2061c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi    @Override
207dfca51726e9dc9a35f462dee39331823eafa07c9Keisuke Kuroyanagi    public String toString() {
208e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        final StringBuffer builder = new StringBuffer();
209bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        for (int i = 0; i < mPrevWordsCount; i++) {
210e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            final WordInfo wordInfo = mPrevWordsInfo[i];
211e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            builder.append("PrevWord[");
212e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            builder.append(i);
213e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            builder.append("]: ");
214845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi            if (wordInfo == null) {
215845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi                builder.append("null. ");
216845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi                continue;
217845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi            }
218845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi            if (!wordInfo.isValid()) {
219e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi                builder.append("Empty. ");
220e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi                continue;
221e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            }
222e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            builder.append(wordInfo.mWord);
223e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            builder.append(", isBeginningOfSentence: ");
224e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            builder.append(wordInfo.mIsBeginningOfSentence);
225e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            builder.append(". ");
226e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        }
227e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        return builder.toString();
228dfca51726e9dc9a35f462dee39331823eafa07c9Keisuke Kuroyanagi    }
22983c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi}
230