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