dic_node.h revision 90f6411899393b1d64dcac1c162d6f84bc2e2b7b
1/* 2 * Copyright (C) 2012 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_DIC_NODE_H 18#define LATINIME_DIC_NODE_H 19 20#include "defines.h" 21#include "suggest/core/dicnode/dic_node_profiler.h" 22#include "suggest/core/dicnode/dic_node_release_listener.h" 23#include "suggest/core/dicnode/dic_node_utils.h" 24#include "suggest/core/dicnode/internal/dic_node_state.h" 25#include "suggest/core/dicnode/internal/dic_node_properties.h" 26#include "suggest/core/dictionary/digraph_utils.h" 27#include "suggest/core/dictionary/error_type_utils.h" 28#include "suggest/core/layout/proximity_info_state.h" 29#include "utils/char_utils.h" 30 31#if DEBUG_DICT 32#define LOGI_SHOW_ADD_COST_PROP \ 33 do { \ 34 char charBuf[50]; \ 35 INTS_TO_CHARS(getOutputWordBuf(), getNodeCodePointCount(), charBuf, NELEMS(charBuf)); \ 36 AKLOGI("%20s, \"%c\", size = %03d, total = %03d, index(0) = %02d, dist = %.4f, %s,,", \ 37 __FUNCTION__, getNodeCodePoint(), inputSize, getTotalInputIndex(), \ 38 getInputIndex(0), getNormalizedCompoundDistance(), charBuf); \ 39 } while (0) 40#define DUMP_WORD_AND_SCORE(header) \ 41 do { \ 42 char charBuf[50]; \ 43 INTS_TO_CHARS(getOutputWordBuf(), \ 44 getNodeCodePointCount() \ 45 + mDicNodeState.mDicNodeStateOutput.getPrevWordsLength(), \ 46 charBuf, NELEMS(charBuf)); \ 47 AKLOGI("#%8s, %5f, %5f, %5f, %5f, %s, %d, %5f,", header, \ 48 getSpatialDistanceForScoring(), getLanguageDistanceForScoring(), \ 49 getNormalizedCompoundDistance(), getRawLength(), charBuf, \ 50 getInputIndex(0), getNormalizedCompoundDistanceAfterFirstWord()); \ 51 } while (0) 52#else 53#define LOGI_SHOW_ADD_COST_PROP 54#define DUMP_WORD_AND_SCORE(header) 55#endif 56 57namespace latinime { 58 59// This struct is purely a bucket to return values. No instances of this struct should be kept. 60struct DicNode_InputStateG { 61 DicNode_InputStateG() 62 : mNeedsToUpdateInputStateG(false), mPointerId(0), mInputIndex(0), 63 mPrevCodePoint(0), mTerminalDiffCost(0.0f), mRawLength(0.0f), 64 mDoubleLetterLevel(NOT_A_DOUBLE_LETTER) {} 65 66 bool mNeedsToUpdateInputStateG; 67 int mPointerId; 68 int16_t mInputIndex; 69 int mPrevCodePoint; 70 float mTerminalDiffCost; 71 float mRawLength; 72 DoubleLetterLevel mDoubleLetterLevel; 73}; 74 75class DicNode { 76 // Caveat: We define Weighting as a friend class of DicNode to let Weighting change 77 // the distance of DicNode. 78 // Caution!!! In general, we avoid using the "friend" access modifier. 79 // This is an exception to explicitly hide DicNode::addCost() from all classes but Weighting. 80 friend class Weighting; 81 82 public: 83#if DEBUG_DICT 84 DicNodeProfiler mProfiler; 85#endif 86 ////////////////// 87 // Memory utils // 88 ////////////////// 89 AK_FORCE_INLINE static void managedDelete(DicNode *node) { 90 node->remove(); 91 } 92 // end 93 ///////////////// 94 95 AK_FORCE_INLINE DicNode() 96 : 97#if DEBUG_DICT 98 mProfiler(), 99#endif 100 mDicNodeProperties(), mDicNodeState(), mIsCachedForNextSuggestion(false), 101 mIsUsed(false), mReleaseListener(nullptr) {} 102 103 DicNode(const DicNode &dicNode); 104 DicNode &operator=(const DicNode &dicNode); 105 ~DicNode() {} 106 107 // Init for copy 108 void initByCopy(const DicNode *const dicNode) { 109 mIsUsed = true; 110 mIsCachedForNextSuggestion = dicNode->mIsCachedForNextSuggestion; 111 mDicNodeProperties.initByCopy(&dicNode->mDicNodeProperties); 112 mDicNodeState.initByCopy(&dicNode->mDicNodeState); 113 PROF_NODE_COPY(&dicNode->mProfiler, mProfiler); 114 } 115 116 // Init for root with prevWordPtNodePos which is used for bigram 117 void initAsRoot(const int rootPtNodeArrayPos, const int prevWordPtNodePos) { 118 mIsUsed = true; 119 mIsCachedForNextSuggestion = false; 120 mDicNodeProperties.init(rootPtNodeArrayPos, prevWordPtNodePos); 121 mDicNodeState.init(); 122 PROF_NODE_RESET(mProfiler); 123 } 124 125 // Init for root with previous word 126 void initAsRootWithPreviousWord(const DicNode *const dicNode, const int rootPtNodeArrayPos) { 127 mIsUsed = true; 128 mIsCachedForNextSuggestion = dicNode->mIsCachedForNextSuggestion; 129 mDicNodeProperties.init(rootPtNodeArrayPos, dicNode->mDicNodeProperties.getPtNodePos()); 130 mDicNodeState.initAsRootWithPreviousWord(&dicNode->mDicNodeState, 131 dicNode->mDicNodeProperties.getDepth()); 132 PROF_NODE_COPY(&dicNode->mProfiler, mProfiler); 133 } 134 135 void initAsPassingChild(DicNode *parentDicNode) { 136 mIsUsed = true; 137 mIsCachedForNextSuggestion = parentDicNode->mIsCachedForNextSuggestion; 138 const int parentCodePoint = parentDicNode->getNodeTypedCodePoint(); 139 mDicNodeProperties.init(&parentDicNode->mDicNodeProperties, parentCodePoint); 140 mDicNodeState.initByCopy(&parentDicNode->mDicNodeState); 141 PROF_NODE_COPY(&parentDicNode->mProfiler, mProfiler); 142 } 143 144 void initAsChild(const DicNode *const dicNode, const int ptNodePos, 145 const int childrenPtNodeArrayPos, const int probability, const bool isTerminal, 146 const bool hasChildren, const bool isBlacklistedOrNotAWord, 147 const uint16_t mergedNodeCodePointCount, const int *const mergedNodeCodePoints) { 148 mIsUsed = true; 149 uint16_t newDepth = static_cast<uint16_t>(dicNode->getNodeCodePointCount() + 1); 150 mIsCachedForNextSuggestion = dicNode->mIsCachedForNextSuggestion; 151 const uint16_t newLeavingDepth = static_cast<uint16_t>( 152 dicNode->mDicNodeProperties.getLeavingDepth() + mergedNodeCodePointCount); 153 mDicNodeProperties.init(ptNodePos, childrenPtNodeArrayPos, mergedNodeCodePoints[0], 154 probability, isTerminal, hasChildren, isBlacklistedOrNotAWord, newDepth, 155 newLeavingDepth, dicNode->mDicNodeProperties.getPrevWordTerminalPtNodePos()); 156 mDicNodeState.init(&dicNode->mDicNodeState, mergedNodeCodePointCount, 157 mergedNodeCodePoints); 158 PROF_NODE_COPY(&dicNode->mProfiler, mProfiler); 159 } 160 161 AK_FORCE_INLINE void remove() { 162 mIsUsed = false; 163 if (mReleaseListener) { 164 mReleaseListener->onReleased(this); 165 } 166 } 167 168 bool isUsed() const { 169 return mIsUsed; 170 } 171 172 bool isRoot() const { 173 return getNodeCodePointCount() == 0; 174 } 175 176 bool hasChildren() const { 177 return mDicNodeProperties.hasChildren(); 178 } 179 180 bool isLeavingNode() const { 181 ASSERT(getNodeCodePointCount() <= mDicNodeProperties.getLeavingDepth()); 182 return getNodeCodePointCount() == mDicNodeProperties.getLeavingDepth(); 183 } 184 185 AK_FORCE_INLINE bool isFirstLetter() const { 186 return getNodeCodePointCount() == 1; 187 } 188 189 bool isCached() const { 190 return mIsCachedForNextSuggestion; 191 } 192 193 void setCached() { 194 mIsCachedForNextSuggestion = true; 195 } 196 197 // Used to expand the node in DicNodeUtils 198 int getNodeTypedCodePoint() const { 199 return mDicNodeState.mDicNodeStateOutput.getCurrentWordCodePointAt(getNodeCodePointCount()); 200 } 201 202 // Check if the current word and the previous word can be considered as a valid multiple word 203 // suggestion. 204 bool isValidMultipleWordSuggestion() const { 205 if (isBlacklistedOrNotAWord()) { 206 return false; 207 } 208 // Treat suggestion as invalid if the current and the previous word are single character 209 // words. 210 const int prevWordLen = mDicNodeState.mDicNodeStateOutput.getPrevWordsLength() 211 - mDicNodeState.mDicNodeStateOutput.getPrevWordStart() - 1; 212 const int currentWordLen = getNodeCodePointCount(); 213 return (prevWordLen != 1 || currentWordLen != 1); 214 } 215 216 bool isFirstCharUppercase() const { 217 const int c = mDicNodeState.mDicNodeStateOutput.getCurrentWordCodePointAt(0); 218 return CharUtils::isAsciiUpper(c); 219 } 220 221 bool isCompletion(const int inputSize) const { 222 return mDicNodeState.mDicNodeStateInput.getInputIndex(0) >= inputSize; 223 } 224 225 bool canDoLookAheadCorrection(const int inputSize) const { 226 return mDicNodeState.mDicNodeStateInput.getInputIndex(0) < inputSize - 1; 227 } 228 229 // Used to get bigram probability in DicNodeUtils 230 int getPtNodePos() const { 231 return mDicNodeProperties.getPtNodePos(); 232 } 233 234 // Used to get bigram probability in DicNodeUtils 235 int getPrevWordTerminalPtNodePos() const { 236 return mDicNodeProperties.getPrevWordTerminalPtNodePos(); 237 } 238 239 // Used in DicNodeUtils 240 int getChildrenPtNodeArrayPos() const { 241 return mDicNodeProperties.getChildrenPtNodeArrayPos(); 242 } 243 244 int getProbability() const { 245 return mDicNodeProperties.getProbability(); 246 } 247 248 AK_FORCE_INLINE bool isTerminalDicNode() const { 249 const bool isTerminalPtNode = mDicNodeProperties.isTerminal(); 250 const int currentDicNodeDepth = getNodeCodePointCount(); 251 const int terminalDicNodeDepth = mDicNodeProperties.getLeavingDepth(); 252 return isTerminalPtNode && currentDicNodeDepth > 0 253 && currentDicNodeDepth == terminalDicNodeDepth; 254 } 255 256 bool shouldBeFilteredBySafetyNetForBigram() const { 257 const uint16_t currentDepth = getNodeCodePointCount(); 258 const int prevWordLen = mDicNodeState.mDicNodeStateOutput.getPrevWordsLength() 259 - mDicNodeState.mDicNodeStateOutput.getPrevWordStart() - 1; 260 return !(currentDepth > 0 && (currentDepth != 1 || prevWordLen != 1)); 261 } 262 263 bool hasMatchedOrProximityCodePoints() const { 264 // This DicNode does not have matched or proximity code points when all code points have 265 // been handled as edit corrections or completion so far. 266 const int editCorrectionCount = mDicNodeState.mDicNodeStateScoring.getEditCorrectionCount(); 267 const int completionCount = mDicNodeState.mDicNodeStateScoring.getCompletionCount(); 268 return (editCorrectionCount + completionCount) < getNodeCodePointCount(); 269 } 270 271 bool isTotalInputSizeExceedingLimit() const { 272 const int prevWordsLen = mDicNodeState.mDicNodeStateOutput.getPrevWordsLength(); 273 const int currentWordDepth = getNodeCodePointCount(); 274 // TODO: 3 can be 2? Needs to be investigated. 275 // TODO: Have a const variable for 3 (or 2) 276 return prevWordsLen + currentWordDepth > MAX_WORD_LENGTH - 3; 277 } 278 279 void outputResult(int *dest) const { 280 const uint16_t prevWordLength = mDicNodeState.mDicNodeStateOutput.getPrevWordsLength(); 281 const uint16_t currentDepth = getNodeCodePointCount(); 282 memmove(dest, getOutputWordBuf(), (prevWordLength + currentDepth) * sizeof(dest[0])); 283 DUMP_WORD_AND_SCORE("OUTPUT"); 284 } 285 286 // "Total" in this context (and other methods in this class) means the whole suggestion. When 287 // this represents a multi-word suggestion, the referenced PtNode (in mDicNodeState) is only 288 // the one that corresponds to the last word of the suggestion, and all the previous words 289 // are concatenated together in mDicNodeStateOutput. 290 int getTotalNodeSpaceCount() const { 291 if (!hasMultipleWords()) { 292 return 0; 293 } 294 return CharUtils::getSpaceCount(mDicNodeState.mDicNodeStateOutput.getCodePointBuf(), 295 mDicNodeState.mDicNodeStateOutput.getPrevWordsLength()); 296 } 297 298 int getSecondWordFirstInputIndex(const ProximityInfoState *const pInfoState) const { 299 const int inputIndex = mDicNodeState.mDicNodeStateOutput.getSecondWordFirstInputIndex(); 300 if (inputIndex == NOT_AN_INDEX) { 301 return NOT_AN_INDEX; 302 } else { 303 return pInfoState->getInputIndexOfSampledPoint(inputIndex); 304 } 305 } 306 307 bool hasMultipleWords() const { 308 return mDicNodeState.mDicNodeStateOutput.getPrevWordCount() > 0; 309 } 310 311 int getProximityCorrectionCount() const { 312 return mDicNodeState.mDicNodeStateScoring.getProximityCorrectionCount(); 313 } 314 315 int getEditCorrectionCount() const { 316 return mDicNodeState.mDicNodeStateScoring.getEditCorrectionCount(); 317 } 318 319 // Used to prune nodes 320 float getNormalizedCompoundDistance() const { 321 return mDicNodeState.mDicNodeStateScoring.getNormalizedCompoundDistance(); 322 } 323 324 // Used to prune nodes 325 float getNormalizedSpatialDistance() const { 326 return mDicNodeState.mDicNodeStateScoring.getSpatialDistance() 327 / static_cast<float>(getInputIndex(0) + 1); 328 } 329 330 // Used to prune nodes 331 float getCompoundDistance() const { 332 return mDicNodeState.mDicNodeStateScoring.getCompoundDistance(); 333 } 334 335 // Used to prune nodes 336 float getCompoundDistance(const float languageWeight) const { 337 return mDicNodeState.mDicNodeStateScoring.getCompoundDistance(languageWeight); 338 } 339 340 // Used to commit input partially 341 int getPrevWordPtNodePos() const { 342 return mDicNodeProperties.getPrevWordTerminalPtNodePos(); 343 } 344 345 AK_FORCE_INLINE const int *getOutputWordBuf() const { 346 return mDicNodeState.mDicNodeStateOutput.getCodePointBuf(); 347 } 348 349 int getPrevCodePointG(int pointerId) const { 350 return mDicNodeState.mDicNodeStateInput.getPrevCodePoint(pointerId); 351 } 352 353 // Whether the current codepoint can be an intentional omission, in which case the traversal 354 // algorithm will always check for a possible omission here. 355 bool canBeIntentionalOmission() const { 356 return CharUtils::isIntentionalOmissionCodePoint(getNodeCodePoint()); 357 } 358 359 // Whether the omission is so frequent that it should incur zero cost. 360 bool isZeroCostOmission() const { 361 // TODO: do not hardcode and read from header 362 return (getNodeCodePoint() == KEYCODE_SINGLE_QUOTE); 363 } 364 365 // TODO: remove 366 float getTerminalDiffCostG(int path) const { 367 return mDicNodeState.mDicNodeStateInput.getTerminalDiffCost(path); 368 } 369 370 ////////////////////// 371 // Temporary getter // 372 // TODO: Remove // 373 ////////////////////// 374 // TODO: Remove once touch path is merged into ProximityInfoState 375 // Note: Returned codepoint may be a digraph codepoint if the node is in a composite glyph. 376 int getNodeCodePoint() const { 377 const int codePoint = mDicNodeProperties.getDicNodeCodePoint(); 378 const DigraphUtils::DigraphCodePointIndex digraphIndex = 379 mDicNodeState.mDicNodeStateScoring.getDigraphIndex(); 380 if (digraphIndex == DigraphUtils::NOT_A_DIGRAPH_INDEX) { 381 return codePoint; 382 } 383 return DigraphUtils::getDigraphCodePointForIndex(codePoint, digraphIndex); 384 } 385 386 //////////////////////////////// 387 // Utils for cost calculation // 388 //////////////////////////////// 389 AK_FORCE_INLINE bool isSameNodeCodePoint(const DicNode *const dicNode) const { 390 return mDicNodeProperties.getDicNodeCodePoint() 391 == dicNode->mDicNodeProperties.getDicNodeCodePoint(); 392 } 393 394 // TODO: remove 395 // TODO: rename getNextInputIndex 396 int16_t getInputIndex(int pointerId) const { 397 return mDicNodeState.mDicNodeStateInput.getInputIndex(pointerId); 398 } 399 400 //////////////////////////////////// 401 // Getter of features for scoring // 402 //////////////////////////////////// 403 float getSpatialDistanceForScoring() const { 404 return mDicNodeState.mDicNodeStateScoring.getSpatialDistance(); 405 } 406 407 float getLanguageDistanceForScoring() const { 408 return mDicNodeState.mDicNodeStateScoring.getLanguageDistance(); 409 } 410 411 // For space-aware gestures, we store the normalized distance at the char index 412 // that ends the first word of the suggestion. We call this the distance after 413 // first word. 414 float getNormalizedCompoundDistanceAfterFirstWord() const { 415 return mDicNodeState.mDicNodeStateScoring.getNormalizedCompoundDistanceAfterFirstWord(); 416 } 417 418 float getLanguageDistanceRatePerWordForScoring() const { 419 const float langDist = getLanguageDistanceForScoring(); 420 const float totalWordCount = 421 static_cast<float>(mDicNodeState.mDicNodeStateOutput.getPrevWordCount() + 1); 422 return langDist / totalWordCount; 423 } 424 425 float getRawLength() const { 426 return mDicNodeState.mDicNodeStateScoring.getRawLength(); 427 } 428 429 bool isLessThanOneErrorForScoring() const { 430 return mDicNodeState.mDicNodeStateScoring.getEditCorrectionCount() 431 + mDicNodeState.mDicNodeStateScoring.getProximityCorrectionCount() <= 1; 432 } 433 434 DoubleLetterLevel getDoubleLetterLevel() const { 435 return mDicNodeState.mDicNodeStateScoring.getDoubleLetterLevel(); 436 } 437 438 void setDoubleLetterLevel(DoubleLetterLevel doubleLetterLevel) { 439 mDicNodeState.mDicNodeStateScoring.setDoubleLetterLevel(doubleLetterLevel); 440 } 441 442 bool isInDigraph() const { 443 return mDicNodeState.mDicNodeStateScoring.getDigraphIndex() 444 != DigraphUtils::NOT_A_DIGRAPH_INDEX; 445 } 446 447 void advanceDigraphIndex() { 448 mDicNodeState.mDicNodeStateScoring.advanceDigraphIndex(); 449 } 450 451 ErrorTypeUtils::ErrorType getContainedErrorTypes() const { 452 return mDicNodeState.mDicNodeStateScoring.getContainedErrorTypes(); 453 } 454 455 bool isBlacklistedOrNotAWord() const { 456 return mDicNodeProperties.isBlacklistedOrNotAWord(); 457 } 458 459 inline uint16_t getNodeCodePointCount() const { 460 return mDicNodeProperties.getDepth(); 461 } 462 463 // Returns code point count including spaces 464 inline uint16_t getTotalNodeCodePointCount() const { 465 return getNodeCodePointCount() + mDicNodeState.mDicNodeStateOutput.getPrevWordsLength(); 466 } 467 468 AK_FORCE_INLINE void dump(const char *tag) const { 469#if DEBUG_DICT 470 DUMP_WORD_AND_SCORE(tag); 471#if DEBUG_DUMP_ERROR 472 mProfiler.dump(); 473#endif 474#endif 475 } 476 477 void setReleaseListener(DicNodeReleaseListener *releaseListener) { 478 mReleaseListener = releaseListener; 479 } 480 481 AK_FORCE_INLINE bool compare(const DicNode *right) { 482 if (!isUsed() && !right->isUsed()) { 483 // Compare pointer values here for stable comparison 484 return this > right; 485 } 486 if (!isUsed()) { 487 return true; 488 } 489 if (!right->isUsed()) { 490 return false; 491 } 492 // Promote exact matches to prevent them from being pruned. 493 const bool leftExactMatch = ErrorTypeUtils::isExactMatch(getContainedErrorTypes()); 494 const bool rightExactMatch = ErrorTypeUtils::isExactMatch(right->getContainedErrorTypes()); 495 if (leftExactMatch != rightExactMatch) { 496 return leftExactMatch; 497 } 498 const float diff = 499 right->getNormalizedCompoundDistance() - getNormalizedCompoundDistance(); 500 static const float MIN_DIFF = 0.000001f; 501 if (diff > MIN_DIFF) { 502 return true; 503 } else if (diff < -MIN_DIFF) { 504 return false; 505 } 506 const int depth = getNodeCodePointCount(); 507 const int depthDiff = right->getNodeCodePointCount() - depth; 508 if (depthDiff != 0) { 509 return depthDiff > 0; 510 } 511 for (int i = 0; i < depth; ++i) { 512 const int codePoint = mDicNodeState.mDicNodeStateOutput.getCurrentWordCodePointAt(i); 513 const int rightCodePoint = 514 right->mDicNodeState.mDicNodeStateOutput.getCurrentWordCodePointAt(i); 515 if (codePoint != rightCodePoint) { 516 return rightCodePoint > codePoint; 517 } 518 } 519 // Compare pointer values here for stable comparison 520 return this > right; 521 } 522 523 private: 524 DicNodeProperties mDicNodeProperties; 525 DicNodeState mDicNodeState; 526 // TODO: Remove 527 bool mIsCachedForNextSuggestion; 528 bool mIsUsed; 529 DicNodeReleaseListener *mReleaseListener; 530 531 AK_FORCE_INLINE int getTotalInputIndex() const { 532 int index = 0; 533 for (int i = 0; i < MAX_POINTER_COUNT_G; i++) { 534 index += mDicNodeState.mDicNodeStateInput.getInputIndex(i); 535 } 536 return index; 537 } 538 539 // Caveat: Must not be called outside Weighting 540 // This restriction is guaranteed by "friend" 541 AK_FORCE_INLINE void addCost(const float spatialCost, const float languageCost, 542 const bool doNormalization, const int inputSize, 543 const ErrorTypeUtils::ErrorType errorType) { 544 if (DEBUG_GEO_FULL) { 545 LOGI_SHOW_ADD_COST_PROP; 546 } 547 mDicNodeState.mDicNodeStateScoring.addCost(spatialCost, languageCost, doNormalization, 548 inputSize, getTotalInputIndex(), errorType); 549 } 550 551 // Saves the current normalized compound distance for space-aware gestures. 552 // See getNormalizedCompoundDistanceAfterFirstWord for details. 553 AK_FORCE_INLINE void saveNormalizedCompoundDistanceAfterFirstWordIfNoneYet() { 554 mDicNodeState.mDicNodeStateScoring.saveNormalizedCompoundDistanceAfterFirstWordIfNoneYet(); 555 } 556 557 // Caveat: Must not be called outside Weighting 558 // This restriction is guaranteed by "friend" 559 AK_FORCE_INLINE void forwardInputIndex(const int pointerId, const int count, 560 const bool overwritesPrevCodePointByNodeCodePoint) { 561 if (count == 0) { 562 return; 563 } 564 mDicNodeState.mDicNodeStateInput.forwardInputIndex(pointerId, count); 565 if (overwritesPrevCodePointByNodeCodePoint) { 566 mDicNodeState.mDicNodeStateInput.setPrevCodePoint(0, getNodeCodePoint()); 567 } 568 } 569 570 AK_FORCE_INLINE void updateInputIndexG(const DicNode_InputStateG *const inputStateG) { 571 if (mDicNodeState.mDicNodeStateOutput.getPrevWordCount() == 1 && isFirstLetter()) { 572 mDicNodeState.mDicNodeStateOutput.setSecondWordFirstInputIndex( 573 inputStateG->mInputIndex); 574 } 575 mDicNodeState.mDicNodeStateInput.updateInputIndexG(inputStateG->mPointerId, 576 inputStateG->mInputIndex, inputStateG->mPrevCodePoint, 577 inputStateG->mTerminalDiffCost, inputStateG->mRawLength); 578 mDicNodeState.mDicNodeStateScoring.addRawLength(inputStateG->mRawLength); 579 mDicNodeState.mDicNodeStateScoring.setDoubleLetterLevel(inputStateG->mDoubleLetterLevel); 580 } 581}; 582} // namespace latinime 583#endif // LATINIME_DIC_NODE_H 584