Make the string builder pool in Suggest a singleton.

This is internal refactoring, done as preliminary work to fix
Bug: 5175740

Change-Id: I21bd4c001c27e7b925ddb87a152105b4dcab320a
main
Jean Chalard 2011-08-17 17:32:25 +09:00
parent 5ba5ff9b80
commit 4e01afc520
2 changed files with 70 additions and 40 deletions

View File

@ -0,0 +1,56 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.android.inputmethod.latin;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* A pool of string builders to be used from anywhere.
*/
public class StringBuilderPool {
// Singleton
private static final StringBuilderPool sInstance = new StringBuilderPool();
private StringBuilderPool() {}
// TODO: Make this a normal array with a size of 20
private final List<StringBuilder> mPool =
Collections.synchronizedList(new ArrayList<StringBuilder>());
public static StringBuilder getStringBuilder(final int initialSize) {
final int poolSize = sInstance.mPool.size();
final StringBuilder sb = poolSize > 0 ? (StringBuilder) sInstance.mPool.remove(poolSize - 1)
: new StringBuilder(initialSize);
sb.setLength(0);
return sb;
}
public static void recycle(final StringBuilder garbage) {
sInstance.mPool.add(garbage);
}
public static void ensureCapacity(final int capacity, final int initialSize) {
for (int i = sInstance.mPool.size(); i < capacity; ++i) {
final StringBuilder sb = new StringBuilder(initialSize);
sInstance.mPool.add(sb);
}
}
public static int getSize() {
return sInstance.mPool.size();
}
}

View File

