Skip to content

Commit

Permalink
Perf Imp 2
Browse files Browse the repository at this point in the history
  • Loading branch information
sathishk committed Mar 2, 2024
1 parent 4d04c82 commit 92ac595
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 292 deletions.
337 changes: 46 additions & 291 deletions src/main/java/com/techatpark/sjson/core/NumberParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,92 +5,11 @@
import java.math.BigDecimal;
import java.math.BigInteger;

import static com.techatpark.sjson.core.util.ReaderUtil.isSpace;

/**
* Parser for Numbers.
*/
public final class NumberParser {

/**
* Number 1.
*/
private static final int ONE = 1;
/**
* Number 2.
*/
private static final int TWO = 2;
/**
* Number 3.
*/
private static final int THREE = 3;
/**
* Number 4.
*/
private static final int FOUR = 4;
/**
* Number 5.
*/
private static final int FIVE = 5;
/**
* Number 6.
*/
private static final int SIX = 6;
/**
* Number 7.
*/
private static final int SEVEN = 7;
/**
* Number 8.
*/
private static final int EIGHT = 8;
/**
* Number 9.
*/
private static final int NINE = 9;
/**
* Number 10.
*/
private static final int TEN = 10;
/**
* Number 11.
*/
private static final int ELEVEN = 11;
/**
* Number 12.
*/
private static final int TWELVE = 12;
/**
* Number 13.
*/
private static final int THIRTEEN = 13;
/**
* Number 14.
*/
private static final int FOURTEEN = 14;
/**
* Number 15.
*/
private static final int FIFTEEN = 15;
/**
* Number 16.
*/
private static final int SIXTEEN = 16;
/**
* Number 17.
*/
private static final int SEVENTEEN = 17;
/**
* Number 18.
*/
private static final int EIGHTEEN = 18;
/**
* Number 19.
*/
private static final int NINETEEN = 19;



/**
* Utility Class.
*/
Expand All @@ -112,224 +31,60 @@ public static Number getNumber(
final Reader reader,
final char startingChar)
throws IOException {

final StringBuilder builder = new StringBuilder(TEN);
char character = (char) reader.read();

// Happy Case : Read AllDigits before . character
while (Character.isDigit(character)) {
builder.append(character);
character = (char) reader.read();
}

// Maybe a double ?!
if (character == '.' || character == 'e' || character == 'E') {
// Decimal Number
if (character == '.') {
StringBuilder decimals = new StringBuilder(TEN);
while ((character = (char) reader.read()) != ','
&& (Character.isDigit(character)
|| character == '-'
|| character == '+'
|| character == 'e'
|| character == 'E')
&& character != '}'
&& character != ']'
&& !isSpace(character)) {
decimals.append(character);
}
contentExtractor.setCursor(character);
return getDecimalNumber(startingChar, builder, decimals);
} else { // Exponential Non Decimal Number
builder.append(character);
while ((character = (char) reader.read()) != ','
&& (Character.isDigit(character)
|| character == '-'
|| character == '+'
|| character == 'e'
|| character == 'E')
&& character != '}'
&& character != ']'
&& !isSpace(character)) {
builder.append(character);
}
contentExtractor.setCursor(character);
return getExponentialNumber(startingChar, builder);
}
} else {
contentExtractor.setCursor(character);
return buildNumber(startingChar, builder);
}
}


/**
* Gets Compact Number of a source String.
* @param source
* @param isNegative
* @return Byte, Short, Integer, Long or BigInteger
*/
private static Number parseNumber(final String source,
final boolean isNegative) {
return switch (source.length()) {
case ONE, TWO
-> isNegative ? (byte) -Byte.parseByte(source)
: Byte.parseByte(source);
case THREE -> getByteOrShort(source, isNegative);
case FOUR -> isNegative ? (short) -Short.parseShort(source)
: Short.parseShort(source);
case FIVE -> getShortOrInteger(source, isNegative);
case SIX, SEVEN, EIGHT, NINE
-> isNegative ? -Integer.parseUnsignedInt(source)
: Integer.parseUnsignedInt(source);
case TEN -> getIntegerOrLong(source, isNegative);
case ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN, SEVENTEEN,
SIXTEEN, EIGHTEEN -> isNegative
? -Long.parseUnsignedLong(source)
: Long.parseUnsignedLong(source);
case NINETEEN -> getLongOrBigNumber(source, isNegative);
default -> isNegative ? new BigInteger("-" + source)
: new BigInteger(source);
};
}



private static Number getByteOrShort(final String source,
final boolean isNegative) {
short aShort = Short.parseShort(source);
if (isNegative) {
aShort = (short) -aShort;
if (aShort >= Byte.MIN_VALUE) {
return (byte) aShort;
}
return aShort;
} else {
if (aShort <= Byte.MAX_VALUE) {
return (byte) aShort;
}
return aShort;
final StringBuilder numberBuilder = new StringBuilder(10);
numberBuilder.append(startingChar);
int read = reader.read();
char charactor = (char) read;
while (read != -1
&& charactor != ','
&& charactor != '}'
&& charactor != ']') {
numberBuilder.append(charactor);
read = reader.read();
charactor = (char) read;
}
}

private static Number getShortOrInteger(final String source,
final boolean isNegative) {
int integer = Integer.parseUnsignedInt(source);
if (isNegative) {
integer = -integer;
if (integer >= Short.MIN_VALUE) {
return (short) integer;
}
return integer;
} else {
if (integer <= Short.MAX_VALUE) {
return (short) integer;
}
return integer;
}
}

private static Number getIntegerOrLong(final String source,
final boolean isNegative) {
long aLong = Long.parseUnsignedLong(source);
if (isNegative) {
aLong = -aLong;
if (aLong >= Integer.MIN_VALUE) {
return (int) aLong;
}
return aLong;
} else {
if (aLong <= Integer.MAX_VALUE) {
return (int) aLong;
}
return aLong;
}
contentExtractor.setCursor(charactor);
return build(numberBuilder);
}

private static Number getLongOrBigNumber(final String source,
final boolean isNegative) {
BigInteger bigInteger = new BigInteger(source);
if (isNegative) {
bigInteger = bigInteger.multiply(new BigInteger("-1"));
if (bigInteger.compareTo(BigInteger.valueOf(Long.MIN_VALUE)) > -1) {
return bigInteger.longValue();
}
return bigInteger;
} else {
if (bigInteger.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > -1) {
return bigInteger.longValue();
}
return bigInteger;
}
}

/**
* Gets Compact decimal Number of a source String.
* @param source
* @return Float,Double or BigDecimal
*/
private static Number parseDecimalNumber(final String source) {
BigDecimal bigDecimal = new BigDecimal(source);
// TODO Better Way to check if this is float / double
private static Number build(final StringBuilder numberBuilder) {
String numberStr = numberBuilder.toString().trim();
try {
if (bigDecimal
.equals(new BigDecimal(
Float.toString(bigDecimal.floatValue())))) {
return bigDecimal.floatValue();
}
if (bigDecimal
.equals(BigDecimal.valueOf(bigDecimal.doubleValue()))) {
return bigDecimal.doubleValue();
// Try to parse as different types based on the range
if (numberStr.contains(".")) {
// Check if the number is a decimal
double doubleValue = Double.parseDouble(numberStr);
if (doubleValue >= Float.MIN_VALUE
&& doubleValue <= Float.MAX_VALUE) {
return (float) doubleValue;
} else {
return doubleValue;
}
} else {
// Check if the number is an integer
long longValue = Long.parseLong(numberStr);
if (longValue >= Byte.MIN_VALUE
&& longValue <= Byte.MAX_VALUE) {
return (byte) longValue;
} else if (longValue >= Short.MIN_VALUE
&& longValue <= Short.MAX_VALUE) {
return (short) longValue;
} else if (longValue >= Integer.MIN_VALUE
&& longValue <= Integer.MAX_VALUE) {
return (int) longValue;
} else if (longValue <= Long.MAX_VALUE) {
return longValue;
} else {
// For very large integers, use BigInteger
return new BigInteger(numberStr);
}
}
} catch (java.lang.NumberFormatException ne) {
return bigDecimal;
} catch (NumberFormatException e) {
// If parsing fails, return BigDecimal
return new BigDecimal(numberStr);
}
return bigDecimal;
}

/**
* Gets Decimal Number from the String.
*
* @param decimal
* @param startingChar
* @param builder
* @return number
*/
private static Number getDecimalNumber(final char startingChar,
final StringBuilder builder,
final StringBuilder decimal) {
return parseDecimalNumber(startingChar
+ builder.toString() + "." + decimal.toString());
}

/**
* Builds Number from the String.
*
* @param startingChar
* @param builder
* @return number
*/
private static Number buildNumber(final char startingChar,
final StringBuilder builder) {
return switch (startingChar) {
case '-' -> parseNumber(builder.toString(), true);
case '+' -> parseNumber(builder.toString(), false);
default -> parseNumber(builder
.insert(0, startingChar)
.toString(), false);
};
}

/**
* Gets Decimal Exponential from the String.
*
* @param startingChar
* @param builder
* @return number
*/
private static Number getExponentialNumber(final char startingChar,
final StringBuilder builder) {
return new BigDecimal(startingChar + builder.toString());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,10 @@ private static List<Number> numbers() {
@ParameterizedTest
@ValueSource(strings = {
"2,1",
"2.5,1"
"2,\n\t1",
"2 ,\n\t1",
"2.5,1",
"2.5\n\t, 1"
})
void testCursor(final String validjson) throws IOException {
StringReader reader = new StringReader(validjson);
Expand Down

0 comments on commit 92ac595

Please sign in to comment.