• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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