@ -105,9 +105,6 @@ public class Suggest implements Dictionary.WordCallback {
private ArrayList<CharSequence> mSuggestions = new ArrayList<CharSequence>();
ArrayList<CharSequence> mBigramSuggestions = new ArrayList<CharSequence>();
// TODO: maybe this should be synchronized, it's quite scary as it is.
// TODO: if it becomes synchronized, also move initPool in the thread in initAsynchronously
private ArrayList<CharSequence> mStringPool = new ArrayList<CharSequence>();
private CharSequence mTypedWord;
// TODO: Remove these member variables by passing more context to addWord() callback method
@ -130,7 +127,7 @@ public class Suggest implements Dictionary.WordCallback {
mWhiteListDictionary = WhitelistDictionary.init(context);
addOrReplaceDictionary(mUnigramDictionaries, DICT_KEY_WHITELIST, mWhiteListDictionary);
mAutoCorrection = new AutoCorrection();
initPool();
StringBuilderPool.ensureCapacity(mPrefMaxSuggestions, getApproxMaxWordLength());
}
private void initAsynchronously(final Context context, final int dictionaryResId,
@ -138,7 +135,7 @@ public class Suggest implements Dictionary.WordCallback {
resetMainDict(context, dictionaryResId, locale);
// TODO: read the whitelist and init the pool asynchronously too.
// initPool should be done asynchronously but the pool is not thread-safe at the moment.
// initPool should be done asynchronously now that the pool is thread-safe.
initWhitelistAndAutocorrectAndPool(context);
}
@ -173,12 +170,6 @@ public class Suggest implements Dictionary.WordCallback {
}.start();
}
private void initPool() {
for (int i = 0; i < mPrefMaxSuggestions; i++) {
StringBuilder sb = new StringBuilder(getApproxMaxWordLength());
mStringPool.add(sb);
}
}
public void setQuickFixesEnabled(boolean enabled) {
mQuickFixesEnabled = enabled;
@ -259,10 +250,7 @@ public class Suggest implements Dictionary.WordCallback {
mScores = new int[mPrefMaxSuggestions];
mBigramScores = new int[PREF_MAX_BIGRAMS];
collectGarbage(mSuggestions, mPrefMaxSuggestions);
while (mStringPool.size() < mPrefMaxSuggestions) {
StringBuilder sb = new StringBuilder(getApproxMaxWordLength());
mStringPool.add(sb);
}
StringBuilderPool.ensureCapacity(mPrefMaxSuggestions, getApproxMaxWordLength());
}
/**
@ -282,11 +270,7 @@ public class Suggest implements Dictionary.WordCallback {
private CharSequence capitalizeWord(boolean all, boolean first, CharSequence word) {
if (TextUtils.isEmpty(word) || !(all || first)) return word;
final int wordLength = word.length();
final int poolSize = mStringPool.size();
final StringBuilder sb =
poolSize > 0 ? (StringBuilder) mStringPool.remove(poolSize - 1)
: new StringBuilder(getApproxMaxWordLength());
sb.setLength(0);
final StringBuilder sb = StringBuilderPool.getStringBuilder(getApproxMaxWordLength());
// TODO: Must pay attention to locale when changing case.
if (all) {
sb.append(word.toString().toUpperCase());
@ -300,13 +284,7 @@ public class Suggest implements Dictionary.WordCallback {
}
protected void addBigramToSuggestions(CharSequence bigram) {
final int poolSize = mStringPool.size();
final StringBuilder sb = poolSize > 0 ?
(StringBuilder) mStringPool.remove(poolSize - 1)
: new StringBuilder(getApproxMaxWordLength());
sb.setLength(0);
sb.append(bigram);
mSuggestions.add(sb);
mSuggestions.add(bigram);
}
// TODO: cleanup dictionaries looking up and suggestions building with SuggestedWords.Builder
@ -475,9 +453,8 @@ public class Suggest implements Dictionary.WordCallback {
private static void removeFromSuggestions(final ArrayList<CharSequence> suggestions,
final int index) {
final CharSequence garbage = suggestions.remove(index);
if (garbage != null && garbage instanceof StringBuilder) {
// TODO: rebase this over the static string builder pool
// mStringPool.add(garbage);
if (garbage instanceof StringBuilder) {
StringBuilderPool.recycle((StringBuilder)garbage);
}
}
@ -555,10 +532,7 @@ public class Suggest implements Dictionary.WordCallback {
System.arraycopy(sortedScores, pos, sortedScores, pos + 1, prefMaxSuggestions - pos - 1);
sortedScores[pos] = score;
int poolSize = mStringPool.size();
StringBuilder sb = poolSize > 0 ? (StringBuilder) mStringPool.remove(poolSize - 1)
: new StringBuilder(getApproxMaxWordLength());
sb.setLength(0);
final StringBuilder sb = StringBuilderPool.getStringBuilder(getApproxMaxWordLength());
// TODO: Must pay attention to locale when changing case.
if (mIsAllUpperCase) {
sb.append(new String(word, offset, length).toUpperCase());
@ -572,9 +546,9 @@ public class Suggest implements Dictionary.WordCallback {
}
suggestions.add(pos, sb);
if (suggestions.size() > prefMaxSuggestions) {
CharSequence garbage = suggestions.remove(prefMaxSuggestions);
final CharSequence garbage = suggestions.remove(prefMaxSuggestions);
if (garbage instanceof StringBuilder) {
mStringPool.add(garbage);
StringBuilderPool.recycle((StringBuilder)garbage);
}
} else {
LatinImeLogger.onAddSuggestedWord(sb.toString(), dicTypeId, dataTypeForLog);
@ -603,12 +577,12 @@ public class Suggest implements Dictionary.WordCallback {
}
private void collectGarbage(ArrayList<CharSequence> suggestions, int prefMaxSuggestions) {
int poolSize = mStringPool.size();
int poolSize = StringBuilderPool.getSize();
int garbageSize = suggestions.size();
while (poolSize < prefMaxSuggestions && garbageSize > 0) {
CharSequence garbage = suggestions.get(garbageSize - 1);
if (garbage != null && garbage instanceof StringBuilder) {
mStringPool.add(garbage);
final CharSequence garbage = suggestions.get(garbageSize - 1);
if (garbage instanceof StringBuilder) {
StringBuilderPool.recycle((StringBuilder)garbage);
poolSize++;
}
garbageSize--;