private static int parseInt(
      FastSimpleStringBufferForCSVProcessorAndJSONParser s, int startIndex, int strLen)
      throws ParseException {
    if (startIndex == strLen)
      throw new ParseException(
          "Failed to parse '" + s.toString() + "' at offset " + startIndex, startIndex);

    int res = 0;
    final boolean isNegative;
    int i = startIndex;
    if (s.charAt(i) == '-') {
      isNegative = true;
      i++;
    } else {
      isNegative = false;
    }
    int intValue = 0;
    for (; i < strLen; i++) {
      final char ch = s.charAt(i);
      if (ch < '0' || ch > '9') {
        throw new ParseException("Failed to parse '" + s.toString() + "' at offset " + i, i);
      } else {
        int val = ch - '0';
        intValue = intValue * 10 + val;
      }
    }
    return isNegative ? (-1 * intValue) : intValue;
  }
  public static double parseDouble(final FastSimpleStringBufferForCSVProcessorAndJSONParser s)
      throws ParseException {
    final int strLen = s.length();
    if (strLen == 0) return Double.NaN;

    final double toReturn =
        strLen <= 9 ? parseUsingIntValue(s, strLen) : parseUsingLongValue(s, strLen);
    if (kDEBUG_VERSUS_JAVA_PARSING) {
      final double alternative = Double.parseDouble(s.toString());
      if (toReturn != alternative)
        throw new IllegalArgumentException(
            s.toString() + " parsed differently! " + toReturn + " vs java " + alternative);
    }
    return toReturn;
  }
  private static double parseUsingIntValue(
      FastSimpleStringBufferForCSVProcessorAndJSONParser s, int strLen) throws ParseException {
    final boolean isNegative;
    int i;
    if (s.charAt(0) == '-') {
      isNegative = true;
      i = 1;
    } else {
      isNegative = false;
      i = 0;
    }
    int intValue = 0;
    int exp = 0;
    int expDelta = 0;
    int numDigits = 0;
    for (; i < strLen; i++) {
      final char ch = s.charAt(i);
      if (ch == '.') {
        if (expDelta == -1)
          throw new ParseException("Failed to parse '" + s.toString() + "' at offset " + i, i);
        expDelta = -1;
      } else if (ch == 'E') {
        exp += parseInt(s, i + 1, strLen);
        i = strLen;
      } else if (ch < '0' || ch > '9') {
        throw new ParseException("Failed to parse '" + s.toString() + "' at offset " + i, i);
      } else {
        int val = ch - '0';
        intValue = intValue * 10 + val;
        exp += expDelta;
        numDigits++;
      }
    }

    if (numDigits == 0) throw new ParseException("Failed to parse '" + s.toString() + "'", 0);

    // todo: we can probably optimize converToDouble knowing that it's of limited size.
    return convertToDouble(intValue, exp, isNegative, numDigits);
  }
  private static double parseUsingLongValue(
      FastSimpleStringBufferForCSVProcessorAndJSONParser s, int strLen) throws ParseException {
    // If the string is ridiculously long, long type is not enough to hold the mantissa.
    // In such case, use java built in double parser as we are not likely to see those numbers
    // anyway...
    if (strLen >= 18) return Double.parseDouble(s.toString());

    final boolean isNegative;
    int i;
    if (s.charAt(0) == '-') {
      isNegative = true;
      i = 1;
    } else {
      isNegative = false;
      i = 0;
    }
    long longValue = 0;
    int exp = 0;
    int expDelta = 0;
    int numDigits = 0;
    for (; i < strLen; i++) {
      final char ch = s.charAt(i);
      if (ch == '.') {
        if (expDelta == -1)
          throw new ParseException("Failed to parse '" + s.toString() + "' at offset " + i, i);
        expDelta = -1;
      } else if (ch == 'E') {
        exp += parseInt(s, i + 1, strLen);
        i = strLen;
      } else if (ch < '0' || ch > '9') {
        throw new ParseException("Failed to parse '" + s.toString() + "' at offset " + i, i);
      } else {
        int val = ch - '0';
        longValue = longValue * 10 + val;
        exp += expDelta;
        numDigits++;
      }
    }

    if (numDigits == 0) throw new ParseException("Failed to parse '" + s.toString() + "'", 0);

    return convertToDouble((double) longValue, exp, isNegative, numDigits);
  }