private int BranchNext(int pos, int length) { while (length > CharsTrie.kMaxBranchLinearSubNodeLength) { ++pos; // ignore the comparison unit // Push state for the greater-or-equal edge. // ICU4N: Sign extended operand here is desirable, as that is what was happening in Java stack_.Add(((long)CharsTrie.SkipDelta(chars_, pos) << 32) | (uint)((length - (length >> 1)) << 16) | (uint)str_.Length); // Follow the less-than edge. length >>= 1; pos = CharsTrie.JumpByDelta(chars_, pos); } // List of key-value pairs where values are either final values or jump deltas. // Read the first (key, value) pair. char trieUnit = chars_[pos++]; int node = chars_[pos++]; bool isFinal = (node & CharsTrie.kValueIsFinal) != 0; int value = CharsTrie.ReadValue(chars_, pos, node &= 0x7fff); pos = CharsTrie.SkipValue(pos, node); // ICU4N: Sign extended operand here is desirable, as that is what was happening in Java stack_.Add(((long)pos << 32) | (uint)((length - 1) << 16) | (uint)str_.Length); str_.Append(trieUnit); if (isFinal) { pos_ = -1; entry_.Chars = str_.AsCharSequence(); entry_.Value = value; return(-1); } else { return(pos + value); } }
/// <summary> /// Finds the next (string, value) pair if there is one. /// </summary> /// <remarks> /// If the string is truncated to the maximum length and does not /// have a real value, then the value is set to -1. /// In this case, this "not a real value" is indistinguishable from /// a real value of -1. /// </remarks> /// <returns>An <see cref="CharsTrieEntry"/> with the string and value of the next element.</returns> /// <stable>ICU 4.8</stable> private CharsTrieEntry Next() { int pos = pos_; if (pos < 0) { //if (stack_.isEmpty()) //{ // throw new NoSuchElementException(); //} // Pop the state off the stack and continue with the next outbound edge of // the branch node. long top = stack_[stack_.Count - 1]; stack_.Remove(top); int length = (int)top; pos = (int)(top >> 32); str_.Length = (length & 0xffff); length = length.TripleShift(16); if (length > 1) { pos = BranchNext(pos, length); if (pos < 0) { return(entry_); // Reached a final value. } } else { str_.Append(chars_[pos++]); } } if (remainingMatchLength_ >= 0) { // We only get here if we started in a pending linear-match node // with more than maxLength remaining units. return(TruncateAndStop()); } for (; ;) { int node = chars_[pos++]; if (node >= CharsTrie.kMinValueLead) { if (skipValue_) { pos = CharsTrie.SkipNodeValue(pos, node); node &= CharsTrie.kNodeTypeMask; skipValue_ = false; } else { // Deliver value for the string so far. bool isFinal = (node & CharsTrie.kValueIsFinal) != 0; if (isFinal) { entry_.Value = CharsTrie.ReadValue(chars_, pos, node & 0x7fff); } else { entry_.Value = CharsTrie.ReadNodeValue(chars_, pos, node); } if (isFinal || (maxLength_ > 0 && str_.Length == maxLength_)) { pos_ = -1; } else { // We cannot skip the value right here because it shares its // lead unit with a match node which we have to evaluate // next time. // Instead, keep pos_ on the node lead unit itself. pos_ = pos - 1; skipValue_ = true; } entry_.Chars = str_.AsCharSequence(); return(entry_); } } if (maxLength_ > 0 && str_.Length == maxLength_) { return(TruncateAndStop()); } if (node < CharsTrie.kMinLinearMatch) { if (node == 0) { node = chars_[pos++]; } pos = BranchNext(pos, node + 1); if (pos < 0) { return(entry_); // Reached a final value. } } else { // Linear-match node, append length units to str_. int length = node - CharsTrie.kMinLinearMatch + 1; if (maxLength_ > 0 && str_.Length + length > maxLength_) { str_.Append(chars_, pos, maxLength_ - str_.Length); // ICU4N: (pos + maxLength_ - str_.Length) - pos == (maxLength_ - str_.Length) return(TruncateAndStop()); } str_.Append(chars_, pos, length); // ICU4N: (pos + length) - pos == length pos += length; } } }