diff options
Diffstat (limited to 'java/src/com/android/i18n/phonenumbers/geocoding/FlyweightMapStorage.java')
-rw-r--r-- | java/src/com/android/i18n/phonenumbers/geocoding/FlyweightMapStorage.java | 237 |
1 files changed, 125 insertions, 112 deletions
diff --git a/java/src/com/android/i18n/phonenumbers/geocoding/FlyweightMapStorage.java b/java/src/com/android/i18n/phonenumbers/geocoding/FlyweightMapStorage.java index 453856fe..f0b27bb7 100644 --- a/java/src/com/android/i18n/phonenumbers/geocoding/FlyweightMapStorage.java +++ b/java/src/com/android/i18n/phonenumbers/geocoding/FlyweightMapStorage.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Google Inc. + * Copyright (C) 2011 The Libphonenumber Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +21,6 @@ import java.io.ObjectInput; import java.io.ObjectOutput; import java.nio.ByteBuffer; import java.util.Arrays; -import java.util.Comparator; import java.util.Map.Entry; import java.util.SortedMap; import java.util.SortedSet; @@ -34,10 +33,10 @@ import java.util.TreeSet; * * @author Philippe Liard */ -class FlyweightMapStorage extends AreaCodeMapStorageStrategy { +final class FlyweightMapStorage extends AreaCodeMapStorageStrategy { // Size of short and integer types in bytes. - private static final int SHORT_SIZE = Short.SIZE / 8; - private static final int INT_SIZE = Integer.SIZE / 8; + private static final int SHORT_NUM_BYTES = Short.SIZE / 8; + private static final int INT_NUM_BYTES = Integer.SIZE / 8; // The number of bytes used to store a phone number prefix. private int prefixSizeInBytes; @@ -51,120 +50,60 @@ class FlyweightMapStorage extends AreaCodeMapStorageStrategy { // Sorted string array of unique description strings. private String[] descriptionPool; - public FlyweightMapStorage() {} - - @Override - public boolean isFlyweight() { - return true; - } - - /** - * Gets the minimum number of bytes that can be used to store the provided {@code value}. - */ - private static int getOptimalNumberOfBytesForValue(int value) { - return value <= Short.MAX_VALUE ? SHORT_SIZE : INT_SIZE; - } - - /** - * Stores the provided {@code value} to the provided byte {@code buffer} at the specified {@code - * index} using the provided {@code wordSize} in bytes. Note that only integer and short sizes are - * supported. - * - * @param buffer the byte buffer to which the value is stored - * @param wordSize the number of bytes used to store the provided value - * @param index the index to which the value is stored - * @param value the value that is stored assuming it does not require more than the specified - * number of bytes. - */ - private static void storeWordInBuffer(ByteBuffer buffer, int wordSize, int index, int value) { - index *= wordSize; - - if (wordSize == SHORT_SIZE) { - buffer.putShort(index, (short) value); - } else { - buffer.putInt(index, value); - } - } - - /** - * Reads the {@code value} at the specified {@code index} from the provided byte {@code buffer}. - * Note that only integer and short sizes are supported. - * - * @param buffer the byte buffer from which the value is read - * @param wordSize the number of bytes used to store the value - * @param index the index where the value is read from - * - * @return the value read from the buffer - */ - private static int readWordFromBuffer(ByteBuffer buffer, int wordSize, int index) { - index *= wordSize; - return wordSize == SHORT_SIZE ? buffer.getShort(index) : buffer.getInt(index); - } - @Override public int getPrefix(int index) { return readWordFromBuffer(phoneNumberPrefixes, prefixSizeInBytes, index); } + /** + * This implementation returns the same string (same identity) when called for multiple indexes + * corresponding to prefixes that have the same description. + */ @Override public String getDescription(int index) { - return descriptionPool[readWordFromBuffer(descriptionIndexes, descIndexSizeInBytes, index)]; + int indexInDescriptionPool = + readWordFromBuffer(descriptionIndexes, descIndexSizeInBytes, index); + return descriptionPool[indexInDescriptionPool]; } @Override - public void readFromSortedMap(SortedMap<Integer, String> sortedAreaCodeMap) { + public void readFromSortedMap(SortedMap<Integer, String> areaCodeMap) { SortedSet<String> descriptionsSet = new TreeSet<String>(); - numOfEntries = sortedAreaCodeMap.size(); - prefixSizeInBytes = getOptimalNumberOfBytesForValue(sortedAreaCodeMap.lastKey()); + numOfEntries = areaCodeMap.size(); + prefixSizeInBytes = getOptimalNumberOfBytesForValue(areaCodeMap.lastKey()); phoneNumberPrefixes = ByteBuffer.allocate(numOfEntries * prefixSizeInBytes); // Fill the phone number prefixes byte buffer, the set of possible lengths of prefixes and the // description set. int index = 0; - for (Entry<Integer, String> entry : sortedAreaCodeMap.entrySet()) { + for (Entry<Integer, String> entry : areaCodeMap.entrySet()) { int prefix = entry.getKey(); - storeWordInBuffer(phoneNumberPrefixes, prefixSizeInBytes, index++, prefix); + storeWordInBuffer(phoneNumberPrefixes, prefixSizeInBytes, index, prefix); possibleLengths.add((int) Math.log10(prefix) + 1); descriptionsSet.add(entry.getValue()); + ++index; } + createDescriptionPool(descriptionsSet, areaCodeMap); + } - // Create the description pool. + /** + * Creates the description pool from the provided set of string descriptions and area code map. + */ + private void createDescriptionPool(SortedSet<String> descriptionsSet, + SortedMap<Integer, String> areaCodeMap) { descIndexSizeInBytes = getOptimalNumberOfBytesForValue(descriptionsSet.size() - 1); descriptionIndexes = ByteBuffer.allocate(numOfEntries * descIndexSizeInBytes); descriptionPool = new String[descriptionsSet.size()]; descriptionsSet.toArray(descriptionPool); // Map the phone number prefixes to the descriptions. - index = 0; + int index = 0; for (int i = 0; i < numOfEntries; i++) { int prefix = readWordFromBuffer(phoneNumberPrefixes, prefixSizeInBytes, i); - String description = sortedAreaCodeMap.get(prefix); - int positionInDescriptionPool = - Arrays.binarySearch(descriptionPool, description, new Comparator<String>() { - public int compare(String o1, String o2) { return o1.compareTo(o2); } - }); - storeWordInBuffer(descriptionIndexes, descIndexSizeInBytes, index++, - positionInDescriptionPool); - } - } - - /** - * Stores a value which is read from the provided {@code objectInput} to the provided byte {@code - * buffer} at the specified {@code index}. - * - * @param objectInput the object input stream from which the value is read - * @param wordSize the number of bytes used to store the value read from the stream - * @param outputBuffer the byte buffer to which the value is stored - * @param index the index where the value is stored in the buffer - * @throws IOException if an error occurred reading from the object input stream - */ - private static void readExternalWord(ObjectInput objectInput, int wordSize, - ByteBuffer outputBuffer, int index) throws IOException { - index *= wordSize; - if (wordSize == SHORT_SIZE) { - outputBuffer.putShort(index, objectInput.readShort()); - } else { - outputBuffer.putInt(index, objectInput.readInt()); + String description = areaCodeMap.get(prefix); + int positionInDescriptionPool = Arrays.binarySearch(descriptionPool, description); + storeWordInBuffer(descriptionIndexes, descIndexSizeInBytes, index, positionInDescriptionPool); + ++index; } } @@ -173,12 +112,14 @@ class FlyweightMapStorage extends AreaCodeMapStorageStrategy { // Read binary words sizes. prefixSizeInBytes = objectInput.readInt(); descIndexSizeInBytes = objectInput.readInt(); + // Read possible lengths. int sizeOfLengths = objectInput.readInt(); possibleLengths.clear(); for (int i = 0; i < sizeOfLengths; i++) { possibleLengths.add(objectInput.readInt()); } + // Read description pool size. int descriptionPoolSize = objectInput.readInt(); // Read description pool. @@ -189,10 +130,17 @@ class FlyweightMapStorage extends AreaCodeMapStorageStrategy { String description = objectInput.readUTF(); descriptionPool[i] = description; } - // Read entries. + readEntries(objectInput); + } + + /** + * Reads the area code entries from the provided input stream and stores them to the internal byte + * buffers. + */ + private void readEntries(ObjectInput objectInput) throws IOException { numOfEntries = objectInput.readInt(); if (phoneNumberPrefixes == null || phoneNumberPrefixes.capacity() < numOfEntries) { - phoneNumberPrefixes = ByteBuffer.allocate(numOfEntries * prefixSizeInBytes); + phoneNumberPrefixes = ByteBuffer.allocate(numOfEntries * prefixSizeInBytes); } if (descriptionIndexes == null || descriptionIndexes.capacity() < numOfEntries) { descriptionIndexes = ByteBuffer.allocate(numOfEntries * descIndexSizeInBytes); @@ -203,43 +151,26 @@ class FlyweightMapStorage extends AreaCodeMapStorageStrategy { } } - /** - * Writes the value read from the provided byte {@code buffer} at the specified {@code index} to - * the provided {@code objectOutput}. - * - * @param objectOutput the object output stream to which the value is written - * @param wordSize the number of bytes used to store the value - * @param inputBuffer the byte buffer from which the value is read - * @param index the index of the value in the the byte buffer - * @throws IOException if an error occurred writing to the provided object output stream - */ - private static void writeExternalWord(ObjectOutput objectOutput, int wordSize, - ByteBuffer inputBuffer, int index) throws IOException { - index *= wordSize; - if (wordSize == SHORT_SIZE) { - objectOutput.writeShort(inputBuffer.getShort(index)); - } else { - objectOutput.writeInt(inputBuffer.getInt(index)); - } - } - @Override public void writeExternal(ObjectOutput objectOutput) throws IOException { // Write binary words sizes. objectOutput.writeInt(prefixSizeInBytes); objectOutput.writeInt(descIndexSizeInBytes); + // Write possible lengths. int sizeOfLengths = possibleLengths.size(); objectOutput.writeInt(sizeOfLengths); for (Integer length : possibleLengths) { objectOutput.writeInt(length); } + // Write description pool size. objectOutput.writeInt(descriptionPool.length); // Write description pool. for (String description : descriptionPool) { objectOutput.writeUTF(description); } + // Write entries. objectOutput.writeInt(numOfEntries); for (int i = 0; i < numOfEntries; i++) { @@ -247,4 +178,86 @@ class FlyweightMapStorage extends AreaCodeMapStorageStrategy { writeExternalWord(objectOutput, descIndexSizeInBytes, descriptionIndexes, i); } } + + /** + * Gets the minimum number of bytes that can be used to store the provided {@code value}. + */ + private static int getOptimalNumberOfBytesForValue(int value) { + return value <= Short.MAX_VALUE ? SHORT_NUM_BYTES : INT_NUM_BYTES; + } + + /** + * Stores a value which is read from the provided {@code objectInput} to the provided byte {@code + * buffer} at the specified {@code index}. + * + * @param objectInput the object input stream from which the value is read + * @param wordSize the number of bytes used to store the value read from the stream + * @param outputBuffer the byte buffer to which the value is stored + * @param index the index where the value is stored in the buffer + * @throws IOException if an error occurred reading from the object input stream + */ + private static void readExternalWord(ObjectInput objectInput, int wordSize, + ByteBuffer outputBuffer, int index) throws IOException { + int wordIndex = index * wordSize; + if (wordSize == SHORT_NUM_BYTES) { + outputBuffer.putShort(wordIndex, objectInput.readShort()); + } else { + outputBuffer.putInt(wordIndex, objectInput.readInt()); + } + } + + /** + * Writes the value read from the provided byte {@code buffer} at the specified {@code index} to + * the provided {@code objectOutput}. + * + * @param objectOutput the object output stream to which the value is written + * @param wordSize the number of bytes used to store the value + * @param inputBuffer the byte buffer from which the value is read + * @param index the index of the value in the the byte buffer + * @throws IOException if an error occurred writing to the provided object output stream + */ + private static void writeExternalWord(ObjectOutput objectOutput, int wordSize, + ByteBuffer inputBuffer, int index) throws IOException { + int wordIndex = index * wordSize; + if (wordSize == SHORT_NUM_BYTES) { + objectOutput.writeShort(inputBuffer.getShort(wordIndex)); + } else { + objectOutput.writeInt(inputBuffer.getInt(wordIndex)); + } + } + + /** + * Reads the {@code value} at the specified {@code index} from the provided byte {@code buffer}. + * Note that only integer and short sizes are supported. + * + * @param buffer the byte buffer from which the value is read + * @param wordSize the number of bytes used to store the value + * @param index the index where the value is read from + * + * @return the value read from the buffer + */ + private static int readWordFromBuffer(ByteBuffer buffer, int wordSize, int index) { + int wordIndex = index * wordSize; + return wordSize == SHORT_NUM_BYTES ? buffer.getShort(wordIndex) : buffer.getInt(wordIndex); + } + + /** + * Stores the provided {@code value} to the provided byte {@code buffer} at the specified {@code + * index} using the provided {@code wordSize} in bytes. Note that only integer and short sizes are + * supported. + * + * @param buffer the byte buffer to which the value is stored + * @param wordSize the number of bytes used to store the provided value + * @param index the index to which the value is stored + * @param value the value that is stored assuming it does not require more than the specified + * number of bytes. + */ + private static void storeWordInBuffer(ByteBuffer buffer, int wordSize, int index, int value) { + int wordIndex = index * wordSize; + if (wordSize == SHORT_NUM_BYTES) { + buffer.putShort(wordIndex, (short) value); + } else { + buffer.putInt(wordIndex, value); + } + } } |