private long readNumber()

in solr/solrj/src/java/org/noggit/JSONParser.java [477:570]


  private long readNumber(int firstChar, boolean isNeg) throws IOException {
    out.unsafeWrite(firstChar); // unsafe OK since we know output is big enough
    // We build up the number in the negative plane since it's larger (by one) than
    // the positive plane.
    long v = (long) '0' - firstChar;
    // can't overflow a long in 18 decimal digits (i.e. 17 additional after the first).
    // we also need 22 additional to handle double, so we'll handle in 2 separate loops.
    int i;
    for (i = 0; i < 17; i++) {
      int ch = getChar();
      // TODO: is this switch faster as an if-then-else?
      switch (ch) {
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
          v = v * 10 - (ch - '0');
          out.unsafeWrite(ch);
          continue;
        case '.':
          out.unsafeWrite('.');
          valstate = readFrac(out, 22 - i);
          return 0;
        case 'e':
        case 'E':
          out.unsafeWrite(ch);
          nstate = 0;
          valstate = readExp(out, 22 - i);
          return 0;
        default:
          // return the number, relying on nextEvent() to return an error
          // for invalid chars following the number.
          if (ch != -1) --start; // push back last char if not EOF

          valstate = LONG;
          return isNeg ? v : -v;
      }
    }

    // after this, we could overflow a long and need to do extra checking
    boolean overflow = false;
    long maxval = isNeg ? Long.MIN_VALUE : -Long.MAX_VALUE;

    for (; i < 22; i++) {
      int ch = getChar();
      switch (ch) {
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
          if (v < (0x8000000000000000L / 10))
            overflow = true; // can't multiply by 10 w/o overflowing
          v *= 10;
          int digit = ch - '0';
          if (v < maxval + digit) overflow = true; // can't add digit w/o overflowing
          v -= digit;
          out.unsafeWrite(ch);
          continue;
        case '.':
          out.unsafeWrite('.');
          valstate = readFrac(out, 22 - i);
          return 0;
        case 'e':
        case 'E':
          out.unsafeWrite(ch);
          nstate = 0;
          valstate = readExp(out, 22 - i);
          return 0;
        default:
          // return the number, relying on nextEvent() to return an error
          // for invalid chars following the number.
          if (ch != -1) --start; // push back last char if not EOF

          valstate = overflow ? BIGNUMBER : LONG;
          return isNeg ? v : -v;
      }
    }

    nstate = 0;
    valstate = BIGNUMBER;
    return 0;
  }