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