19651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia/*
2ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia * Copyright (C) 2011 The Libphonenumber Authors
39651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia *
49651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia * Licensed under the Apache License, Version 2.0 (the "License");
59651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia * you may not use this file except in compliance with the License.
69651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia * You may obtain a copy of the License at
79651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia *
89651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia * http://www.apache.org/licenses/LICENSE-2.0
99651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia *
109651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia * Unless required by applicable law or agreed to in writing, software
119651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia * distributed under the License is distributed on an "AS IS" BASIS,
129651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia * See the License for the specific language governing permissions and
149651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia * limitations under the License.
159651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia */
169651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia
17f9768eb3c8f303725fb4f899598481cbc4fb76a3Shaopeng Jiapackage com.android.i18n.phonenumbers.prefixmapper;
189651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia
199651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jiaimport java.io.IOException;
209651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jiaimport java.io.ObjectInput;
219651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jiaimport java.io.ObjectOutput;
229651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jiaimport java.nio.ByteBuffer;
239651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jiaimport java.util.Arrays;
249651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jiaimport java.util.Map.Entry;
259651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jiaimport java.util.SortedMap;
269651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jiaimport java.util.SortedSet;
279651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jiaimport java.util.TreeSet;
289651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia
299651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia/**
30f9768eb3c8f303725fb4f899598481cbc4fb76a3Shaopeng Jia * Flyweight phone prefix map storage strategy that uses a table to store unique strings and shorts
31f9768eb3c8f303725fb4f899598481cbc4fb76a3Shaopeng Jia * to store the prefix and description indexes when possible. It is particularly space-efficient
32f9768eb3c8f303725fb4f899598481cbc4fb76a3Shaopeng Jia * when the provided phone prefix map contains a lot of redundant descriptions.
339651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia *
349651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia * @author Philippe Liard
359651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia */
36f9768eb3c8f303725fb4f899598481cbc4fb76a3Shaopeng Jiafinal class FlyweightMapStorage extends PhonePrefixMapStorageStrategy {
379651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia  // Size of short and integer types in bytes.
38ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia  private static final int SHORT_NUM_BYTES = Short.SIZE / 8;
39ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia  private static final int INT_NUM_BYTES = Integer.SIZE / 8;
409651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia
419651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia  // The number of bytes used to store a phone number prefix.
429651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia  private int prefixSizeInBytes;
439651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia  // The number of bytes used to store a description index. It is computed from the size of the
449651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia  // description pool containing all the strings.
459651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia  private int descIndexSizeInBytes;
469651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia
479651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia  private ByteBuffer phoneNumberPrefixes;
489651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia  private ByteBuffer descriptionIndexes;
499651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia
509651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia  // Sorted string array of unique description strings.
519651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia  private String[] descriptionPool;
529651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia
539651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia  @Override
549651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia  public int getPrefix(int index) {
559651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    return readWordFromBuffer(phoneNumberPrefixes, prefixSizeInBytes, index);
569651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia  }
579651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia
58ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia  /**
59ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   * This implementation returns the same string (same identity) when called for multiple indexes
60ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   * corresponding to prefixes that have the same description.
61ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   */
629651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia  @Override
639651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia  public String getDescription(int index) {
64ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    int indexInDescriptionPool =
65ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia        readWordFromBuffer(descriptionIndexes, descIndexSizeInBytes, index);
66ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    return descriptionPool[indexInDescriptionPool];
679651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia  }
689651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia
699651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia  @Override
70f9768eb3c8f303725fb4f899598481cbc4fb76a3Shaopeng Jia  public void readFromSortedMap(SortedMap<Integer, String> phonePrefixMap) {
719651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    SortedSet<String> descriptionsSet = new TreeSet<String>();
72f9768eb3c8f303725fb4f899598481cbc4fb76a3Shaopeng Jia    numOfEntries = phonePrefixMap.size();
73f9768eb3c8f303725fb4f899598481cbc4fb76a3Shaopeng Jia    prefixSizeInBytes = getOptimalNumberOfBytesForValue(phonePrefixMap.lastKey());
749651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    phoneNumberPrefixes = ByteBuffer.allocate(numOfEntries * prefixSizeInBytes);
759651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia
769651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    // Fill the phone number prefixes byte buffer, the set of possible lengths of prefixes and the
779651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    // description set.
789651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    int index = 0;
79f9768eb3c8f303725fb4f899598481cbc4fb76a3Shaopeng Jia    for (Entry<Integer, String> entry : phonePrefixMap.entrySet()) {
809651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia      int prefix = entry.getKey();
81ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia      storeWordInBuffer(phoneNumberPrefixes, prefixSizeInBytes, index, prefix);
82f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia      possibleLengths.add((int) Math.log10(prefix) + 1);
839651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia      descriptionsSet.add(entry.getValue());
84ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia      ++index;
859651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    }
86f9768eb3c8f303725fb4f899598481cbc4fb76a3Shaopeng Jia    createDescriptionPool(descriptionsSet, phonePrefixMap);
87ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia  }
889651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia
89ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia  /**
90f9768eb3c8f303725fb4f899598481cbc4fb76a3Shaopeng Jia   * Creates the description pool from the provided set of string descriptions and phone prefix map.
91ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   */
92ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia  private void createDescriptionPool(SortedSet<String> descriptionsSet,
93f9768eb3c8f303725fb4f899598481cbc4fb76a3Shaopeng Jia      SortedMap<Integer, String> phonePrefixMap) {
949651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    descIndexSizeInBytes = getOptimalNumberOfBytesForValue(descriptionsSet.size() - 1);
959651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    descriptionIndexes = ByteBuffer.allocate(numOfEntries * descIndexSizeInBytes);
969651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    descriptionPool = new String[descriptionsSet.size()];
979651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    descriptionsSet.toArray(descriptionPool);
989651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia
999651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    // Map the phone number prefixes to the descriptions.
100ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    int index = 0;
1019651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    for (int i = 0; i < numOfEntries; i++) {
102f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia      int prefix = readWordFromBuffer(phoneNumberPrefixes, prefixSizeInBytes, i);
103f9768eb3c8f303725fb4f899598481cbc4fb76a3Shaopeng Jia      String description = phonePrefixMap.get(prefix);
104ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia      int positionInDescriptionPool = Arrays.binarySearch(descriptionPool, description);
105ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia      storeWordInBuffer(descriptionIndexes, descIndexSizeInBytes, index, positionInDescriptionPool);
106ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia      ++index;
1079651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    }
1089651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia  }
1099651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia
1109651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia  @Override
1119651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia  public void readExternal(ObjectInput objectInput) throws IOException {
1129651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    // Read binary words sizes.
1139651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    prefixSizeInBytes = objectInput.readInt();
1149651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    descIndexSizeInBytes = objectInput.readInt();
115ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia
1169651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    // Read possible lengths.
1179651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    int sizeOfLengths = objectInput.readInt();
1189651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    possibleLengths.clear();
1199651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    for (int i = 0; i < sizeOfLengths; i++) {
1209651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia      possibleLengths.add(objectInput.readInt());
1219651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    }
122ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia
1239651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    // Read description pool size.
1249651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    int descriptionPoolSize = objectInput.readInt();
1259651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    // Read description pool.
1269651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    if (descriptionPool == null || descriptionPool.length < descriptionPoolSize) {
1279651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia      descriptionPool = new String[descriptionPoolSize];
1289651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    }
1299651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    for (int i = 0; i < descriptionPoolSize; i++) {
1309651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia      String description = objectInput.readUTF();
1319651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia      descriptionPool[i] = description;
1329651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    }
133ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    readEntries(objectInput);
134ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia  }
135ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia
136ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia  /**
137f9768eb3c8f303725fb4f899598481cbc4fb76a3Shaopeng Jia   * Reads the phone prefix entries from the provided input stream and stores them to the internal
138f9768eb3c8f303725fb4f899598481cbc4fb76a3Shaopeng Jia   * byte buffers.
139ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   */
140ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia  private void readEntries(ObjectInput objectInput) throws IOException {
1419651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    numOfEntries = objectInput.readInt();
1429651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    if (phoneNumberPrefixes == null || phoneNumberPrefixes.capacity() < numOfEntries) {
143ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia      phoneNumberPrefixes = ByteBuffer.allocate(numOfEntries * prefixSizeInBytes);
1449651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    }
1459651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    if (descriptionIndexes == null || descriptionIndexes.capacity() < numOfEntries) {
1469651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia      descriptionIndexes = ByteBuffer.allocate(numOfEntries * descIndexSizeInBytes);
1479651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    }
1489651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    for (int i = 0; i < numOfEntries; i++) {
1499651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia      readExternalWord(objectInput, prefixSizeInBytes, phoneNumberPrefixes, i);
1509651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia      readExternalWord(objectInput, descIndexSizeInBytes, descriptionIndexes, i);
1519651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    }
1529651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia  }
1539651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia
1549651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia  @Override
1559651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia  public void writeExternal(ObjectOutput objectOutput) throws IOException {
1569651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    // Write binary words sizes.
1579651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    objectOutput.writeInt(prefixSizeInBytes);
1589651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    objectOutput.writeInt(descIndexSizeInBytes);
159ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia
1609651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    // Write possible lengths.
1619651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    int sizeOfLengths = possibleLengths.size();
1629651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    objectOutput.writeInt(sizeOfLengths);
1639651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    for (Integer length : possibleLengths) {
1649651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia      objectOutput.writeInt(length);
1659651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    }
166ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia
1679651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    // Write description pool size.
1689651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    objectOutput.writeInt(descriptionPool.length);
1699651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    // Write description pool.
1709651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    for (String description : descriptionPool) {
1719651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia      objectOutput.writeUTF(description);
1729651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    }
173ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia
1749651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    // Write entries.
1759651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    objectOutput.writeInt(numOfEntries);
1769651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    for (int i = 0; i < numOfEntries; i++) {
1779651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia      writeExternalWord(objectOutput, prefixSizeInBytes, phoneNumberPrefixes, i);
1789651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia      writeExternalWord(objectOutput, descIndexSizeInBytes, descriptionIndexes, i);
1799651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia    }
1809651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia  }
181ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia
182ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia  /**
183ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   * Gets the minimum number of bytes that can be used to store the provided {@code value}.
184ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   */
185ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia  private static int getOptimalNumberOfBytesForValue(int value) {
186ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    return value <= Short.MAX_VALUE ? SHORT_NUM_BYTES : INT_NUM_BYTES;
187ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia  }
188ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia
189ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia  /**
190ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   * Stores a value which is read from the provided {@code objectInput} to the provided byte {@code
191ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   * buffer} at the specified {@code index}.
192ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   *
193ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   * @param objectInput  the object input stream from which the value is read
194ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   * @param wordSize  the number of bytes used to store the value read from the stream
195ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   * @param outputBuffer  the byte buffer to which the value is stored
196ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   * @param index  the index where the value is stored in the buffer
197ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   * @throws IOException  if an error occurred reading from the object input stream
198ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   */
199ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia  private static void readExternalWord(ObjectInput objectInput, int wordSize,
200ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia      ByteBuffer outputBuffer, int index) throws IOException {
201ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    int wordIndex = index * wordSize;
202ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    if (wordSize == SHORT_NUM_BYTES) {
203ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia      outputBuffer.putShort(wordIndex, objectInput.readShort());
204ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    } else {
205ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia      outputBuffer.putInt(wordIndex, objectInput.readInt());
206ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    }
207ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia  }
208ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia
209ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia  /**
210ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   * Writes the value read from the provided byte {@code buffer} at the specified {@code index} to
211ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   * the provided {@code objectOutput}.
212ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   *
213ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   * @param objectOutput  the object output stream to which the value is written
214ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   * @param wordSize  the number of bytes used to store the value
215ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   * @param inputBuffer  the byte buffer from which the value is read
216ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   * @param index  the index of the value in the the byte buffer
217ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   * @throws IOException if an error occurred writing to the provided object output stream
218ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   */
219ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia  private static void writeExternalWord(ObjectOutput objectOutput, int wordSize,
220ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia      ByteBuffer inputBuffer, int index) throws IOException {
221ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    int wordIndex = index * wordSize;
222ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    if (wordSize == SHORT_NUM_BYTES) {
223ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia      objectOutput.writeShort(inputBuffer.getShort(wordIndex));
224ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    } else {
225ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia      objectOutput.writeInt(inputBuffer.getInt(wordIndex));
226ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    }
227ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia  }
228ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia
229ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia  /**
230ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   * Reads the {@code value} at the specified {@code index} from the provided byte {@code buffer}.
231ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   * Note that only integer and short sizes are supported.
232ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   *
233ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   * @param buffer  the byte buffer from which the value is read
234ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   * @param wordSize  the number of bytes used to store the value
235ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   * @param index  the index where the value is read from
236ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   *
237ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   * @return  the value read from the buffer
238ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   */
239ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia  private static int readWordFromBuffer(ByteBuffer buffer, int wordSize, int index) {
240ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    int wordIndex = index * wordSize;
241ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    return wordSize == SHORT_NUM_BYTES ? buffer.getShort(wordIndex) : buffer.getInt(wordIndex);
242ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia  }
243ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia
244ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia  /**
245ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   * Stores the provided {@code value} to the provided byte {@code buffer} at the specified {@code
246ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   * index} using the provided {@code wordSize} in bytes. Note that only integer and short sizes are
247ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   * supported.
248ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   *
249ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   * @param buffer  the byte buffer to which the value is stored
250ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   * @param wordSize  the number of bytes used to store the provided value
251ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   * @param index  the index to which the value is stored
252ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   * @param value  the value that is stored assuming it does not require more than the specified
253ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   *    number of bytes.
254ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia   */
255ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia  private static void storeWordInBuffer(ByteBuffer buffer, int wordSize, int index, int value) {
256ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    int wordIndex = index * wordSize;
257ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    if (wordSize == SHORT_NUM_BYTES) {
258ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia      buffer.putShort(wordIndex, (short) value);
259ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    } else {
260ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia      buffer.putInt(wordIndex, value);
261ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    }
262ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia  }
2639651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia}
264