public static boolean fastSetFromBytes()

in kyuubi-hive-jdbc/src/main/java/org/apache/kyuubi/jdbc/hive/common/FastHiveDecimalImpl.java [262:681]


  public static boolean fastSetFromBytes(
      byte[] bytes, int offset, int length, boolean trimBlanks, FastHiveDecimal fastResult) {

    final int bytesLength = bytes.length;

    if (offset < 0 || offset >= bytesLength) {
      return false;
    }
    final int end = offset + length;
    if (end <= offset || end > bytesLength) {
      return false;
    }

    // We start here with at least one byte.
    int index = offset;

    if (trimBlanks) {
      while (bytes[index] == BYTE_BLANK) {
        if (++index >= end) {
          return false;
        }
      }
    }

    // Started with a few ideas from BigDecimal(char[] in, int offset, int len) constructor...
    // But soon became very fast decimal specific.

    boolean isNegative = false;
    if (bytes[index] == BYTE_MINUS) {
      isNegative = true;
      if (++index >= end) {
        return false;
      }
    } else if (bytes[index] == BYTE_PLUS) {
      if (++index >= end) {
        return false;
      }
    }

    int precision = 0;

    // We fill starting with highest digit in highest longword (HIGHWORD_DECIMAL_DIGITS) and
    // move down.  At end will will shift everything down if necessary.

    int longWordIndex = 0; // Where 0 is the highest longword; 1 is middle longword, etc.

    int digitNum = HIGHWORD_DECIMAL_DIGITS;
    long multiplier = powerOfTenTable[HIGHWORD_DECIMAL_DIGITS - 1];

    int digitValue = 0;
    long longWord = 0;

    long fast0 = 0;
    long fast1 = 0;
    long fast2 = 0;

    byte work;

    // Parse integer portion.

    boolean haveInteger = false;
    while (true) {
      work = bytes[index];
      if (work < BYTE_DIGIT_ZERO || work > BYTE_DIGIT_NINE) {
        break;
      }
      haveInteger = true;
      if (precision == 0 && work == BYTE_DIGIT_ZERO) {
        // Ignore leading zeroes.
        if (++index >= end) {
          break;
        }
        continue;
      }
      digitValue = work - BYTE_DIGIT_ZERO;
      if (digitNum == 0) {

        // Integer parsing move to next lower longword.

        // Save previous longword.
        if (longWordIndex == 0) {
          fast2 = longWord;
        } else if (longWordIndex == 1) {
          fast1 = longWord;
        } else if (longWordIndex == 2) {

          // We have filled HiveDecimal.MAX_PRECISION digits and have no more room in our limit
          // precision
          // fast decimal.
          return false;
        }
        longWordIndex++;

        // The middle and lowest longwords highest digit number is LONGWORD_DECIMAL_DIGITS.
        digitNum = LONGWORD_DECIMAL_DIGITS;
        multiplier = powerOfTenTable[LONGWORD_DECIMAL_DIGITS - 1];
        longWord = 0;
      }
      longWord += digitValue * multiplier;
      multiplier /= 10;
      digitNum--;
      precision++;
      if (++index >= end) {
        break;
      }
    }

    // At this point we may have parsed an integer.

    // Try to eat a dot now since it could be the end.  We remember if we saw a dot so we can
    // do error checking later and detect just a dot.
    boolean sawDot = false;
    if (index < end && bytes[index] == BYTE_DOT) {
      sawDot = true;
      index++;
    }

    // Try to eat trailing blank padding.
    if (trimBlanks && index < end && bytes[index] == BYTE_BLANK) {
      index++;
      while (index < end && bytes[index] == BYTE_BLANK) {
        index++;
      }
      if (index < end) {
        // Junk after trailing blank padding.
        return false;
      }
      // Otherwise, fall through and process the what we saw before possible trailing blanks.
    }

    // Any more input?
    if (index >= end) {

      // We hit the end after getting optional integer and optional dot and optional blank padding.

      if (!haveInteger) {
        return false;
      }

      if (precision == 0) {

        // We just had leading zeroes (and possibly a dot and trailing blanks).
        // Value is 0.
        return true;
      }
      // Save last longword.
      if (longWordIndex == 0) {
        fast2 = longWord;
      } else if (longWordIndex == 1) {
        fast1 = longWord;
      } else {
        fast0 = longWord;
      }
      fastResult.fastSignum = (isNegative ? -1 : 1);
      fastResult.fastIntegerDigitCount = precision;
      fastResult.fastScale = 0;
      final int scaleDown = HiveDecimal.MAX_PRECISION - precision;
      if (scaleDown > 0) {
        doFastScaleDown(fast0, fast1, fast2, scaleDown, fastResult);
      } else {
        fastResult.fast0 = fast0;
        fastResult.fast1 = fast1;
        fastResult.fast2 = fast2;
      }
      return true;
    }

    // We have more input but did we start with something valid?
    if (!haveInteger && !sawDot) {

      // Must have one of those at this point.
      return false;
    }

    int integerDigitCount = precision;

    int nonTrailingZeroScale = 0;
    boolean roundingNecessary = false;
    if (sawDot) {

      // Parse fraction portion.

      while (true) {
        work = bytes[index];
        if (work < BYTE_DIGIT_ZERO || work > BYTE_DIGIT_NINE) {
          if (!haveInteger) {

            // Naked dot.
            return false;
          }
          break;
        }
        digitValue = work - BYTE_DIGIT_ZERO;
        if (digitNum == 0) {

          // Fraction digit parsing move to next lower longword.

          // Save previous longword.
          if (longWordIndex == 0) {
            fast2 = longWord;
          } else if (longWordIndex == 1) {
            fast1 = longWord;
          } else if (longWordIndex == 2) {

            // We have filled HiveDecimal.MAX_PRECISION digits and have no more room in our limit
            // precision
            // fast decimal.  However, since we are processing fractional digits, we do rounding.
            // away.
            if (digitValue >= 5) {
              roundingNecessary = true;
            }

            // Scan through any remaining digits...
            while (++index < end) {
              work = bytes[index];
              if (work < BYTE_DIGIT_ZERO || work > BYTE_DIGIT_NINE) {
                break;
              }
            }
            break;
          }
          longWordIndex++;
          digitNum = LONGWORD_DECIMAL_DIGITS;
          multiplier = powerOfTenTable[digitNum - 1];
          longWord = 0;
        }
        longWord += digitValue * multiplier;
        multiplier /= 10;
        digitNum--;
        precision++;
        if (digitValue != 0) {
          nonTrailingZeroScale = precision - integerDigitCount;
        }
        if (++index >= end) {
          break;
        }
      }
    }

    boolean haveExponent = false;
    if (index < end
        && (bytes[index] == BYTE_EXPONENT_UPPER || bytes[index] == BYTE_EXPONENT_LOWER)) {
      haveExponent = true;
      index++;
      if (index >= end) {
        // More required.
        return false;
      }
    }

    // At this point we have a number.  Save it in fastResult.  Round it.  If we have an exponent,
    // we will do a power 10 operation on fastResult.

    // Save last longword.
    if (longWordIndex == 0) {
      fast2 = longWord;
    } else if (longWordIndex == 1) {
      fast1 = longWord;
    } else {
      fast0 = longWord;
    }

    int trailingZeroesScale = precision - integerDigitCount;
    if (integerDigitCount == 0 && nonTrailingZeroScale == 0) {
      // Zero(es).
    } else {
      fastResult.fastSignum = (isNegative ? -1 : 1);
      fastResult.fastIntegerDigitCount = integerDigitCount;
      fastResult.fastScale = nonTrailingZeroScale;
      final int trailingZeroCount = trailingZeroesScale - fastResult.fastScale;
      final int scaleDown = HiveDecimal.MAX_PRECISION - precision + trailingZeroCount;
      if (scaleDown > 0) {
        doFastScaleDown(fast0, fast1, fast2, scaleDown, fastResult);
      } else {
        fastResult.fast0 = fast0;
        fastResult.fast1 = fast1;
        fastResult.fast2 = fast2;
      }
    }

    if (roundingNecessary) {

      if (fastResult.fastSignum == 0) {
        fastResult.fastSignum = (isNegative ? -1 : 1);
        fastResult.fast0 = 1;
        fastResult.fastIntegerDigitCount = 0;
        fastResult.fastScale = HiveDecimal.MAX_SCALE;
      } else {
        if (!fastAdd(
            fastResult.fastSignum,
            fastResult.fast0,
            fastResult.fast1,
            fastResult.fast2,
            fastResult.fastIntegerDigitCount,
            fastResult.fastScale,
            fastResult.fastSignum,
            1,
            0,
            0,
            0,
            trailingZeroesScale,
            fastResult)) {
          return false;
        }
      }
    }

    if (!haveExponent) {

      // Try to eat trailing blank padding.
      if (trimBlanks && index < end && bytes[index] == BYTE_BLANK) {
        index++;
        while (index < end && bytes[index] == BYTE_BLANK) {
          index++;
        }
      }
      if (index < end) {
        // Junk after trailing blank padding.
        return false;
      }
      return true;
    }

    // At this point, we have seen the exponent letter E or e and have decimal information as:
    //     isNegative, precision, integerDigitCount, nonTrailingZeroScale, and
    //     fast0, fast1, fast2.
    //
    // After we determine the exponent, we will do appropriate scaling and fill in fastResult.

    boolean isExponentNegative = false;
    if (bytes[index] == BYTE_MINUS) {
      isExponentNegative = true;
      if (++index >= end) {
        return false;
      }
    } else if (bytes[index] == BYTE_PLUS) {
      if (++index >= end) {
        return false;
      }
    }

    long exponent = 0;
    multiplier = 1;
    while (true) {
      work = bytes[index];
      if (work < BYTE_DIGIT_ZERO || work > BYTE_DIGIT_NINE) {
        break;
      }
      if (multiplier > 10) {
        // Power of ten way beyond our precision/scale...
        return false;
      }
      digitValue = work - BYTE_DIGIT_ZERO;
      if (digitValue != 0 || exponent != 0) {
        exponent = exponent * 10 + digitValue;
        multiplier *= 10;
      }
      if (++index >= end) {
        break;
      }
    }
    if (isExponentNegative) {
      exponent = -exponent;
    }

    // Try to eat trailing blank padding.
    if (trimBlanks && index < end && bytes[index] == BYTE_BLANK) {
      index++;
      while (index < end && bytes[index] == BYTE_BLANK) {
        index++;
      }
    }
    if (index < end) {
      // Junk after exponent.
      return false;
    }

    if (integerDigitCount == 0 && nonTrailingZeroScale == 0) {
      // Zero(es).
      return true;
    }

    if (exponent == 0) {

      // No effect since 10^0 = 1.

    } else {

      // We for these input with exponents, we have at this point an intermediate decimal,
      // an exponent power, and a result:
      //
      //                     intermediate
      //   input               decimal      exponent        result
      // 701E+1            701 scale 0        +1            7010 scale 0
      // 3E+4              3 scale 0          +4               3 scale 0
      // 3.223E+9          3.223 scale 3      +9      3223000000 scale 0
      // 0.009E+10         0.009 scale 4      +10       90000000 scale 0
      // 0.3221E-2         0.3221 scale 4     -2               0.003221 scale 6
      // 0.00223E-20       0.00223 scale 5    -20              0.0000000000000000000000223 scale 25
      //

      if (!fastScaleByPowerOfTen(fastResult, (int) exponent, fastResult)) {
        return false;
      }
    }

    final int trailingZeroCount =
        fastTrailingDecimalZeroCount(
            fastResult.fast0,
            fastResult.fast1,
            fastResult.fast2,
            fastResult.fastIntegerDigitCount,
            fastResult.fastScale);
    if (trailingZeroCount > 0) {
      doFastScaleDown(fastResult, trailingZeroCount, fastResult);
      fastResult.fastScale -= trailingZeroCount;
    }

    return true;
  }