1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef LATINIME_WORDS_PRIORITY_QUEUE_H 18 #define LATINIME_WORDS_PRIORITY_QUEUE_H 19 20 #include <cstring> // for memcpy() 21 #include <queue> 22 23 #include "correction.h" 24 #include "defines.h" 25 26 namespace latinime { 27 28 class WordsPriorityQueue { 29 public: 30 class SuggestedWord { 31 public: 32 int mScore; 33 unsigned short mWord[MAX_WORD_LENGTH_INTERNAL]; 34 int mWordLength; 35 bool mUsed; 36 int mType; 37 setParams(int score,unsigned short * word,int wordLength,int type)38 void setParams(int score, unsigned short *word, int wordLength, int type) { 39 mScore = score; 40 mWordLength = wordLength; 41 memcpy(mWord, word, sizeof(unsigned short) * wordLength); 42 mUsed = true; 43 mType = type; 44 } 45 }; 46 WordsPriorityQueue(int maxWords,int maxWordLength)47 WordsPriorityQueue(int maxWords, int maxWordLength) 48 : mSuggestions(), MAX_WORDS(static_cast<unsigned int>(maxWords)), 49 MAX_WORD_LENGTH(static_cast<unsigned int>(maxWordLength)), 50 mSuggestedWords(new SuggestedWord[maxWordLength]), mHighestSuggestedWord(0) { 51 for (int i = 0; i < maxWordLength; ++i) { 52 mSuggestedWords[i].mUsed = false; 53 } 54 } 55 ~WordsPriorityQueue()56 virtual ~WordsPriorityQueue() { 57 delete[] mSuggestedWords; 58 } 59 push(int score,unsigned short * word,int wordLength,int type)60 void push(int score, unsigned short *word, int wordLength, int type) { 61 SuggestedWord *sw = 0; 62 if (mSuggestions.size() >= MAX_WORDS) { 63 sw = mSuggestions.top(); 64 const int minScore = sw->mScore; 65 if (minScore >= score) { 66 return; 67 } else { 68 sw->mUsed = false; 69 mSuggestions.pop(); 70 } 71 } 72 if (sw == 0) { 73 sw = getFreeSuggestedWord(score, word, wordLength, type); 74 } else { 75 sw->setParams(score, word, wordLength, type); 76 } 77 if (sw == 0) { 78 AKLOGE("SuggestedWord is accidentally null."); 79 return; 80 } 81 if (DEBUG_WORDS_PRIORITY_QUEUE) { 82 AKLOGI("Push word. %d, %d", score, wordLength); 83 DUMP_WORD(word, wordLength); 84 } 85 mSuggestions.push(sw); 86 if (!mHighestSuggestedWord || mHighestSuggestedWord->mScore < sw->mScore) { 87 mHighestSuggestedWord = sw; 88 } 89 } 90 top()91 SuggestedWord *top() { 92 if (mSuggestions.empty()) return 0; 93 SuggestedWord *sw = mSuggestions.top(); 94 return sw; 95 } 96 outputSuggestions(const unsigned short * before,const int beforeLength,int * frequencies,unsigned short * outputChars,int * outputTypes)97 int outputSuggestions(const unsigned short *before, const int beforeLength, 98 int *frequencies, unsigned short *outputChars, int* outputTypes) { 99 mHighestSuggestedWord = 0; 100 const unsigned int size = min( 101 MAX_WORDS, static_cast<unsigned int>(mSuggestions.size())); 102 SuggestedWord *swBuffer[size]; 103 int index = size - 1; 104 while (!mSuggestions.empty() && index >= 0) { 105 SuggestedWord *sw = mSuggestions.top(); 106 if (DEBUG_WORDS_PRIORITY_QUEUE) { 107 AKLOGI("dump word. %d", sw->mScore); 108 DUMP_WORD(sw->mWord, sw->mWordLength); 109 } 110 swBuffer[index] = sw; 111 mSuggestions.pop(); 112 --index; 113 } 114 if (size >= 2) { 115 SuggestedWord *nsMaxSw = 0; 116 unsigned int maxIndex = 0; 117 float maxNs = 0; 118 for (unsigned int i = 0; i < size; ++i) { 119 SuggestedWord *tempSw = swBuffer[i]; 120 if (!tempSw) { 121 continue; 122 } 123 const float tempNs = getNormalizedScore(tempSw, before, beforeLength, 0, 0, 0); 124 if (tempNs >= maxNs) { 125 maxNs = tempNs; 126 maxIndex = i; 127 nsMaxSw = tempSw; 128 } 129 } 130 if (maxIndex > 0 && nsMaxSw) { 131 memmove(&swBuffer[1], &swBuffer[0], maxIndex * sizeof(SuggestedWord *)); 132 swBuffer[0] = nsMaxSw; 133 } 134 } 135 for (unsigned int i = 0; i < size; ++i) { 136 SuggestedWord *sw = swBuffer[i]; 137 if (!sw) { 138 AKLOGE("SuggestedWord is null %d", i); 139 continue; 140 } 141 const unsigned int wordLength = sw->mWordLength; 142 unsigned short *targetAddress = outputChars + i * MAX_WORD_LENGTH; 143 frequencies[i] = sw->mScore; 144 outputTypes[i] = sw->mType; 145 memcpy(targetAddress, sw->mWord, wordLength * sizeof(unsigned short)); 146 if (wordLength < MAX_WORD_LENGTH) { 147 targetAddress[wordLength] = 0; 148 } 149 sw->mUsed = false; 150 } 151 return size; 152 } 153 size()154 int size() const { 155 return mSuggestions.size(); 156 } 157 clear()158 void clear() { 159 mHighestSuggestedWord = 0; 160 while (!mSuggestions.empty()) { 161 SuggestedWord *sw = mSuggestions.top(); 162 if (DEBUG_WORDS_PRIORITY_QUEUE) { 163 AKLOGI("Clear word. %d", sw->mScore); 164 DUMP_WORD(sw->mWord, sw->mWordLength); 165 } 166 sw->mUsed = false; 167 mSuggestions.pop(); 168 } 169 } 170 dumpTopWord()171 void dumpTopWord() { 172 if (size() <= 0) { 173 return; 174 } 175 DUMP_WORD(mHighestSuggestedWord->mWord, mHighestSuggestedWord->mWordLength); 176 } 177 getHighestNormalizedScore(const unsigned short * before,const int beforeLength,unsigned short ** outWord,int * outScore,int * outLength)178 float getHighestNormalizedScore(const unsigned short *before, const int beforeLength, 179 unsigned short **outWord, int *outScore, int *outLength) { 180 if (!mHighestSuggestedWord) { 181 return 0.0; 182 } 183 return getNormalizedScore( 184 mHighestSuggestedWord, before, beforeLength, outWord, outScore, outLength); 185 } 186 187 private: 188 DISALLOW_IMPLICIT_CONSTRUCTORS(WordsPriorityQueue); 189 struct wordComparator { operatorwordComparator190 bool operator ()(SuggestedWord * left, SuggestedWord * right) { 191 return left->mScore > right->mScore; 192 } 193 }; 194 getFreeSuggestedWord(int score,unsigned short * word,int wordLength,int type)195 SuggestedWord *getFreeSuggestedWord(int score, unsigned short *word, 196 int wordLength, int type) { 197 for (unsigned int i = 0; i < MAX_WORD_LENGTH; ++i) { 198 if (!mSuggestedWords[i].mUsed) { 199 mSuggestedWords[i].setParams(score, word, wordLength, type); 200 return &mSuggestedWords[i]; 201 } 202 } 203 return 0; 204 } 205 getNormalizedScore(SuggestedWord * sw,const unsigned short * before,const int beforeLength,unsigned short ** outWord,int * outScore,int * outLength)206 static float getNormalizedScore(SuggestedWord *sw, const unsigned short *before, 207 const int beforeLength, unsigned short **outWord, int *outScore, int *outLength) { 208 const int score = sw->mScore; 209 unsigned short *word = sw->mWord; 210 const int wordLength = sw->mWordLength; 211 if (outScore) { 212 *outScore = score; 213 } 214 if (outWord) { 215 *outWord = word; 216 } 217 if (outLength) { 218 *outLength = wordLength; 219 } 220 return Correction::RankingAlgorithm::calcNormalizedScore( 221 before, beforeLength, word, wordLength, score); 222 } 223 224 typedef std::priority_queue<SuggestedWord *, std::vector<SuggestedWord *>, 225 wordComparator> Suggestions; 226 Suggestions mSuggestions; 227 const unsigned int MAX_WORDS; 228 const unsigned int MAX_WORD_LENGTH; 229 SuggestedWord *mSuggestedWords; 230 SuggestedWord *mHighestSuggestedWord; 231 }; 232 } // namespace latinime 233 #endif // LATINIME_WORDS_PRIORITY_QUEUE_H 234