Merge "Kill the StringBuilderPool."
This commit is contained in:
commit
b8753eb31c
3 changed files with 11 additions and 117 deletions
|
@ -1,70 +0,0 @@
|
|||
/*
|
||||
* 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 static final boolean DEBUG = false;
|
||||
private StringBuilderPool() {}
|
||||
// TODO: Make this a normal array with a size of 20, or a ConcurrentQueue
|
||||
private final List<StringBuilder> mPool =
|
||||
Collections.synchronizedList(new ArrayList<StringBuilder>());
|
||||
|
||||
public static StringBuilder getStringBuilder(final int initialSize) {
|
||||
// TODO: although the pool is synchronized, the following is not thread-safe.
|
||||
// Two threads entering this at the same time could take the same size of the pool and the
|
||||
// second to attempt removing this index from the pool would crash with an
|
||||
// IndexOutOfBoundsException.
|
||||
// At the moment this pool is only used in Suggest.java and only in one thread so it's
|
||||
// okay. The simplest thing to do here is probably to replace the ArrayList with a
|
||||
// ConcurrentQueue.
|
||||
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) {
|
||||
if (DEBUG) {
|
||||
final int gid = garbage.hashCode();
|
||||
for (final StringBuilder q : sInstance.mPool) {
|
||||
if (gid == q.hashCode()) throw new RuntimeException("Duplicate id " + gid);
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
|
@ -142,7 +142,7 @@ public class StringUtils {
|
|||
for (int j = 0; j < i; j++) {
|
||||
CharSequence previous = suggestions.get(j);
|
||||
if (TextUtils.equals(cur, previous)) {
|
||||
removeFromSuggestions(suggestions, i);
|
||||
suggestions.remove(i);
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
|
@ -151,14 +151,6 @@ public class StringUtils {
|
|||
}
|
||||
}
|
||||
|
||||
private static void removeFromSuggestions(final ArrayList<CharSequence> suggestions,
|
||||
final int index) {
|
||||
final CharSequence garbage = suggestions.remove(index);
|
||||
if (garbage instanceof StringBuilder) {
|
||||
StringBuilderPool.recycle((StringBuilder)garbage);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getFullDisplayName(Locale locale, boolean returnsNameInThisLocale) {
|
||||
if (returnsNameInThisLocale) {
|
||||
return toTitleCase(SubtypeLocale.getFullDisplayName(locale), locale);
|
||||
|
|
|
@ -98,7 +98,7 @@ public class Suggest implements Dictionary.WordCallback {
|
|||
private int[] mBigramScores = new int[PREF_MAX_BIGRAMS];
|
||||
|
||||
private ArrayList<CharSequence> mSuggestions = new ArrayList<CharSequence>();
|
||||
ArrayList<CharSequence> mBigramSuggestions = new ArrayList<CharSequence>();
|
||||
private ArrayList<CharSequence> mBigramSuggestions = new ArrayList<CharSequence>();
|
||||
private CharSequence mConsideredWord;
|
||||
|
||||
// TODO: Remove these member variables by passing more context to addWord() callback method
|
||||
|
@ -122,7 +122,6 @@ public class Suggest implements Dictionary.WordCallback {
|
|||
private void initWhitelistAndAutocorrectAndPool(final Context context, final Locale locale) {
|
||||
mWhiteListDictionary = new WhitelistDictionary(context, locale);
|
||||
addOrReplaceDictionary(mUnigramDictionaries, DICT_KEY_WHITELIST, mWhiteListDictionary);
|
||||
StringBuilderPool.ensureCapacity(mPrefMaxSuggestions, getApproxMaxWordLength());
|
||||
}
|
||||
|
||||
private void initAsynchronously(final Context context, final int dictionaryResId,
|
||||
|
@ -229,14 +228,13 @@ public class Suggest implements Dictionary.WordCallback {
|
|||
mPrefMaxSuggestions = maxSuggestions;
|
||||
mScores = new int[mPrefMaxSuggestions];
|
||||
mBigramScores = new int[PREF_MAX_BIGRAMS];
|
||||
collectGarbage(mSuggestions, mPrefMaxSuggestions);
|
||||
StringBuilderPool.ensureCapacity(mPrefMaxSuggestions, getApproxMaxWordLength());
|
||||
mSuggestions = new ArrayList<CharSequence>(mPrefMaxSuggestions);
|
||||
}
|
||||
|
||||
private CharSequence capitalizeWord(boolean all, boolean first, CharSequence word) {
|
||||
if (TextUtils.isEmpty(word) || !(all || first)) return word;
|
||||
final int wordLength = word.length();
|
||||
final StringBuilder sb = StringBuilderPool.getStringBuilder(getApproxMaxWordLength());
|
||||
final StringBuilder sb = new StringBuilder(getApproxMaxWordLength());
|
||||
// TODO: Must pay attention to locale when changing case.
|
||||
if (all) {
|
||||
sb.append(word.toString().toUpperCase());
|
||||
|
@ -250,12 +248,7 @@ public class Suggest implements Dictionary.WordCallback {
|
|||
}
|
||||
|
||||
protected void addBigramToSuggestions(CharSequence bigram) {
|
||||
// TODO: Try to be a little more shrewd with resource allocation.
|
||||
// At the moment we copy this object because the StringBuilders are pooled (see
|
||||
// StringBuilderPool.java) and when we are finished using mSuggestions and
|
||||
// mBigramSuggestions we will take everything from both and insert them back in the
|
||||
// pool, so we can't allow the same object to be in both lists at the same time.
|
||||
final StringBuilder sb = StringBuilderPool.getStringBuilder(getApproxMaxWordLength());
|
||||
final StringBuilder sb = new StringBuilder(getApproxMaxWordLength());
|
||||
sb.append(bigram);
|
||||
mSuggestions.add(sb);
|
||||
}
|
||||
|
@ -266,7 +259,7 @@ public class Suggest implements Dictionary.WordCallback {
|
|||
mIsFirstCharCapitalized = false;
|
||||
mIsAllUpperCase = false;
|
||||
mTrailingSingleQuotesCount = 0;
|
||||
collectGarbage(mSuggestions, mPrefMaxSuggestions);
|
||||
mSuggestions = new ArrayList<CharSequence>(mPrefMaxSuggestions);
|
||||
Arrays.fill(mScores, 0);
|
||||
|
||||
// Treating USER_TYPED as UNIGRAM suggestion for logging now.
|
||||
|
@ -274,7 +267,7 @@ public class Suggest implements Dictionary.WordCallback {
|
|||
mConsideredWord = "";
|
||||
|
||||
Arrays.fill(mBigramScores, 0);
|
||||
collectGarbage(mBigramSuggestions, PREF_MAX_BIGRAMS);
|
||||
mBigramSuggestions = new ArrayList<CharSequence>(PREF_MAX_BIGRAMS);
|
||||
|
||||
CharSequence lowerPrevWord = prevWordForBigram.toString().toLowerCase();
|
||||
if (mMainDict != null && mMainDict.isValidWord(lowerPrevWord)) {
|
||||
|
@ -305,7 +298,7 @@ public class Suggest implements Dictionary.WordCallback {
|
|||
mIsFirstCharCapitalized = wordComposer.isFirstCharCapitalized();
|
||||
mIsAllUpperCase = wordComposer.isAllUpperCase();
|
||||
mTrailingSingleQuotesCount = wordComposer.trailingSingleQuotesCount();
|
||||
collectGarbage(mSuggestions, mPrefMaxSuggestions);
|
||||
mSuggestions = new ArrayList<CharSequence>(mPrefMaxSuggestions);
|
||||
Arrays.fill(mScores, 0);
|
||||
|
||||
final String typedWord = wordComposer.getTypedWord();
|
||||
|
@ -328,7 +321,7 @@ public class Suggest implements Dictionary.WordCallback {
|
|||
if (wordComposer.size() <= 1 && (correctionMode == CORRECTION_FULL_BIGRAM)) {
|
||||
// At first character typed, search only the bigrams
|
||||
Arrays.fill(mBigramScores, 0);
|
||||
collectGarbage(mBigramSuggestions, PREF_MAX_BIGRAMS);
|
||||
mBigramSuggestions = new ArrayList<CharSequence>(PREF_MAX_BIGRAMS);
|
||||
|
||||
if (!TextUtils.isEmpty(prevWordForBigram)) {
|
||||
CharSequence lowerPrevWord = prevWordForBigram.toString().toLowerCase();
|
||||
|
@ -542,7 +535,7 @@ public class Suggest implements Dictionary.WordCallback {
|
|||
|
||||
System.arraycopy(sortedScores, pos, sortedScores, pos + 1, prefMaxSuggestions - pos - 1);
|
||||
sortedScores[pos] = score;
|
||||
final StringBuilder sb = StringBuilderPool.getStringBuilder(getApproxMaxWordLength());
|
||||
final StringBuilder sb = new StringBuilder(getApproxMaxWordLength());
|
||||
// TODO: Must pay attention to locale when changing case.
|
||||
if (mIsAllUpperCase) {
|
||||
sb.append(new String(word, offset, length).toUpperCase());
|
||||
|
@ -559,10 +552,7 @@ public class Suggest implements Dictionary.WordCallback {
|
|||
}
|
||||
suggestions.add(pos, sb);
|
||||
if (suggestions.size() > prefMaxSuggestions) {
|
||||
final CharSequence garbage = suggestions.remove(prefMaxSuggestions);
|
||||
if (garbage instanceof StringBuilder) {
|
||||
StringBuilderPool.recycle((StringBuilder)garbage);
|
||||
}
|
||||
suggestions.remove(prefMaxSuggestions);
|
||||
} else {
|
||||
LatinImeLogger.onAddSuggestedWord(sb.toString(), dicTypeId, dataTypeForLog);
|
||||
}
|
||||
|
@ -589,24 +579,6 @@ public class Suggest implements Dictionary.WordCallback {
|
|||
return -1;
|
||||
}
|
||||
|
||||
private static void collectGarbage(ArrayList<CharSequence> suggestions,
|
||||
int prefMaxSuggestions) {
|
||||
int poolSize = StringBuilderPool.getSize();
|
||||
int garbageSize = suggestions.size();
|
||||
while (poolSize < prefMaxSuggestions && garbageSize > 0) {
|
||||
final CharSequence garbage = suggestions.get(garbageSize - 1);
|
||||
if (garbage instanceof StringBuilder) {
|
||||
StringBuilderPool.recycle((StringBuilder)garbage);
|
||||
poolSize++;
|
||||
}
|
||||
garbageSize--;
|
||||
}
|
||||
if (poolSize == prefMaxSuggestions + 1) {
|
||||
Log.w("Suggest", "String pool got too big: " + poolSize);
|
||||
}
|
||||
suggestions.clear();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
final Set<Dictionary> dictionaries = new HashSet<Dictionary>();
|
||||
dictionaries.addAll(mUnigramDictionaries.values());
|
||||
|
|
Loading…
Reference in a new issue