Optimize KeyboardTextsTable
This change counts all occurrences of each string resource and sort those in descending order of the occurrence. Change-Id: I726402157feb0d436a54bd0a7252acd17fd711f9main
parent
8dd47029f1
commit
0fe4d00068
File diff suppressed because it is too large
Load Diff
|
@ -63,6 +63,7 @@ public final class KeyboardTextsTable {
|
|||
}
|
||||
|
||||
private static final String[] NAMES = {
|
||||
// /* index:histogram */ "name",
|
||||
/* @NAMES@ */
|
||||
};
|
||||
|
||||
|
|
|
@ -22,17 +22,22 @@ public class ArrayInitializerFormatter {
|
|||
private final PrintStream mOut;
|
||||
private final int mMaxWidth;
|
||||
private final String mIndent;
|
||||
// String resource names array; indexed by {@link #CurrentIndex} and
|
||||
// {@link #mStartIndexOfBuffer}.
|
||||
private final String[] mResourceNames;
|
||||
|
||||
private int mCurrentIndex = 0;
|
||||
private String mFixedElement;
|
||||
private String mLastElement;
|
||||
private final StringBuilder mBuffer = new StringBuilder();
|
||||
private int mBufferedLen;
|
||||
private int mBufferedIndex = Integer.MIN_VALUE;
|
||||
private int mStartIndexOfBuffer = Integer.MIN_VALUE;
|
||||
|
||||
public ArrayInitializerFormatter(final PrintStream out, final int width, final String indent) {
|
||||
public ArrayInitializerFormatter(final PrintStream out, final int width, final String indent,
|
||||
final String[] resourceNames) {
|
||||
mOut = out;
|
||||
mMaxWidth = width - indent.length();
|
||||
mIndent = indent;
|
||||
mResourceNames = resourceNames;
|
||||
}
|
||||
|
||||
public int getCurrentIndex() {
|
||||
|
@ -44,20 +49,24 @@ public class ArrayInitializerFormatter {
|
|||
return;
|
||||
}
|
||||
final int lastIndex = mCurrentIndex - 1;
|
||||
if (mBufferedIndex == lastIndex) {
|
||||
mOut.format("%s/* %d */ %s\n", mIndent, mBufferedIndex, mBuffer);
|
||||
} else if (mBufferedIndex == lastIndex - 1) {
|
||||
final String[] elements = mBuffer.toString().split(" ");
|
||||
mOut.format("%s/* %d */ %s\n"
|
||||
+ "%s/* %d */ %s\n",
|
||||
mIndent, mBufferedIndex, elements[0],
|
||||
mIndent, lastIndex, elements[1]);
|
||||
if (mStartIndexOfBuffer == lastIndex) {
|
||||
mOut.format("%s/* %s */ %s\n",
|
||||
mIndent, mResourceNames[mStartIndexOfBuffer], mBuffer);
|
||||
} else if (mStartIndexOfBuffer == lastIndex - 1) {
|
||||
final String startElement = mBuffer.toString()
|
||||
.substring(0, mBuffer.length() - mLastElement.length())
|
||||
.trim();
|
||||
mOut.format("%s/* %s */ %s\n"
|
||||
+ "%s/* %s */ %s\n",
|
||||
mIndent, mResourceNames[mStartIndexOfBuffer], startElement,
|
||||
mIndent, mResourceNames[lastIndex], mLastElement);
|
||||
} else {
|
||||
mOut.format("%s/* %d~ */\n"
|
||||
mOut.format("%s/* %s ~ */\n"
|
||||
+ "%s%s\n"
|
||||
+ "%s/* ~%d */\n", mIndent, mBufferedIndex,
|
||||
+ "%s/* ~ %s */\n",
|
||||
mIndent, mResourceNames[mStartIndexOfBuffer],
|
||||
mIndent, mBuffer,
|
||||
mIndent, lastIndex);
|
||||
mIndent, mResourceNames[lastIndex]);
|
||||
}
|
||||
mBuffer.setLength(0);
|
||||
mBufferedLen = 0;
|
||||
|
@ -66,20 +75,22 @@ public class ArrayInitializerFormatter {
|
|||
public void outCommentLines(final String lines) {
|
||||
flush();
|
||||
mOut.print(lines);
|
||||
mFixedElement = null;
|
||||
mLastElement = null;
|
||||
}
|
||||
|
||||
public void outElement(final String element) {
|
||||
if (!element.equals(mFixedElement)) {
|
||||
if (!element.equals(mLastElement)) {
|
||||
flush();
|
||||
mBufferedIndex = mCurrentIndex;
|
||||
mStartIndexOfBuffer = mCurrentIndex;
|
||||
}
|
||||
final int nextLen = mBufferedLen + " ".length() + element.length();
|
||||
if (mBufferedLen != 0 && nextLen < mMaxWidth) {
|
||||
// Element can fit in the current line.
|
||||
mBuffer.append(' ');
|
||||
mBuffer.append(element);
|
||||
mBufferedLen = nextLen;
|
||||
} else {
|
||||
// Element should be on the next line.
|
||||
if (mBufferedLen != 0) {
|
||||
mBuffer.append('\n');
|
||||
mBuffer.append(mIndent);
|
||||
|
@ -88,6 +99,6 @@ public class ArrayInitializerFormatter {
|
|||
mBufferedLen = element.length();
|
||||
}
|
||||
mCurrentIndex++;
|
||||
mFixedElement = element;
|
||||
mLastElement = element;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import java.io.LineNumberReader;
|
|||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.jar.JarFile;
|
||||
|
@ -47,8 +48,19 @@ public class MoreKeysResources {
|
|||
// Language to string resources map.
|
||||
private final HashMap<String, StringResourceMap> mResourcesMap =
|
||||
new HashMap<String, StringResourceMap>();
|
||||
// Name to id map.
|
||||
private final HashMap<String, Integer> mNameToIdMap = new HashMap<String,Integer>();
|
||||
// Sorted languages list. The language is taken from string resource directories
|
||||
// (values-<language>/) or {@link #DEFAULT_LANGUAGE_NAME} for the default string resource
|
||||
// directory (values/).
|
||||
private final ArrayList<String> mSortedLanguagesList = new ArrayList<String>();
|
||||
// Default string resources map.
|
||||
private final StringResourceMap mDefaultResourceMap;
|
||||
// Histogram of string resource names. This is used to sort {@link #mSortedResourceNames}.
|
||||
private final HashMap<String, Integer> mNameHistogram = new HashMap<String, Integer>();
|
||||
// Sorted string resource names array; Descending order of histogram count.
|
||||
// The string resource name is specified as an attribute "name" in string resource files.
|
||||
// The string resource can be accessed by specifying name "!text/<name>"
|
||||
// via {@link KeyboardTextsSet#getText(String)}.
|
||||
private final String[] mSortedResourceNames;
|
||||
|
||||
public MoreKeysResources(final JarFile jar) {
|
||||
mJar = jar;
|
||||
|
@ -65,6 +77,45 @@ public class MoreKeysResources {
|
|||
close(stream);
|
||||
}
|
||||
}
|
||||
mDefaultResourceMap = mResourcesMap.get(DEFAULT_LANGUAGE_NAME);
|
||||
mSortedLanguagesList.addAll(mResourcesMap.keySet());
|
||||
Collections.sort(mSortedLanguagesList);
|
||||
|
||||
// Initialize name histogram and names list.
|
||||
final HashMap<String, Integer> nameHistogram = mNameHistogram;
|
||||
final ArrayList<String> resourceNamesList = new ArrayList<String>();
|
||||
for (final StringResource res : mDefaultResourceMap.getResources()) {
|
||||
nameHistogram.put(res.mName, 0); // Initialize histogram value.
|
||||
resourceNamesList.add(res.mName);
|
||||
}
|
||||
// Make name histogram.
|
||||
for (final String language : mResourcesMap.keySet()) {
|
||||
final StringResourceMap resMap = mResourcesMap.get(language);
|
||||
if (resMap == mDefaultResourceMap) continue;
|
||||
for (final StringResource res : resMap.getResources()) {
|
||||
if (!mDefaultResourceMap.contains(res.mName)) {
|
||||
throw new RuntimeException(res.mName + " in " + language
|
||||
+ " doesn't have default resource");
|
||||
}
|
||||
final int histogramValue = nameHistogram.get(res.mName);
|
||||
nameHistogram.put(res.mName, histogramValue + 1);
|
||||
}
|
||||
}
|
||||
// Sort names list.
|
||||
Collections.sort(resourceNamesList, new Comparator<String>() {
|
||||
@Override
|
||||
public int compare(final String leftName, final String rightName) {
|
||||
final int leftCount = nameHistogram.get(leftName);
|
||||
final int rightCount = nameHistogram.get(rightName);
|
||||
// Descending order of histogram count.
|
||||
if (leftCount > rightCount) return -1;
|
||||
if (leftCount < rightCount) return 1;
|
||||
// TODO: Add further criteria to order the same histogram value names to be able to
|
||||
// minimize footprints of string resources arrays.
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
mSortedResourceNames = resourceNamesList.toArray(new String[resourceNamesList.size()]);
|
||||
}
|
||||
|
||||
private static String getLanguageFromResDir(final String dirName) {
|
||||
|
@ -132,19 +183,17 @@ public class MoreKeysResources {
|
|||
}
|
||||
|
||||
private void dumpNames(final PrintStream out) {
|
||||
final StringResourceMap defaultResMap = mResourcesMap.get(DEFAULT_LANGUAGE_NAME);
|
||||
int id = 0;
|
||||
for (final StringResource res : defaultResMap.getResources()) {
|
||||
out.format(" /* %2d */ \"%s\",\n", id, res.mName);
|
||||
mNameToIdMap.put(res.mName, id);
|
||||
id++;
|
||||
final int namesCount = mSortedResourceNames.length;
|
||||
for (int index = 0; index < namesCount; index++) {
|
||||
final String name = mSortedResourceNames[index];
|
||||
final int histogramValue = mNameHistogram.get(name);
|
||||
out.format(" /* %3d:%2d */ \"%s\",\n", index, histogramValue, name);
|
||||
}
|
||||
}
|
||||
|
||||
private void dumpDefaultTexts(final PrintStream out) {
|
||||
final StringResourceMap defaultResMap = mResourcesMap.get(DEFAULT_LANGUAGE_NAME);
|
||||
final int outputArraySize = dumpTextsInternal(out, defaultResMap, defaultResMap);
|
||||
defaultResMap.setOutputArraySize(outputArraySize);
|
||||
final int outputArraySize = dumpTextsInternal(out, mDefaultResourceMap);
|
||||
mDefaultResourceMap.setOutputArraySize(outputArraySize);
|
||||
}
|
||||
|
||||
private static String getArrayNameForLanguage(final String language) {
|
||||
|
@ -152,35 +201,20 @@ public class MoreKeysResources {
|
|||
}
|
||||
|
||||
private void dumpTexts(final PrintStream out) {
|
||||
final StringResourceMap defaultResMap = mResourcesMap.get(DEFAULT_LANGUAGE_NAME);
|
||||
final ArrayList<String> allLanguages = new ArrayList<String>();
|
||||
allLanguages.addAll(mResourcesMap.keySet());
|
||||
Collections.sort(allLanguages);
|
||||
for (final String language : allLanguages) {
|
||||
if (language.equals(DEFAULT_LANGUAGE_NAME)) {
|
||||
continue;
|
||||
}
|
||||
for (final String language : mSortedLanguagesList) {
|
||||
final StringResourceMap resMap = mResourcesMap.get(language);
|
||||
if (resMap == mDefaultResourceMap) continue;
|
||||
out.format(" /* Language %s: %s */\n", language, getLanguageDisplayName(language));
|
||||
out.format(" private static final String[] " + getArrayNameForLanguage(language)
|
||||
+ " = {\n");
|
||||
final StringResourceMap resMap = mResourcesMap.get(language);
|
||||
for (final StringResource res : resMap.getResources()) {
|
||||
if (!defaultResMap.contains(res.mName)) {
|
||||
throw new RuntimeException(res.mName + " in " + language
|
||||
+ " doesn't have default resource");
|
||||
}
|
||||
}
|
||||
final int outputArraySize = dumpTextsInternal(out, resMap, defaultResMap);
|
||||
final int outputArraySize = dumpTextsInternal(out, resMap);
|
||||
resMap.setOutputArraySize(outputArraySize);
|
||||
out.format(" };\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
private void dumpLanguageMap(final PrintStream out) {
|
||||
final ArrayList<String> allLanguages = new ArrayList<String>();
|
||||
allLanguages.addAll(mResourcesMap.keySet());
|
||||
Collections.sort(allLanguages);
|
||||
for (final String language : allLanguages) {
|
||||
for (final String language : mSortedLanguagesList) {
|
||||
final StringResourceMap resMap = mResourcesMap.get(language);
|
||||
final Locale locale = LocaleUtils.constructLocaleFromString(language);
|
||||
final String languageKeyToDump = locale.getCountry().isEmpty()
|
||||
|
@ -201,15 +235,17 @@ public class MoreKeysResources {
|
|||
return locale.getDisplayName(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
private static int dumpTextsInternal(final PrintStream out, final StringResourceMap resMap,
|
||||
final StringResourceMap defaultResMap) {
|
||||
private int dumpTextsInternal(final PrintStream out, final StringResourceMap resMap) {
|
||||
final ArrayInitializerFormatter formatter =
|
||||
new ArrayInitializerFormatter(out, 100, " ");
|
||||
new ArrayInitializerFormatter(out, 100, " ", mSortedResourceNames);
|
||||
int outputArraySize = 0;
|
||||
boolean successiveNull = false;
|
||||
for (final StringResource defaultRes : defaultResMap.getResources()) {
|
||||
if (resMap.contains(defaultRes.mName)) {
|
||||
final StringResource res = resMap.get(defaultRes.mName);
|
||||
final int namesCount = mSortedResourceNames.length;
|
||||
for (int index = 0; index < namesCount; index++) {
|
||||
final String name = mSortedResourceNames[index];
|
||||
final StringResource res = resMap.get(name);
|
||||
if (res != null) {
|
||||
// TODO: Check whether the resource value is equal to the default.
|
||||
if (res.mComment != null) {
|
||||
formatter.outCommentLines(addPrefix(" // ", res. mComment));
|
||||
}
|
||||
|
@ -270,7 +306,7 @@ public class MoreKeysResources {
|
|||
return t;
|
||||
}
|
||||
|
||||
private static void close(Closeable stream) {
|
||||
private static void close(final Closeable stream) {
|
||||
try {
|
||||
if (stream != null) {
|
||||
stream.close();
|
||||
|
|
Loading…
Reference in New Issue