Merge "Remove redundant EditorInfo member from KeyboardLayoutSet.Builder"
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 08a5429..a7798e3 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -74,6 +74,7 @@
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
 import com.android.inputmethod.latin.define.ProductionFlag;
 import com.android.inputmethod.latin.personalization.PersonalizationDictionaryHelper;
+import com.android.inputmethod.latin.personalization.PersonalizationDictionarySessionRegister;
 import com.android.inputmethod.latin.personalization.PersonalizationPredictionDictionary;
 import com.android.inputmethod.latin.personalization.UserHistoryPredictionDictionary;
 import com.android.inputmethod.latin.settings.Settings;
@@ -470,6 +471,7 @@
         KeyboardSwitcher.init(this);
         AudioAndHapticFeedbackManager.init(this);
         AccessibilityUtils.init(this);
+        PersonalizationDictionarySessionRegister.init(this);
 
         super.onCreate();
 
@@ -650,6 +652,7 @@
                 mOptionsDialog.dismiss();
             }
         }
+        PersonalizationDictionarySessionRegister.onConfigurationChanged(this, conf);
         super.onConfigurationChanged(conf);
     }
 
diff --git a/java/src/com/android/inputmethod/latin/personalization/DynamicPredictionDictionaryBase.java b/java/src/com/android/inputmethod/latin/personalization/DynamicPredictionDictionaryBase.java
index bb6ec6b..b2e979d 100644
--- a/java/src/com/android/inputmethod/latin/personalization/DynamicPredictionDictionaryBase.java
+++ b/java/src/com/android/inputmethod/latin/personalization/DynamicPredictionDictionaryBase.java
@@ -402,7 +402,11 @@
     }
 
     public void registerUpdateSession(PersonalizationDictionaryUpdateSession session) {
-        session.setDictionary(this);
+        session.setPredictionDictionary(mLocale, this);
         mSessions.add(session);
     }
+
+    public void unRegisterUpdateSession(PersonalizationDictionaryUpdateSession session) {
+        mSessions.remove(session);
+    }
 }
diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryHelper.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryHelper.java
index da256f8..b4fd250 100644
--- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryHelper.java
+++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryHelper.java
@@ -59,9 +59,8 @@
         }
     }
 
