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