dic_node.h revision 1fb11da36ab279fa4fcc62d772d9cce877bf23bd
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(const DicNode *const dicNode, const int pos, const int childrenPos, 161 const int probability, const bool isTerminal, const bool hasChildren, 162 const bool isBlacklistedOrNotAWord, const uint16_t mergedNodeCodePointCount, 163 const int *const mergedNodeCodePoints) { 164 mIsUsed = true; 165 uint16_t newDepth = static_cast<uint16_t>(dicNode->getNodeCodePointCount() + 1); 166 mIsCachedForNextSuggestion = dicNode->mIsCachedForNextSuggestion; 167 const uint16_t newLeavingDepth = static_cast<uint16_t>( 168 dicNode->mDicNodeProperties.getLeavingDepth() + mergedNodeCodePointCount); 169 mDicNodeProperties.init(pos, childrenPos, mergedNodeCodePoints[0], probability, 170 isTerminal, hasChildren, isBlacklistedOrNotAWord, newDepth, newLeavingDepth); 171 mDicNodeState.init(&dicNode->mDicNodeState, mergedNodeCodePointCount, 172 mergedNodeCodePoints); 173 PROF_NODE_COPY(&dicNode->mProfiler, mProfiler); 174 } 175 176 AK_FORCE_INLINE void remove() { 177 mIsUsed = false; 178 if (mReleaseListener) { 179 mReleaseListener->onReleased(this); 180 } 181 } 182 183 bool isUsed() const { 184 return mIsUsed; 185 } 186 187 bool isRoot() const { 188 return getNodeCodePointCount() == 0; 189 } 190 191 bool hasChildren() const { 192 return mDicNodeProperties.hasChildren(); 193 } 194 195 bool isLeavingNode() const { 196 ASSERT(getNodeCodePointCount() <= mDicNodeProperties.getLeavingDepth()); 197 return getNodeCodePointCount() == mDicNodeProperties.getLeavingDepth(); 198 } 199 200 AK_FORCE_INLINE bool isFirstLetter() const { 201 return getNodeCodePointCount() == 1; 202 } 203 204 bool isCached() const { 205 return mIsCachedForNextSuggestion; 206 } 207 208 void setCached() { 209 mIsCachedForNextSuggestion = true; 210 } 211 212 // Used to expand the node in DicNodeUtils 213 int getNodeTypedCodePoint() const { 214 return mDicNodeState.mDicNodeStateOutput.getCodePointAt(getNodeCodePointCount()); 215 } 216 217 // Check if the current word and the previous word can be considered as a valid multiple word 218 // suggestion. 219 bool isValidMultipleWordSuggestion() const { 220 if (isBlacklistedOrNotAWord()) { 221 return false; 222 } 223 // Treat suggestion as invalid if the current and the previous word are single character 224 // words. 225 const int prevWordLen = mDicNodeState.mDicNodeStatePrevWord.getPrevWordLength() 226 - mDicNodeState.mDicNodeStatePrevWord.getPrevWordStart() - 1; 227 const int currentWordLen = getNodeCodePointCount(); 228 return (prevWordLen != 1 || currentWordLen != 1); 229 } 230 231 bool isFirstCharUppercase() const { 232 const int c = getOutputWordBuf()[0]; 233 return CharUtils::isAsciiUpper(c); 234 } 235 236 bool isFirstWord() const { 237 return mDicNodeState.mDicNodeStatePrevWord.getPrevWordNodePos() == NOT_A_VALID_WORD_POS; 238 } 239 240 bool isCompletion(const int inputSize) const { 241 return mDicNodeState.mDicNodeStateInput.getInputIndex(0) >= inputSize; 242 } 243 244 bool canDoLookAheadCorrection(const int inputSize) const { 245 return mDicNodeState.mDicNodeStateInput.getInputIndex(0) < inputSize - 1; 246 } 247 248 // Used to get bigram probability in DicNodeUtils 249 int getPos() const { 250 return mDicNodeProperties.getPos(); 251 } 252 253 // Used to get bigram probability in DicNodeUtils 254 int getPrevWordPos() const { 255 return mDicNodeState.mDicNodeStatePrevWord.getPrevWordNodePos(); 256 } 257 258 // Used in DicNodeUtils 259 int getChildrenPos() const { 260 return mDicNodeProperties.getChildrenPos(); 261 } 262 263 int getProbability() const { 264 return mDicNodeProperties.getProbability(); 265 } 266 267 AK_FORCE_INLINE bool isTerminalWordNode() const { 268 const bool isTerminalNodes = mDicNodeProperties.isTerminal(); 269 const int currentNodeDepth = getNodeCodePointCount(); 270 const int terminalNodeDepth = mDicNodeProperties.getLeavingDepth(); 271 return isTerminalNodes && currentNodeDepth > 0 && currentNodeDepth == terminalNodeDepth; 272 } 273 274 bool shouldBeFilterdBySafetyNetForBigram() const { 275 const uint16_t currentDepth = getNodeCodePointCount(); 276 const int prevWordLen = mDicNodeState.mDicNodeStatePrevWord.getPrevWordLength() 277 - mDicNodeState.mDicNodeStatePrevWord.getPrevWordStart() - 1; 278 return !(currentDepth > 0 && (currentDepth != 1 || prevWordLen != 1)); 279 } 280 281 bool isTotalInputSizeExceedingLimit() const { 282 const int prevWordsLen = mDicNodeState.mDicNodeStatePrevWord.getPrevWordLength(); 283 const int currentWordDepth = getNodeCodePointCount(); 284 // TODO: 3 can be 2? Needs to be investigated. 285 // TODO: Have a const variable for 3 (or 2) 286 return prevWordsLen + currentWordDepth > MAX_WORD_LENGTH - 3; 287 } 288 289 // TODO: This may be defective. Needs to be revised. 290 bool truncateNode(const DicNode *const topNode, const int inputCommitPoint) { 291 const int prevWordLenOfTop = mDicNodeState.mDicNodeStatePrevWord.getPrevWordLength(); 292 int newPrevWordStartIndex = inputCommitPoint; 293 int charCount = 0; 294 // Find new word start index 295 for (int i = 0; i < prevWordLenOfTop; ++i) { 296 const int c = mDicNodeState.mDicNodeStatePrevWord.getPrevWordCodePointAt(i); 297 // TODO: Check other separators. 298 if (c != KEYCODE_SPACE && c != KEYCODE_SINGLE_QUOTE) { 299 if (charCount == inputCommitPoint) { 300 newPrevWordStartIndex = i; 301 break; 302 } 303 ++charCount; 304 } 305 } 306 if (!mDicNodeState.mDicNodeStatePrevWord.startsWith( 307 &topNode->mDicNodeState.mDicNodeStatePrevWord, newPrevWordStartIndex - 1)) { 308 // Node mismatch. 309 return false; 310 } 311 mDicNodeState.mDicNodeStateInput.truncate(inputCommitPoint); 312 mDicNodeState.mDicNodeStatePrevWord.truncate(newPrevWordStartIndex); 313 return true; 314 } 315 316 void outputResult(int *dest) const { 317 const uint16_t prevWordLength = mDicNodeState.mDicNodeStatePrevWord.getPrevWordLength(); 318 const uint16_t currentDepth = getNodeCodePointCount(); 319 DicNodeUtils::appendTwoWords(mDicNodeState.mDicNodeStatePrevWord.mPrevWord, 320 prevWordLength, getOutputWordBuf(), currentDepth, dest); 321 DUMP_WORD_AND_SCORE("OUTPUT"); 322 } 323 324 void outputSpacePositionsResult(int *spaceIndices) const { 325 mDicNodeState.mDicNodeStatePrevWord.outputSpacePositions(spaceIndices); 326 } 327 328 bool hasMultipleWords() const { 329 return mDicNodeState.mDicNodeStatePrevWord.getPrevWordCount() > 0; 330 } 331 332 int getProximityCorrectionCount() const { 333 return mDicNodeState.mDicNodeStateScoring.getProximityCorrectionCount(); 334 } 335 336 int getEditCorrectionCount() const { 337 return mDicNodeState.mDicNodeStateScoring.getEditCorrectionCount(); 338 } 339 340 // Used to prune nodes 341 float getNormalizedCompoundDistance() const { 342 return mDicNodeState.mDicNodeStateScoring.getNormalizedCompoundDistance(); 343 } 344 345 // Used to prune nodes 346 float getNormalizedSpatialDistance() const { 347 return mDicNodeState.mDicNodeStateScoring.getSpatialDistance() 348 / static_cast<float>(getInputIndex(0) + 1); 349 } 350 351 // Used to prune nodes 352 float getCompoundDistance() const { 353 return mDicNodeState.mDicNodeStateScoring.getCompoundDistance(); 354 } 355 356 // Used to prune nodes 357 float getCompoundDistance(const float languageWeight) const { 358 return mDicNodeState.mDicNodeStateScoring.getCompoundDistance(languageWeight); 359 } 360 361 // Used to commit input partially 362 int getPrevWordNodePos() const { 363 return mDicNodeState.mDicNodeStatePrevWord.getPrevWordNodePos(); 364 } 365 366 AK_FORCE_INLINE const int *getOutputWordBuf() const { 367 return mDicNodeState.mDicNodeStateOutput.mCodePointsBuf; 368 } 369 370 int getPrevCodePointG(int pointerId) const { 371 return mDicNodeState.mDicNodeStateInput.getPrevCodePoint(pointerId); 372 } 373 374 // Whether the current codepoint can be an intentional omission, in which case the traversal 375 // algorithm will always check for a possible omission here. 376 bool canBeIntentionalOmission() const { 377 return CharUtils::isIntentionalOmissionCodePoint(getNodeCodePoint()); 378 } 379 380 // Whether the omission is so frequent that it should incur zero cost. 381 bool isZeroCostOmission() const { 382 // TODO: do not hardcode and read from header 383 return (getNodeCodePoint() == KEYCODE_SINGLE_QUOTE); 384 } 385 386 // TODO: remove 387 float getTerminalDiffCostG(int path) const { 388 return mDicNodeState.mDicNodeStateInput.getTerminalDiffCost(path); 389 } 390 391 ////////////////////// 392 // Temporary getter // 393 // TODO: Remove // 394 ////////////////////// 395 // TODO: Remove once touch path is merged into ProximityInfoState 396 // Note: Returned codepoint may be a digraph codepoint if the node is in a composite glyph. 397 int getNodeCodePoint() const { 398 const int codePoint = mDicNodeProperties.getNodeCodePoint(); 399 const DigraphUtils::DigraphCodePointIndex digraphIndex = 400 mDicNodeState.mDicNodeStateScoring.getDigraphIndex(); 401 if (digraphIndex == DigraphUtils::NOT_A_DIGRAPH_INDEX) { 402 return codePoint; 403 } 404 return DigraphUtils::getDigraphCodePointForIndex(codePoint, digraphIndex); 405 } 406 407 //////////////////////////////// 408 // Utils for cost calculation // 409 //////////////////////////////// 410 AK_FORCE_INLINE bool isSameNodeCodePoint(const DicNode *const dicNode) const { 411 return mDicNodeProperties.getNodeCodePoint() 412 == dicNode->mDicNodeProperties.getNodeCodePoint(); 413 } 414 415 // TODO: remove 416 // TODO: rename getNextInputIndex 417 int16_t getInputIndex(int pointerId) const { 418 return mDicNodeState.mDicNodeStateInput.getInputIndex(pointerId); 419 } 420 421 //////////////////////////////////// 422 // Getter of features for scoring // 423 //////////////////////////////////// 424 float getSpatialDistanceForScoring() const { 425 return mDicNodeState.mDicNodeStateScoring.getSpatialDistance(); 426 } 427 428 float getLanguageDistanceForScoring() const { 429 return mDicNodeState.mDicNodeStateScoring.getLanguageDistance(); 430 } 431 432 float getLanguageDistanceRatePerWordForScoring() const { 433 const float langDist = getLanguageDistanceForScoring(); 434 const float totalWordCount = 435 static_cast<float>(mDicNodeState.mDicNodeStatePrevWord.getPrevWordCount() + 1); 436 return langDist / totalWordCount; 437 } 438 439 float getRawLength() const { 440 return mDicNodeState.mDicNodeStateScoring.getRawLength(); 441 } 442 443 bool isLessThanOneErrorForScoring() const { 444 return mDicNodeState.mDicNodeStateScoring.getEditCorrectionCount() 445 + mDicNodeState.mDicNodeStateScoring.getProximityCorrectionCount() <= 1; 446 } 447 448 DoubleLetterLevel getDoubleLetterLevel() const { 449 return mDicNodeState.mDicNodeStateScoring.getDoubleLetterLevel(); 450 } 451 452 void setDoubleLetterLevel(DoubleLetterLevel doubleLetterLevel) { 453 mDicNodeState.mDicNodeStateScoring.setDoubleLetterLevel(doubleLetterLevel); 454 } 455 456 bool isInDigraph() const { 457 return mDicNodeState.mDicNodeStateScoring.getDigraphIndex() 458 != DigraphUtils::NOT_A_DIGRAPH_INDEX; 459 } 460 461 void advanceDigraphIndex() { 462 mDicNodeState.mDicNodeStateScoring.advanceDigraphIndex(); 463 } 464 465 bool isExactMatch() const { 466 return mDicNodeState.mDicNodeStateScoring.isExactMatch(); 467 } 468 469 bool isBlacklistedOrNotAWord() const { 470 return mDicNodeProperties.isBlacklistedOrNotAWord(); 471 } 472 473 inline uint16_t getNodeCodePointCount() const { 474 return mDicNodeProperties.getDepth(); 475 } 476 477 // Returns code point count including spaces 478 inline uint16_t getTotalNodeCodePointCount() const { 479 return getNodeCodePointCount() + mDicNodeState.mDicNodeStatePrevWord.getPrevWordLength(); 480 } 481 482 AK_FORCE_INLINE void dump(const char *tag) const { 483#if DEBUG_DICT 484 DUMP_WORD_AND_SCORE(tag); 485#if DEBUG_DUMP_ERROR 486 mProfiler.dump(); 487#endif 488#endif 489 } 490 491 void setReleaseListener(DicNodeReleaseListener *releaseListener) { 492 mReleaseListener = releaseListener; 493 } 494 495 AK_FORCE_INLINE bool compare(const DicNode *right) { 496 if (!isUsed() && !right->isUsed()) { 497 // Compare pointer values here for stable comparison 498 return this > right; 499 } 500 if (!isUsed()) { 501 return true; 502 } 503 if (!right->isUsed()) { 504 return false; 505 } 506 // Promote exact matches to prevent them from being pruned. 507 const bool leftExactMatch = isExactMatch(); 508 const bool rightExactMatch = right->isExactMatch(); 509 if (leftExactMatch != rightExactMatch) { 510 return leftExactMatch; 511 } 512 const float diff = 513 right->getNormalizedCompoundDistance() - getNormalizedCompoundDistance(); 514 static const float MIN_DIFF = 0.000001f; 515 if (diff > MIN_DIFF) { 516 return true; 517 } else if (diff < -MIN_DIFF) { 518 return false; 519 } 520 const int depth = getNodeCodePointCount(); 521 const int depthDiff = right->getNodeCodePointCount() - depth; 522 if (depthDiff != 0) { 523 return depthDiff > 0; 524 } 525 for (int i = 0; i < depth; ++i) { 526 const int codePoint = mDicNodeState.mDicNodeStateOutput.getCodePointAt(i); 527 const int rightCodePoint = right->mDicNodeState.mDicNodeStateOutput.getCodePointAt(i); 528 if (codePoint != rightCodePoint) { 529 return rightCodePoint > codePoint; 530 } 531 } 532 // Compare pointer values here for stable comparison 533 return this > right; 534 } 535 536 private: 537 DicNodeProperties mDicNodeProperties; 538 DicNodeState mDicNodeState; 539 // TODO: Remove 540 bool mIsCachedForNextSuggestion; 541 bool mIsUsed; 542 DicNodeReleaseListener *mReleaseListener; 543 544 AK_FORCE_INLINE int getTotalInputIndex() const { 545 int index = 0; 546 for (int i = 0; i < MAX_POINTER_COUNT_G; i++) { 547 index += mDicNodeState.mDicNodeStateInput.getInputIndex(i); 548 } 549 return index; 550 } 551 552 // Caveat: Must not be called outside Weighting 553 // This restriction is guaranteed by "friend" 554 AK_FORCE_INLINE void addCost(const float spatialCost, const float languageCost, 555 const bool doNormalization, const int inputSize, const ErrorType errorType) { 556 if (DEBUG_GEO_FULL) { 557 LOGI_SHOW_ADD_COST_PROP; 558 } 559 mDicNodeState.mDicNodeStateScoring.addCost(spatialCost, languageCost, doNormalization, 560 inputSize, getTotalInputIndex(), errorType); 561 } 562 563 // Caveat: Must not be called outside Weighting 564 // This restriction is guaranteed by "friend" 565 AK_FORCE_INLINE void forwardInputIndex(const int pointerId, const int count, 566 const bool overwritesPrevCodePointByNodeCodePoint) { 567 if (count == 0) { 568 return; 569 } 570 mDicNodeState.mDicNodeStateInput.forwardInputIndex(pointerId, count); 571 if (overwritesPrevCodePointByNodeCodePoint) { 572 mDicNodeState.mDicNodeStateInput.setPrevCodePoint(0, getNodeCodePoint()); 573 } 574 } 575 576 AK_FORCE_INLINE void updateInputIndexG(DicNode_InputStateG *inputStateG) { 577 mDicNodeState.mDicNodeStateInput.updateInputIndexG(inputStateG->mPointerId, 578 inputStateG->mInputIndex, inputStateG->mPrevCodePoint, 579 inputStateG->mTerminalDiffCost, inputStateG->mRawLength); 580 mDicNodeState.mDicNodeStateScoring.addRawLength(inputStateG->mRawLength); 581 mDicNodeState.mDicNodeStateScoring.setDoubleLetterLevel(inputStateG->mDoubleLetterLevel); 582 } 583}; 584} // namespace latinime 585#endif // LATINIME_DIC_NODE_H 586