-    public static void
-            registerPersonalizationDictionaryUpdateSession(final Context context,
-                    final PersonalizationDictionaryUpdateSession session) {
+    public static void registerPersonalizationDictionaryUpdateSession(final Context context,
+            final PersonalizationDictionaryUpdateSession session) {
         final PersonalizationPredictionDictionary dictionary =
                 getPersonalizationPredictionDictionary(context,
                         context.getResources().getConfiguration().locale.toString(),
diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionarySessionRegister.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionarySessionRegister.java
new file mode 100644
index 0000000..534d3c5
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionarySessionRegister.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2013 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.personalization;
+
+import android.content.Context;
+import android.content.res.Configuration;
+
+public class PersonalizationDictionarySessionRegister {
+    public static void init(Context context) {
+    }
+
+    public static void onConfigurationChanged(final Context context, final Configuration conf) {
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdateSession.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdateSession.java
index d62aec1..e9dbbc2 100644
--- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdateSession.java
+++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdateSession.java
@@ -43,18 +43,36 @@
     }
 
     // TODO: Use a dynamic binary dictionary instead
-    public WeakReference<DynamicPredictionDictionaryBase> mDictionary;
+    public WeakReference<DynamicPredictionDictionaryBase> mPredictionDictionary;
+    public String mLocale;
 
     public abstract void onDictionaryReady();
 
-    public void setDictionary(DynamicPredictionDictionaryBase dictionary) {
-        mDictionary = new WeakReference<DynamicPredictionDictionaryBase>(dictionary);
+    public void setPredictionDictionary(String locale, DynamicPredictionDictionaryBase dictionary) {
+        mPredictionDictionary = new WeakReference<DynamicPredictionDictionaryBase>(dictionary);
+        mLocale = locale;
+    }
+
+    protected DynamicPredictionDictionaryBase getPredictionDictionary() {
+        return mPredictionDictionary == null ? null : mPredictionDictionary.get();
+    }
+
+    private void unsetPredictionDictionary() {
+        final DynamicPredictionDictionaryBase dictionary = getPredictionDictionary();
+        if (dictionary == null) {
+            return;
+        }
+        dictionary.unRegisterUpdateSession(this);
+    }
+
+
+    public void closeSession() {
+        unsetPredictionDictionary();
     }
 
     public void addToPersonalizationDictionary(
             final ArrayList<PersonalizationLanguageModelParam> lmParams) {
-        final DynamicPredictionDictionaryBase dictionary = mDictionary == null
-                ? null : mDictionary.get();
+        final DynamicPredictionDictionaryBase dictionary = getPredictionDictionary();
         if (dictionary == null) {
             return;
         }
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java
index 4467777..1677e18 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java
@@ -229,10 +229,10 @@
 
         if (!Settings.readFromBuildConfigIfGestureInputEnabled(res)) {
             removePreference(Settings.PREF_GESTURE_SETTINGS, getPreferenceScreen());
-        } else {
-            AdditionalFeaturesSettingUtils.addAdditionalFeaturesPreferences(context, this);
         }
 
+        AdditionalFeaturesSettingUtils.addAdditionalFeaturesPreferences(context, this);
+
         setupKeyLongpressTimeoutSettings(prefs, res);
         setupKeypressVibrationDurationSettings(prefs, res);
         setupKeypressSoundVolumeSettings(prefs, res);
diff --git a/native/jni/Android.mk b/native/jni/Android.mk
index 4786ef6..1f86ecc 100644
--- a/native/jni/Android.mk
+++ b/native/jni/Android.mk
@@ -56,7 +56,6 @@
         binary_dictionary_format_utils.cpp \
         binary_dictionary_header.cpp \
         binary_dictionary_header_reading_utils.cpp \
-        binary_dictionary_terminal_attributes_reading_utils.cpp \
         bloom_filter.cpp \
         byte_array_utils.cpp \
         dictionary.cpp \
@@ -71,6 +70,8 @@
     suggest/core/policy/weighting.cpp \
     suggest/core/session/dic_traverse_session.cpp \
     $(addprefix suggest/policyimpl/dictionary/, \
+        bigram/bigram_list_reading_utils.cpp \
+        shortcut/binary_dictionary_terminal_attributes_reading_utils.cpp \
         dictionary_structure_with_buffer_policy_factory.cpp \
         dynamic_patricia_trie_node_reader.cpp \
         dynamic_patricia_trie_policy.cpp \
diff --git a/native/jni/src/suggest/core/dictionary/terminal_attributes.h b/native/jni/src/suggest/core/dictionary/terminal_attributes.h
index c40a3bb..789450d 100644
--- a/native/jni/src/suggest/core/dictionary/terminal_attributes.h
+++ b/native/jni/src/suggest/core/dictionary/terminal_attributes.h
@@ -19,8 +19,7 @@
 
 #include <stdint.h>
 
-#include "suggest/core/dictionary/binary_dictionary_info.h"
-#include "suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.h"
+#include "suggest/core/policy/dictionary_shortcuts_structure_policy.h"
 
 namespace latinime {
 
@@ -33,9 +32,9 @@
  public:
     class ShortcutIterator {
      public:
-        ShortcutIterator(const BinaryDictionaryInfo *const binaryDictionaryInfo,
+        ShortcutIterator(const DictionaryShortcutsStructurePolicy *const shortcutStructurePolicy,
                 const int shortcutPos, const bool hasShortcutList)
-                : mBinaryDictionaryInfo(binaryDictionaryInfo), mPos(shortcutPos),
+                : mShortcutStructurePolicy(shortcutStructurePolicy), mPos(shortcutPos),
                   mHasNextShortcutTarget(hasShortcutList) {}
 
         inline bool hasNextShortcutTarget() const {
@@ -47,46 +46,34 @@
         AK_FORCE_INLINE void nextShortcutTarget(
                 const int maxDepth, int *const outTarget, int *const outTargetLength,
                 bool *const outIsWhitelist) {
-            const BinaryDictionaryTerminalAttributesReadingUtils::ShortcutFlags flags =
-                    BinaryDictionaryTerminalAttributesReadingUtils::getFlagsAndForwardPointer(
-                            mBinaryDictionaryInfo->getDictRoot(), &mPos);
-            mHasNextShortcutTarget =
-                    BinaryDictionaryTerminalAttributesReadingUtils::hasNext(flags);
-            if (outIsWhitelist) {
-                *outIsWhitelist =
-                        BinaryDictionaryTerminalAttributesReadingUtils::isWhitelist(flags);
-            }
-            if (outTargetLength) {
-                *outTargetLength =
-                        BinaryDictionaryTerminalAttributesReadingUtils::readShortcutTarget(
-                                mBinaryDictionaryInfo, maxDepth, outTarget, &mPos);
-            }
+            mShortcutStructurePolicy->getNextShortcut(maxDepth, outTarget, outTargetLength,
+                    outIsWhitelist, &mHasNextShortcutTarget, &mPos);
         }
 
      private:
-        const BinaryDictionaryInfo *const mBinaryDictionaryInfo;
+        const DictionaryShortcutsStructurePolicy *const mShortcutStructurePolicy;
         int mPos;
         bool mHasNextShortcutTarget;
     };
 
-    TerminalAttributes(const BinaryDictionaryInfo *const binaryDictionaryInfo,
+    TerminalAttributes(const DictionaryShortcutsStructurePolicy *const shortcutStructurePolicy,
             const int shortcutPos)
-            : mBinaryDictionaryInfo(binaryDictionaryInfo), mShortcutListSizePos(shortcutPos) {}
+            : mShortcutStructurePolicy(shortcutStructurePolicy),
+              mShortcutListSizePos(shortcutPos) {}
 
     inline ShortcutIterator getShortcutIterator() const {
         int shortcutPos = mShortcutListSizePos;
         const bool hasShortcutList = shortcutPos != NOT_A_DICT_POS;
         if (hasShortcutList) {
-            BinaryDictionaryTerminalAttributesReadingUtils::getShortcutListSizeAndForwardPointer(
-                    mBinaryDictionaryInfo, &shortcutPos);
+            shortcutPos = mShortcutStructurePolicy->getStartPos(shortcutPos);
         }
         // shortcutPos is never used if hasShortcutList is false.
-        return ShortcutIterator(mBinaryDictionaryInfo, shortcutPos, hasShortcutList);
+        return ShortcutIterator(mShortcutStructurePolicy, shortcutPos, hasShortcutList);
     }
 
  private:
     DISALLOW_IMPLICIT_CONSTRUCTORS(TerminalAttributes);
-    const BinaryDictionaryInfo *const mBinaryDictionaryInfo;
+    const DictionaryShortcutsStructurePolicy *const mShortcutStructurePolicy;
     const int mShortcutListSizePos;
 };
 } // namespace latinime
diff --git a/native/jni/src/suggest/core/policy/dictionary_shortcuts_structure_policy.h b/native/jni/src/suggest/core/policy/dictionary_shortcuts_structure_policy.h
new file mode 100644
index 0000000..40b6c2d
--- /dev/null
+++ b/native/jni/src/suggest/core/policy/dictionary_shortcuts_structure_policy.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2013, 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.
+ */
+
+#ifndef LATINIME_DICTIONARY_SHORTCUTS_STRUCTURE_POLICY_H
+#define LATINIME_DICTIONARY_SHORTCUTS_STRUCTURE_POLICY_H
+
+#include "defines.h"
+
+namespace latinime {
+
+/*
+ * This class abstracts structure of shortcuts.
+ */
+class DictionaryShortcutsStructurePolicy {
+ public:
+    virtual ~DictionaryShortcutsStructurePolicy() {}
+
+    virtual int getStartPos(const int pos) const = 0;
+
+    virtual void getNextShortcut(const int maxCodePointCount, int *const outCodePoint,
+            int *const outCodePointCount, bool *const outIsWhitelist, bool *const outHasNext,
+            int *const pos) const = 0;
+
+    virtual void skipAllShortcuts(int *const pos) const = 0;
+
+ protected:
+    DictionaryShortcutsStructurePolicy() {}
+
+ private:
+    DISALLOW_COPY_AND_ASSIGN(DictionaryShortcutsStructurePolicy);
+};
+} // namespace latinime
+#endif /* LATINIME_DICTIONARY_SHORTCUTS_STRUCTURE_POLICY_H */
diff --git a/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h b/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h
index d83d1e3..6c97067 100644
--- a/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h
+++ b/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h
@@ -24,6 +24,7 @@
 class DicNode;
 class DicNodeVector;
 class DictionaryBigramsStructurePolicy;
+class DictionaryShortcutsStructurePolicy;
 
 /*
  * This class abstracts structure of dictionaries.
@@ -66,6 +67,8 @@
 
     virtual const DictionaryBigramsStructurePolicy *getBigramsStructurePolicy() const = 0;
 
+    virtual const DictionaryShortcutsStructurePolicy *getShortcutsStructurePolicy() const = 0;
+
  protected:
     DictionaryStructureWithBufferPolicy() {}
 
diff --git a/native/jni/src/suggest/core/suggest.cpp b/native/jni/src/suggest/core/suggest.cpp
index f28efd5..e2b96ad 100644
--- a/native/jni/src/suggest/core/suggest.cpp
+++ b/native/jni/src/suggest/core/suggest.cpp
@@ -19,6 +19,7 @@
 #include "suggest/core/dicnode/dic_node.h"
 #include "suggest/core/dicnode/dic_node_priority_queue.h"
 #include "suggest/core/dicnode/dic_node_vector.h"
+// TODO: Use DictionaryStructurePolicy instead of BinaryDictionaryInfo.
 #include "suggest/core/dictionary/binary_dictionary_info.h"
 #include "suggest/core/dictionary/dictionary.h"
 #include "suggest/core/dictionary/digraph_utils.h"
@@ -211,11 +212,11 @@
         }
 
         if (!terminalDicNode->hasMultipleWords()) {
-            const BinaryDictionaryInfo *const binaryDictionaryInfo =
-                    traverseSession->getBinaryDictionaryInfo();
-            const TerminalAttributes terminalAttributes(traverseSession->getBinaryDictionaryInfo(),
-                    binaryDictionaryInfo->getStructurePolicy()->getShortcutPositionOfNode(
-                            terminalDicNode->getPos()));
+            const DictionaryStructureWithBufferPolicy *const structurePolicy =
+                    traverseSession->getBinaryDictionaryInfo()->getStructurePolicy();
+            const TerminalAttributes terminalAttributes(
+                    structurePolicy->getShortcutsStructurePolicy(),
+                    structurePolicy->getShortcutPositionOfNode(terminalDicNode->getPos()));
             // Shortcut is not supported for multiple words suggestions.
             // TODO: Check shortcuts during traversal for multiple words suggestions.
             const bool sameAsTyped = TRAVERSAL->sameAsTyped(traverseSession, terminalDicNode);
diff --git a/native/jni/src/suggest/policyimpl/dictionary/bigrams/bigram_list_policy.h b/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_policy.h
similarity index 64%
rename from native/jni/src/suggest/policyimpl/dictionary/bigrams/bigram_list_policy.h
rename to native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_policy.h
index a9e5da3..beb9bee 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/bigrams/bigram_list_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_policy.h
@@ -21,8 +21,7 @@
 
 #include "defines.h"
 #include "suggest/core/policy/dictionary_bigrams_structure_policy.h"
-// TODO: Move bigrams reading methods to policyimpl.
-#include "suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.h"
+#include "suggest/policyimpl/dictionary/bigram/bigram_list_reading_utils.h"
 
 namespace latinime {
 
@@ -34,19 +33,16 @@
 
     void getNextBigram(int *const outBigramPos, int *const outProbability, bool *const outHasNext,
             int *const pos) const {
-        const BinaryDictionaryTerminalAttributesReadingUtils::BigramFlags flags =
-                BinaryDictionaryTerminalAttributesReadingUtils::getFlagsAndForwardPointer(
-                        mBigramsBuf, pos);
-        *outBigramPos =
-                BinaryDictionaryTerminalAttributesReadingUtils::getBigramAddressAndForwardPointer(
+        const BigramListReadingUtils::BigramFlags flags =
+                BigramListReadingUtils::getFlagsAndForwardPointer(mBigramsBuf, pos);
+        *outBigramPos = BigramListReadingUtils::getBigramAddressAndForwardPointer(
                         mBigramsBuf, flags, pos);
-        *outProbability =
-                BinaryDictionaryTerminalAttributesReadingUtils::getProbabilityFromFlags(flags);
-        *outHasNext = BinaryDictionaryTerminalAttributesReadingUtils::hasNext(flags);
+        *outProbability = BigramListReadingUtils::getProbabilityFromFlags(flags);
+        *outHasNext = BigramListReadingUtils::hasNext(flags);
     }
 
     void skipAllBigrams(int *const pos) const {
-        BinaryDictionaryTerminalAttributesReadingUtils::skipExistingBigrams(mBigramsBuf, pos);
+        BigramListReadingUtils::skipExistingBigrams(mBigramsBuf, pos);
     }
 
  private:
diff --git a/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_reading_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_reading_utils.cpp
new file mode 100644
index 0000000..6f4fcbf
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_reading_utils.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#include "suggest/policyimpl/dictionary/bigram/bigram_list_reading_utils.h"
+
+#include "suggest/core/dictionary/byte_array_utils.h"
+
+namespace latinime {
+
+const BigramListReadingUtils::BigramFlags BigramListReadingUtils::MASK_ATTRIBUTE_ADDRESS_TYPE =
+        0x30;
+const BigramListReadingUtils::BigramFlags
+        BigramListReadingUtils::FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE = 0x10;
+const BigramListReadingUtils::BigramFlags
+        BigramListReadingUtils::FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES = 0x20;
+const BigramListReadingUtils::BigramFlags
+        BigramListReadingUtils::FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES = 0x30;
+const BigramListReadingUtils::BigramFlags
+        BigramListReadingUtils::FLAG_ATTRIBUTE_OFFSET_NEGATIVE = 0x40;
+// Flag for presence of more attributes
+const BigramListReadingUtils::BigramFlags BigramListReadingUtils::FLAG_ATTRIBUTE_HAS_NEXT = 0x80;
+// Mask for attribute probability, stored on 4 bits inside the flags byte.
+const BigramListReadingUtils::BigramFlags
+        BigramListReadingUtils::MASK_ATTRIBUTE_PROBABILITY = 0x0F;
+const int BigramListReadingUtils::ATTRIBUTE_ADDRESS_SHIFT = 4;
+
+/* static */ int BigramListReadingUtils::getBigramAddressAndForwardPointer(
+        const uint8_t *const bigramsBuf, const BigramFlags flags, int *const pos) {
+    int offset = 0;
+    const int origin = *pos;
+    switch (MASK_ATTRIBUTE_ADDRESS_TYPE & flags) {
+        case FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE:
+            offset = ByteArrayUtils::readUint8AndAdvancePosition(bigramsBuf, pos);
+            break;
+        case FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES:
+            offset = ByteArrayUtils::readUint16AndAdvancePosition(bigramsBuf, pos);
+            break;
+        case FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES:
+            offset = ByteArrayUtils::readUint24AndAdvancePosition(bigramsBuf, pos);
+            break;
+    }
+    if (isOffsetNegative(flags)) {
+        return origin - offset;
+    } else {
+        return origin + offset;
+    }
+}
+
+} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_reading_utils.h b/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_reading_utils.h
new file mode 100644
index 0000000..6b2bfe8
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_reading_utils.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef LATINIME_BIGRAM_LIST_READING_UTILS_H
+#define LATINIME_BIGRAM_LIST_READING_UTILS_H
+
+#include <stdint.h>
+
+#include "defines.h"
+#include "suggest/core/dictionary/byte_array_utils.h"
+
+namespace latinime {
+
+class BigramListReadingUtils {
+public:
+   typedef uint8_t BigramFlags;
+
+   static AK_FORCE_INLINE BigramFlags getFlagsAndForwardPointer(
+           const uint8_t *const bigramsBuf, int *const pos) {
+       return ByteArrayUtils::readUint8AndAdvancePosition(bigramsBuf, pos);
+   }
+
+   static AK_FORCE_INLINE int getProbabilityFromFlags(const BigramFlags flags) {
+       return flags & MASK_ATTRIBUTE_PROBABILITY;
+   }
+
+   static AK_FORCE_INLINE bool hasNext(const BigramFlags flags) {
+       return (flags & FLAG_ATTRIBUTE_HAS_NEXT) != 0;
+   }
+
+   // Bigrams reading methods
+   static AK_FORCE_INLINE void skipExistingBigrams(const uint8_t *const bigramsBuf,
+           int *const pos) {
+       BigramFlags flags = getFlagsAndForwardPointer(bigramsBuf, pos);
+       while (hasNext(flags)) {
+           *pos += attributeAddressSize(flags);
+           flags = getFlagsAndForwardPointer(bigramsBuf, pos);
+       }
+       *pos += attributeAddressSize(flags);
+   }
+
+   static int getBigramAddressAndForwardPointer(const uint8_t *const bigramsBuf,
+           const BigramFlags flags, int *const pos);
+
+private:
+   DISALLOW_IMPLICIT_CONSTRUCTORS(BigramListReadingUtils);
+
+   static const BigramFlags MASK_ATTRIBUTE_ADDRESS_TYPE;
+   static const BigramFlags FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE;
+   static const BigramFlags FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES;
+   static const BigramFlags FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES;
+   static const BigramFlags FLAG_ATTRIBUTE_OFFSET_NEGATIVE;
+   static const BigramFlags FLAG_ATTRIBUTE_HAS_NEXT;
+   static const BigramFlags MASK_ATTRIBUTE_PROBABILITY;
+   static const int ATTRIBUTE_ADDRESS_SHIFT;
+
+   static AK_FORCE_INLINE bool isOffsetNegative(const BigramFlags flags) {
+       return (flags & FLAG_ATTRIBUTE_OFFSET_NEGATIVE) != 0;
+   }
+
+   static AK_FORCE_INLINE int attributeAddressSize(const BigramFlags flags) {
+       return (flags & MASK_ATTRIBUTE_ADDRESS_TYPE) >> ATTRIBUTE_ADDRESS_SHIFT;
+       /* Note: this is a value-dependant optimization of what may probably be
+          more readably written this way:
+          switch (flags * BinaryFormat::MASK_ATTRIBUTE_ADDRESS_TYPE) {
+          case FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE: return 1;
+          case FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES: return 2;
+          case FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTE: return 3;
+          default: return 0;
+          }
+       */
+   }
+};
+} // namespace latinime
+#endif // LATINIME_BIGRAM_LIST_READING_UTILS_H
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_with_buffer_policy_factory.cpp b/native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_with_buffer_policy_factory.cpp
index f2c5862..324992a 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_with_buffer_policy_factory.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_with_buffer_policy_factory.cpp
@@ -28,11 +28,9 @@
         const BinaryDictionaryInfo *const binaryDictionaryInfo) {
     switch (binaryDictionaryInfo->getFormat()) {
         case BinaryDictionaryFormatUtils::VERSION_2:
-            return new PatriciaTriePolicy(binaryDictionaryInfo->getDictRoot(),
-                    binaryDictionaryInfo);
+            return new PatriciaTriePolicy(binaryDictionaryInfo->getDictRoot());
         case BinaryDictionaryFormatUtils::VERSION_3:
-            return new DynamicPatriciaTriePolicy(binaryDictionaryInfo->getDictRoot(),
-                    binaryDictionaryInfo);
+            return new DynamicPatriciaTriePolicy(binaryDictionaryInfo->getDictRoot());
         default:
             ASSERT(false);
             return 0;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.cpp b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.cpp
index e8799e5..77a85c8 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.cpp
@@ -16,42 +16,40 @@
 
 #include "suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h"
 
-#include "suggest/core/dictionary/binary_dictionary_info.h"
-#include "suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.h"
-#include "suggest/policyimpl/dictionary/bigrams/bigram_list_policy.h"
+#include "suggest/core/policy/dictionary_bigrams_structure_policy.h"
+#include "suggest/core/policy/dictionary_shortcuts_structure_policy.h"
 #include "suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h"
 
 namespace latinime {
 
 void DynamicPatriciaTrieNodeReader::fetchNodeInfoFromBufferAndProcessMovedNode(const int nodePos,
         const int maxCodePointCount, int *const outCodePoints) {
-    const uint8_t *const dictRoot = mBinaryDictionaryInfo->getDictRoot();
     int pos = nodePos;
-    mFlags = PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(dictRoot, &pos);
+    mFlags = PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(mDictRoot, &pos);
     const int parentPos =
-            DynamicPatriciaTrieReadingUtils::getParentPosAndAdvancePosition(dictRoot, &pos);
+            DynamicPatriciaTrieReadingUtils::getParentPosAndAdvancePosition(mDictRoot, &pos);
     mParentPos = (parentPos != 0) ? mNodePos + parentPos : NOT_A_DICT_POS;
     if (outCodePoints != 0) {
         mCodePointCount = PatriciaTrieReadingUtils::getCharsAndAdvancePosition(
-                dictRoot, mFlags, maxCodePointCount, outCodePoints, &pos);
+                mDictRoot, mFlags, maxCodePointCount, outCodePoints, &pos);
     } else {
         mCodePointCount = PatriciaTrieReadingUtils::skipCharacters(
-                dictRoot, mFlags, MAX_WORD_LENGTH, &pos);
+                mDictRoot, mFlags, MAX_WORD_LENGTH, &pos);
     }
     if (isTerminal()) {
-        mProbability = PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(dictRoot, &pos);
+        mProbability = PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(mDictRoot, &pos);
     } else {
         mProbability = NOT_A_PROBABILITY;
     }
     if (hasChildren()) {
         mChildrenPos = DynamicPatriciaTrieReadingUtils::readChildrenPositionAndAdvancePosition(
-                dictRoot, mFlags, &pos);
+                mDictRoot, mFlags, &pos);
     } else {
         mChildrenPos = NOT_A_DICT_POS;
     }
     if (PatriciaTrieReadingUtils::hasShortcutTargets(mFlags)) {
         mShortcutPos = pos;
-        BinaryDictionaryTerminalAttributesReadingUtils::skipShortcuts(mBinaryDictionaryInfo, &pos);
+        mShortcutsPolicy->skipAllShortcuts(&pos);
     } else {
         mShortcutPos = NOT_A_DICT_POS;
     }
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h
index 641ac9b..e990809 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h
@@ -20,14 +20,13 @@
 #include <stdint.h>
 
 #include "defines.h"
-#include "suggest/policyimpl/dictionary/bigrams/bigram_list_policy.h"
 #include "suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h"
 #include "suggest/policyimpl/dictionary/patricia_trie_reading_utils.h"
 
 namespace latinime {
 
-class BinaryDictionaryInfo;
 class DictionaryBigramsStructurePolicy;
+class DictionaryShortcutsStructurePolicy;
 
 /*
  * This class is used for helping to read nodes of dynamic patricia trie. This class handles moved
@@ -35,13 +34,14 @@
  */
 class DynamicPatriciaTrieNodeReader {
  public:
-    DynamicPatriciaTrieNodeReader(const BinaryDictionaryInfo *const binaryDictionaryInfo,
-            const DictionaryBigramsStructurePolicy *const bigramsPolicy)
-            : mBinaryDictionaryInfo(binaryDictionaryInfo), mBigramsPolicy(bigramsPolicy),
-              mNodePos(NOT_A_VALID_WORD_POS), mFlags(0), mParentPos(NOT_A_DICT_POS),
-              mCodePointCount(0), mProbability(NOT_A_PROBABILITY), mChildrenPos(NOT_A_DICT_POS),
-              mShortcutPos(NOT_A_DICT_POS), mBigramPos(NOT_A_DICT_POS),
-              mSiblingPos(NOT_A_VALID_WORD_POS) {}
+    DynamicPatriciaTrieNodeReader(const uint8_t *const dictRoot,
+            const DictionaryBigramsStructurePolicy *const bigramsPolicy,
+            const DictionaryShortcutsStructurePolicy *const shortcutsPolicy)
+            : mDictRoot(dictRoot), mBigramsPolicy(bigramsPolicy),
+              mShortcutsPolicy(shortcutsPolicy), mNodePos(NOT_A_VALID_WORD_POS), mFlags(0),
+              mParentPos(NOT_A_DICT_POS), mCodePointCount(0), mProbability(NOT_A_PROBABILITY),
+              mChildrenPos(NOT_A_DICT_POS), mShortcutPos(NOT_A_DICT_POS),
+              mBigramPos(NOT_A_DICT_POS), mSiblingPos(NOT_A_VALID_WORD_POS) {}
 
     ~DynamicPatriciaTrieNodeReader() {}
 
@@ -121,8 +121,10 @@
  private:
     DISALLOW_COPY_AND_ASSIGN(DynamicPatriciaTrieNodeReader);
 
-    const BinaryDictionaryInfo *const mBinaryDictionaryInfo;
+    // TODO: Consolidate mDictRoot.
+    const uint8_t *const mDictRoot;
     const DictionaryBigramsStructurePolicy *const mBigramsPolicy;
+    const DictionaryShortcutsStructurePolicy *const mShortcutsPolicy;
     int mNodePos;
     DynamicPatriciaTrieReadingUtils::NodeFlags mFlags;
     int mParentPos;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.cpp
index 9b38415..7d3b2e2 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.cpp
@@ -19,7 +19,6 @@
 #include "defines.h"
 #include "suggest/core/dicnode/dic_node.h"
 #include "suggest/core/dicnode/dic_node_vector.h"
-#include "suggest/core/dictionary/binary_dictionary_info.h"
 #include "suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h"
 #include "suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h"
 #include "suggest/policyimpl/dictionary/patricia_trie_reading_utils.h"
@@ -34,7 +33,8 @@
     if (!dicNode->hasChildren()) {
         return;
     }
-    DynamicPatriciaTrieNodeReader nodeReader(mBinaryDictionaryInfo, getBigramsStructurePolicy());
+    DynamicPatriciaTrieNodeReader nodeReader(mDictRoot, getBigramsStructurePolicy(),
+            getShortcutsStructurePolicy());
     int mergedNodeCodePoints[MAX_WORD_LENGTH];
     int nextPos = dicNode->getChildrenPos();
     int totalChildCount = 0;
@@ -79,7 +79,8 @@
     int mergedNodeCodePoints[maxCodePointCount];
     int codePointCount = 0;
 
-    DynamicPatriciaTrieNodeReader nodeReader(mBinaryDictionaryInfo, getBigramsStructurePolicy());
+    DynamicPatriciaTrieNodeReader nodeReader(mDictRoot, getBigramsStructurePolicy(),
+            getShortcutsStructurePolicy());
     // First, read terminal node and get its probability.
     nodeReader.fetchNodeInfoFromBufferAndGetNodeCodePoints(nodePos, maxCodePointCount,
             mergedNodeCodePoints);
@@ -123,7 +124,8 @@
     int mergedNodeCodePoints[MAX_WORD_LENGTH];
     int currentLength = 0;
     int pos = getRootPosition();
-    DynamicPatriciaTrieNodeReader nodeReader(mBinaryDictionaryInfo, getBigramsStructurePolicy());
+    DynamicPatriciaTrieNodeReader nodeReader(mDictRoot, getBigramsStructurePolicy(),
+            getShortcutsStructurePolicy());
     while (currentLength <= length) {
         // When foundMatchedNode becomes true, currentLength is increased at least once.
         bool foundMatchedNode = false;
@@ -194,7 +196,8 @@
     if (nodePos == NOT_A_VALID_WORD_POS) {
         return NOT_A_PROBABILITY;
     }
-    DynamicPatriciaTrieNodeReader nodeReader(mBinaryDictionaryInfo, getBigramsStructurePolicy());
+    DynamicPatriciaTrieNodeReader nodeReader(mDictRoot, getBigramsStructurePolicy(),
+            getShortcutsStructurePolicy());
     nodeReader.fetchNodeInfoFromBuffer(nodePos);
     if (nodeReader.isDeleted() || nodeReader.isBlacklisted() || nodeReader.isNotAWord()) {
         return NOT_A_PROBABILITY;
@@ -206,7 +209,8 @@
     if (nodePos == NOT_A_VALID_WORD_POS) {
         return NOT_A_DICT_POS;
     }
-    DynamicPatriciaTrieNodeReader nodeReader(mBinaryDictionaryInfo, getBigramsStructurePolicy());
+    DynamicPatriciaTrieNodeReader nodeReader(mDictRoot, getBigramsStructurePolicy(),
+            getShortcutsStructurePolicy());
     nodeReader.fetchNodeInfoFromBuffer(nodePos);
     if (nodeReader.isDeleted()) {
         return NOT_A_DICT_POS;
@@ -218,7 +222,8 @@
     if (nodePos == NOT_A_VALID_WORD_POS) {
         return NOT_A_DICT_POS;
     }
-    DynamicPatriciaTrieNodeReader nodeReader(mBinaryDictionaryInfo, getBigramsStructurePolicy());
+    DynamicPatriciaTrieNodeReader nodeReader(mDictRoot, getBigramsStructurePolicy(),
+            getShortcutsStructurePolicy());
     nodeReader.fetchNodeInfoFromBuffer(nodePos);
     if (nodeReader.isDeleted()) {
         return NOT_A_DICT_POS;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h
index 2386d93..caca369 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h
@@ -21,20 +21,18 @@
 
 #include "defines.h"
 #include "suggest/core/policy/dictionary_structure_with_buffer_policy.h"
-#include "suggest/policyimpl/dictionary/bigrams/bigram_list_policy.h"
+#include "suggest/policyimpl/dictionary/bigram/bigram_list_policy.h"
+#include "suggest/policyimpl/dictionary/shortcut/shortcut_list_policy.h"
 
 namespace latinime {
 
-class BinaryDictionaryInfo;
 class DicNode;
 class DicNodeVector;
 
 class DynamicPatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
  public:
-    DynamicPatriciaTriePolicy(const uint8_t *const dictRoot,
-            const BinaryDictionaryInfo *const binaryDictionaryInfo)
-            : mDictRoot(dictRoot), mBinaryDictionaryInfo(binaryDictionaryInfo),
-              mBigramListPolicy(dictRoot) {}
+    DynamicPatriciaTriePolicy(const uint8_t *const dictRoot)
+            : mDictRoot(dictRoot), mBigramListPolicy(dictRoot), mShortcutListPolicy(dictRoot) {}
 
     ~DynamicPatriciaTriePolicy() {}
 
@@ -62,14 +60,18 @@
         return &mBigramListPolicy;
     }
 
+    const DictionaryShortcutsStructurePolicy *getShortcutsStructurePolicy() const {
+        return &mShortcutListPolicy;
+    }
+
  private:
     DISALLOW_IMPLICIT_CONSTRUCTORS(DynamicPatriciaTriePolicy);
     static const int MAX_CHILD_COUNT_TO_AVOID_INFINITE_LOOP;
 
+    // TODO: Consolidate mDictRoot.
     const uint8_t *const mDictRoot;
-    // TODO: remove
-    const BinaryDictionaryInfo *const mBinaryDictionaryInfo;
     const BigramListPolicy mBigramListPolicy;
+    const ShortcutListPolicy mShortcutListPolicy;
 };
 } // namespace latinime
 #endif // LATINIME_DYNAMIC_PATRICIA_TRIE_POLICY_H
diff --git a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.cpp
index 7001509..8ce2b3e 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.cpp
@@ -20,8 +20,6 @@
 #include "defines.h"
 #include "suggest/core/dicnode/dic_node.h"
 #include "suggest/core/dicnode/dic_node_vector.h"
-#include "suggest/core/dictionary/binary_dictionary_info.h"
-#include "suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.h"
 #include "suggest/policyimpl/dictionary/binary_format.h"
 #include "suggest/policyimpl/dictionary/patricia_trie_reading_utils.h"
 
@@ -112,7 +110,7 @@
         PatriciaTrieReadingUtils::readChildrenPositionAndAdvancePosition(mDictRoot, flags, &pos);
     }
     if (PatriciaTrieReadingUtils::hasShortcutTargets(flags)) {
-        BinaryDictionaryTerminalAttributesReadingUtils::skipShortcuts(mBinaryDictionaryInfo, &pos);
+        mShortcutListPolicy.skipAllShortcuts(&pos);;
     }
     return pos;
 }
@@ -133,7 +131,7 @@
             PatriciaTrieReadingUtils::readChildrenPositionAndAdvancePosition(
                     mDictRoot, flags, &pos) : NOT_A_DICT_POS;
     if (PatriciaTrieReadingUtils::hasShortcutTargets(flags)) {
-        BinaryDictionaryTerminalAttributesReadingUtils::skipShortcuts(mBinaryDictionaryInfo, &pos);
+        getShortcutsStructurePolicy()->skipAllShortcuts(&pos);
     }
     if (PatriciaTrieReadingUtils::hasBigrams(flags)) {
         getBigramsStructurePolicy()->skipAllBigrams(&pos);
diff --git a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.h
index bebee39..51b5b9a 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.h
@@ -21,20 +21,18 @@
 
 #include "defines.h"
 #include "suggest/core/policy/dictionary_structure_with_buffer_policy.h"
-#include "suggest/policyimpl/dictionary/bigrams/bigram_list_policy.h"
+#include "suggest/policyimpl/dictionary/bigram/bigram_list_policy.h"
+#include "suggest/policyimpl/dictionary/shortcut/shortcut_list_policy.h"
 
 namespace latinime {
 
-class BinaryDictionaryInfo;
 class DicNode;
 class DicNodeVector;
 
 class PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
  public:
-    PatriciaTriePolicy(const uint8_t *const dictRoot,
-            const BinaryDictionaryInfo *const binaryDictionaryInfo)
-            : mDictRoot(dictRoot), mBinaryDictionaryInfo(binaryDictionaryInfo),
-              mBigramListPolicy(dictRoot) {}
+    PatriciaTriePolicy(const uint8_t *const dictRoot)
+            : mDictRoot(dictRoot), mBigramListPolicy(dictRoot), mShortcutListPolicy(dictRoot) {}
 
     ~PatriciaTriePolicy() {}
 
@@ -62,13 +60,16 @@
         return &mBigramListPolicy;
     }
 
+    const DictionaryShortcutsStructurePolicy *getShortcutsStructurePolicy() const {
+        return &mShortcutListPolicy;
+    }
+
  private:
     DISALLOW_IMPLICIT_CONSTRUCTORS(PatriciaTriePolicy);
 
     const uint8_t *const mDictRoot;
-    // TODO: remove
-    const BinaryDictionaryInfo *const mBinaryDictionaryInfo;
     const BigramListPolicy mBigramListPolicy;
+    const ShortcutListPolicy mShortcutListPolicy;
 
     int createAndGetLeavingChildNode(const DicNode *const dicNode, const int nodePos,
             const NodeFilter *const nodeFilter, DicNodeVector *const childDicNodes) const;
diff --git a/native/jni/src/suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/shortcut/binary_dictionary_terminal_attributes_reading_utils.cpp
similarity index 65%
rename from native/jni/src/suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.cpp
rename to native/jni/src/suggest/policyimpl/dictionary/shortcut/binary_dictionary_terminal_attributes_reading_utils.cpp
index 9e7d7a3..4b619be 100644
--- a/native/jni/src/suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/shortcut/binary_dictionary_terminal_attributes_reading_utils.cpp
@@ -14,7 +14,8 @@
  * limitations under the License.
  */
 
-#include "suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.h"
+#include \
+    "suggest/policyimpl/dictionary/shortcut/binary_dictionary_terminal_attributes_reading_utils.h"
 
 #include "suggest/core/dictionary/byte_array_utils.h"
 
@@ -36,27 +37,4 @@
 // The numeric value of the shortcut probability that means 'whitelist'.
 const int TaUtils::WHITELIST_SHORTCUT_PROBABILITY = 15;
 
-/* static */ int TaUtils::getBigramAddressAndForwardPointer(
-        const uint8_t *const dictRoot, const TerminalAttributeFlags flags,
-        int *const pos) {
-    int offset = 0;
-    const int origin = *pos;
-    switch (MASK_ATTRIBUTE_ADDRESS_TYPE & flags) {
-        case FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE:
-            offset = ByteArrayUtils::readUint8AndAdvancePosition(dictRoot, pos);
-            break;
-        case FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES:
-            offset = ByteArrayUtils::readUint16AndAdvancePosition(dictRoot, pos);
-            break;
-        case FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES:
-            offset = ByteArrayUtils::readUint24AndAdvancePosition(dictRoot, pos);
-            break;
-    }
-    if (isOffsetNegative(flags)) {
-        return origin - offset;
-    } else {
-        return origin + offset;
-    }
-}
-
 } // namespace latinime
diff --git a/native/jni/src/suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.h b/native/jni/src/suggest/policyimpl/dictionary/shortcut/binary_dictionary_terminal_attributes_reading_utils.h
similarity index 74%
rename from native/jni/src/suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.h
rename to native/jni/src/suggest/policyimpl/dictionary/shortcut/binary_dictionary_terminal_attributes_reading_utils.h
index e1e3e16..3799d84 100644
--- a/native/jni/src/suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/shortcut/binary_dictionary_terminal_attributes_reading_utils.h
@@ -20,7 +20,6 @@
 #include <stdint.h>
 
 #include "defines.h"
-#include "suggest/core/dictionary/binary_dictionary_info.h"
 #include "suggest/core/dictionary/byte_array_utils.h"
 
 namespace latinime {
@@ -28,7 +27,6 @@
 class BinaryDictionaryTerminalAttributesReadingUtils {
  public:
     typedef uint8_t TerminalAttributeFlags;
-    typedef TerminalAttributeFlags BigramFlags;
     typedef TerminalAttributeFlags ShortcutFlags;
 
     static AK_FORCE_INLINE TerminalAttributeFlags getFlagsAndForwardPointer(
@@ -44,34 +42,18 @@
         return (flags & FLAG_ATTRIBUTE_HAS_NEXT) != 0;
     }
 
-    // Bigrams reading methods
-    static AK_FORCE_INLINE void skipExistingBigrams(
-            const uint8_t *const dictRoot, int *const pos) {
-        BigramFlags flags = getFlagsAndForwardPointer(dictRoot, pos);
-        while (hasNext(flags)) {
-            *pos += attributeAddressSize(flags);
-            flags = getFlagsAndForwardPointer(dictRoot, pos);
-        }
-        *pos += attributeAddressSize(flags);
-    }
-
-    static int getBigramAddressAndForwardPointer(
-            const uint8_t *const dictRoot, const BigramFlags flags, int *const pos);
-
     // Shortcuts reading methods
     // This method returns the size of the shortcut list region excluding the shortcut list size
     // field at the beginning.
     static AK_FORCE_INLINE int getShortcutListSizeAndForwardPointer(
-            const BinaryDictionaryInfo *const binaryDictionaryInfo, int *const pos) {
+            const uint8_t *const dictRoot, int *const pos) {
         // readUint16andAdvancePosition() returns an offset *including* the uint16 field itself.
-        return ByteArrayUtils::readUint16AndAdvancePosition(
-                binaryDictionaryInfo->getDictRoot(), pos) - SHORTCUT_LIST_SIZE_FIELD_SIZE;
+        return ByteArrayUtils::readUint16AndAdvancePosition(dictRoot, pos)
+                - SHORTCUT_LIST_SIZE_FIELD_SIZE;
     }
 
-    static AK_FORCE_INLINE void skipShortcuts(
-            const BinaryDictionaryInfo *const binaryDictionaryInfo, int *const pos) {
-        const int shortcutListSize = getShortcutListSizeAndForwardPointer(
-                binaryDictionaryInfo, pos);
+    static AK_FORCE_INLINE void skipShortcuts(const uint8_t *const dictRoot, int *const pos) {
+        const int shortcutListSize = getShortcutListSizeAndForwardPointer(dictRoot, pos);
         *pos += shortcutListSize;
     }
 
@@ -80,10 +62,9 @@
     }
 
     static AK_FORCE_INLINE int readShortcutTarget(
-            const BinaryDictionaryInfo *const binaryDictionaryInfo, const int maxLength,
-            int *const outWord, int *const pos) {
-        return ByteArrayUtils::readStringAndAdvancePosition(
-                binaryDictionaryInfo->getDictRoot(), maxLength, outWord, pos);
+            const uint8_t *const dictRoot, const int maxLength,  int *const outWord,
+            int *const pos) {
+        return ByteArrayUtils::readStringAndAdvancePosition(dictRoot, maxLength, outWord, pos);
     }
 
  private:
diff --git a/native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_policy.h b/native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_policy.h
new file mode 100644
index 0000000..e7acb9d
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_policy.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef LATINIME_SHORTCUT_LIST_POLICY_H
+#define LATINIME_SHORTCUT_LIST_POLICY_H
+
+#include <stdint.h>
+
+#include "defines.h"
+#include "suggest/core/policy/dictionary_shortcuts_structure_policy.h"
+#include \
+    "suggest/policyimpl/dictionary/shortcut/binary_dictionary_terminal_attributes_reading_utils.h"
+
+namespace latinime {
+
+class ShortcutListPolicy : public DictionaryShortcutsStructurePolicy {
+ public:
+    explicit ShortcutListPolicy(const uint8_t *const shortcutBuf)
+            : mShortcutsBuf(shortcutBuf) {}
+
+    ~ShortcutListPolicy() {}
+
+    int getStartPos(const int pos) const {
+        int listPos = pos;
+        BinaryDictionaryTerminalAttributesReadingUtils::getShortcutListSizeAndForwardPointer(
+                mShortcutsBuf, &listPos);
+        return listPos;
+    }
+
+    void getNextShortcut(const int maxCodePointCount, int *const outCodePoint,
+            int *const outCodePointCount, bool *const outIsWhitelist, bool *const outHasNext,
+            int *const pos) const {
+        const BinaryDictionaryTerminalAttributesReadingUtils::ShortcutFlags flags =
+                BinaryDictionaryTerminalAttributesReadingUtils::getFlagsAndForwardPointer(
+                        mShortcutsBuf, pos);
+        if (outHasNext) {
+            *outHasNext = BinaryDictionaryTerminalAttributesReadingUtils::hasNext(flags);
+        }
+        if (outIsWhitelist) {
+            *outIsWhitelist =
+                    BinaryDictionaryTerminalAttributesReadingUtils::isWhitelist(flags);
+        }
+        if (outCodePoint) {
+            *outCodePointCount =
+                    BinaryDictionaryTerminalAttributesReadingUtils::readShortcutTarget(
+                            mShortcutsBuf, maxCodePointCount, outCodePoint, pos);
+        }
+    }
+
+    void skipAllShortcuts(int *const pos) const {
+        const int shortcutListSize = BinaryDictionaryTerminalAttributesReadingUtils
+                ::getShortcutListSizeAndForwardPointer(mShortcutsBuf, pos);
+        *pos += shortcutListSize;
+    }
+
+ private:
+    DISALLOW_IMPLICIT_CONSTRUCTORS(ShortcutListPolicy);
+
+    const uint8_t *const mShortcutsBuf;
+};
+} // namespace latinime
+#endif // LATINIME_SHORTCUT_LIST_POLICY_H