Add new bigram entry at the tail of existing list.

Bug: 13406708
Change-Id: If3162e65fc9aa2c47f046aee528276cb51fad9f4
diff --git a/native/jni/src/suggest/policyimpl/dictionary/bigram/ver4_bigram_list_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/bigram/ver4_bigram_list_policy.cpp
index 5df2096..04e768f 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/bigram/ver4_bigram_list_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/bigram/ver4_bigram_list_policy.cpp
@@ -55,7 +55,7 @@
     }
     const int bigramListPos = mBigramDictContent->getBigramListHeadPos(terminalId);
     if (bigramListPos == NOT_A_DICT_POS) {
-        // Updating PtNode doesn't have a bigram list.
+        // Updating PtNode that doesn't have a bigram list.
         // Create new bigram list.
         if (!mBigramDictContent->createNewBigramList(terminalId)) {
             return false;
@@ -98,19 +98,27 @@
     if (!mBigramDictContent->createNewBigramList(terminalId)) {
         return false;
     }
-    // Write new entry at a head position of the bigram list.
     int writingPos = mBigramDictContent->getBigramListHeadPos(terminalId);
-    const BigramEntry newBigramEntry(true /* hasNext */, NOT_A_PROBABILITY, newTargetTerminalId);
+    int tailEntryPos = NOT_A_DICT_POS;
+    // Copy existing bigram list.
+    if (!mBigramDictContent->copyBigramList(bigramListPos, writingPos, &tailEntryPos)) {
+        return false;
+    }
+    // Write new entry at the tail position of the bigram content.
+    const BigramEntry newBigramEntry(false /* hasNext */, NOT_A_PROBABILITY, newTargetTerminalId);
     const BigramEntry bigramEntryToWrite = createUpdatedBigramEntryFrom(
             &newBigramEntry, newProbability, timestamp);
-    if (!mBigramDictContent->writeBigramEntryAndAdvancePosition(&bigramEntryToWrite, &writingPos)) {
+    if (!mBigramDictContent->writeBigramEntryAtTail(&bigramEntryToWrite)) {
+        return false;
+    }
+    // Update has next flag of the tail entry.
+    if (!updateHasNextFlag(true /* hasNext */, tailEntryPos)) {
         return false;
     }
     if (outAddedNewEntry) {
         *outAddedNewEntry = true;
     }
-    // Append existing entries by copying.
-    return mBigramDictContent->copyBigramList(bigramListPos, writingPos);
+    return true;
 }
 
 bool Ver4BigramListPolicy::removeEntry(const int terminalId, const int targetTerminalId) {
@@ -239,4 +247,10 @@
     }
 }
 
+bool Ver4BigramListPolicy::updateHasNextFlag(const bool hasNext, const int bigramEntryPos) {
+    const BigramEntry bigramEntry = mBigramDictContent->getBigramEntry(bigramEntryPos);
+    const BigramEntry updatedBigramEntry = bigramEntry.updateHasNextAndGetEntry(hasNext);
+    return mBigramDictContent->writeBigramEntry(&updatedBigramEntry, bigramEntryPos);
+}
+
 } // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/bigram/ver4_bigram_list_policy.h b/native/jni/src/suggest/policyimpl/dictionary/bigram/ver4_bigram_list_policy.h
index 5b6c5a1..d8f7be6 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/bigram/ver4_bigram_list_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/bigram/ver4_bigram_list_policy.h
@@ -61,6 +61,8 @@
     const BigramEntry createUpdatedBigramEntryFrom(const BigramEntry *const originalBigramEntry,
             const int newProbability, const int timestamp) const;
 
+    bool updateHasNextFlag(const bool hasNext, const int bigramEntryPos);
+
     BigramDictContent *const mBigramDictContent;
     const TerminalPositionLookupTable *const mTerminalPositionLookupTable;
     const HeaderPolicy *const mHeaderPolicy;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/bigram_dict_content.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/bigram_dict_content.cpp
index 279f5b3..56f19db 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/bigram_dict_content.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/bigram_dict_content.cpp
@@ -113,13 +113,17 @@
     return true;
 }
 
-bool BigramDictContent::copyBigramList(const int bigramListPos, const int toPos) {
+bool BigramDictContent::copyBigramList(const int bigramListPos, const int toPos,
+        int *const outTailEntryPos) {
     int readingPos = bigramListPos;
     int writingPos = toPos;
     bool hasNext = true;
     while (hasNext) {
         const BigramEntry bigramEntry = getBigramEntryAndAdvancePosition(&readingPos);
         hasNext = bigramEntry.hasNext();
+        if (!hasNext) {
+            *outTailEntryPos = writingPos;
+        }
         if (!writeBigramEntryAndAdvancePosition(&bigramEntry, &writingPos)) {
             AKLOGE("Cannot write bigram entry to copy. pos: %d", writingPos);
             return false;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/bigram_dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/bigram_dict_content.h
index ba2a052..40ece76 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/bigram_dict_content.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/bigram_dict_content.h
@@ -58,6 +58,11 @@
         return addressLookupTable->get(terminalId);
     }
 
+    bool writeBigramEntryAtTail(const BigramEntry *const bigramEntryToWrite) {
+        int writingPos = getContentBuffer()->getTailPosition();
+        return writeBigramEntryAndAdvancePosition(bigramEntryToWrite, &writingPos);
+    }
+
     bool writeBigramEntry(const BigramEntry *const bigramEntryToWrite, const int entryWritingPos) {
         int writingPos = entryWritingPos;
         return writeBigramEntryAndAdvancePosition(bigramEntryToWrite, &writingPos);
@@ -71,7 +76,7 @@
         return getUpdatableAddressLookupTable()->set(terminalId, bigramListPos);
     }
 
-    bool copyBigramList(const int bigramListPos, const int toPos);
+    bool copyBigramList(const int bigramListPos, const int toPos, int *const outTailEntryPos);
 
     bool flushToFile(const char *const dictPath) const {
         return flush(dictPath, Ver4DictConstants::BIGRAM_LOOKUP_TABLE_FILE_EXTENSION,