org.codehaus.jackson.io.NumberOutput Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ehcache Show documentation
Show all versions of ehcache Show documentation
Ehcache is an open source, standards-based cache used to boost performance,
offload the database and simplify scalability. Ehcache is robust, proven and full-featured and
this has made it the most widely-used Java-based cache.
package org.codehaus.jackson.io;
public final class NumberOutput
{
private final static char NULL_CHAR = (char) 0;
private static int MILLION = 1000000;
private static int BILLION = 1000000000;
private static long TEN_BILLION_L = 10000000000L;
private static long THOUSAND_L = 1000L;
private static long MIN_INT_AS_LONG = (long) Integer.MIN_VALUE;
private static long MAX_INT_AS_LONG = (long) Integer.MAX_VALUE;
final static String SMALLEST_LONG = String.valueOf(Long.MIN_VALUE);
final static char[] LEADING_TRIPLETS = new char[4000];
final static char[] FULL_TRIPLETS = new char[4000];
static {
/* Let's fill it with NULLs for ignorable leading digits,
* and digit chars for others
*/
int ix = 0;
for (int i1 = 0; i1 < 10; ++i1) {
char f1 = (char) ('0' + i1);
char l1 = (i1 == 0) ? NULL_CHAR : f1;
for (int i2 = 0; i2 < 10; ++i2) {
char f2 = (char) ('0' + i2);
char l2 = (i1 == 0 && i2 == 0) ? NULL_CHAR : f2;
for (int i3 = 0; i3 < 10; ++i3) {
// Last is never to be empty
char f3 = (char) ('0' + i3);
LEADING_TRIPLETS[ix] = l1;
LEADING_TRIPLETS[ix+1] = l2;
LEADING_TRIPLETS[ix+2] = f3;
FULL_TRIPLETS[ix] = f1;
FULL_TRIPLETS[ix+1] = f2;
FULL_TRIPLETS[ix+2] = f3;
ix += 4;
}
}
}
}
final static byte[] FULL_TRIPLETS_B = new byte[4000];
static {
for (int i = 0; i < 4000; ++i) {
FULL_TRIPLETS_B[i] = (byte) FULL_TRIPLETS[i];
}
}
final static String[] sSmallIntStrs = new String[] {
"0","1","2","3","4","5","6","7","8","9","10"
};
final static String[] sSmallIntStrs2 = new String[] {
"-1","-2","-3","-4","-5","-6","-7","-8","-9","-10"
};
/*
/**********************************************************
/* Efficient serialization methods using raw buffers
/**********************************************************
*/
/**
* @return Offset within buffer after outputting int
*/
public static int outputInt(int value, char[] buffer, int offset)
{
if (value < 0) {
if (value == Integer.MIN_VALUE) {
/* Special case: no matching positive value within range;
* let's then "upgrade" to long and output as such.
*/
return outputLong((long) value, buffer, offset);
}
buffer[offset++] = '-';
value = -value;
}
if (value < MILLION) { // at most 2 triplets...
if (value < 1000) {
if (value < 10) {
buffer[offset++] = (char) ('0' + value);
} else {
offset = outputLeadingTriplet(value, buffer, offset);
}
} else {
int thousands = value / 1000;
value -= (thousands * 1000); // == value % 1000
offset = outputLeadingTriplet(thousands, buffer, offset);
offset = outputFullTriplet(value, buffer, offset);
}
return offset;
}
// ok, all 3 triplets included
/* Let's first hand possible billions separately before
* handling 3 triplets. This is possible since we know we
* can have at most '2' as billion count.
*/
boolean hasBillions = (value >= BILLION);
if (hasBillions) {
value -= BILLION;
if (value >= BILLION) {
value -= BILLION;
buffer[offset++] = '2';
} else {
buffer[offset++] = '1';
}
}
int newValue = value / 1000;
int ones = (value - (newValue * 1000)); // == value % 1000
value = newValue;
newValue /= 1000;
int thousands = (value - (newValue * 1000));
// value now has millions, which have 1, 2 or 3 digits
if (hasBillions) {
offset = outputFullTriplet(newValue, buffer, offset);
} else {
offset = outputLeadingTriplet(newValue, buffer, offset);
}
offset = outputFullTriplet(thousands, buffer, offset);
offset = outputFullTriplet(ones, buffer, offset);
return offset;
}
public static int outputInt(int value, byte[] buffer, int offset)
{
if (value < 0) {
if (value == Integer.MIN_VALUE) {
return outputLong((long) value, buffer, offset);
}
buffer[offset++] = '-';
value = -value;
}
if (value < MILLION) { // at most 2 triplets...
if (value < 1000) {
if (value < 10) {
buffer[offset++] = (byte) ('0' + value);
} else {
offset = outputLeadingTriplet(value, buffer, offset);
}
} else {
int thousands = value / 1000;
value -= (thousands * 1000); // == value % 1000
offset = outputLeadingTriplet(thousands, buffer, offset);
offset = outputFullTriplet(value, buffer, offset);
}
return offset;
}
boolean hasBillions = (value >= BILLION);
if (hasBillions) {
value -= BILLION;
if (value >= BILLION) {
value -= BILLION;
buffer[offset++] = '2';
} else {
buffer[offset++] = '1';
}
}
int newValue = value / 1000;
int ones = (value - (newValue * 1000)); // == value % 1000
value = newValue;
newValue /= 1000;
int thousands = (value - (newValue * 1000));
if (hasBillions) {
offset = outputFullTriplet(newValue, buffer, offset);
} else {
offset = outputLeadingTriplet(newValue, buffer, offset);
}
offset = outputFullTriplet(thousands, buffer, offset);
offset = outputFullTriplet(ones, buffer, offset);
return offset;
}
/**
* @return Offset within buffer after outputting int
*/
public static int outputLong(long value, char[] buffer, int offset)
{
// First: does it actually fit in an int?
if (value < 0L) {
/* MIN_INT is actually printed as long, just because its
* negation is not an int but long
*/
if (value > MIN_INT_AS_LONG) {
return outputInt((int) value, buffer, offset);
}
if (value == Long.MIN_VALUE) {
// Special case: no matching positive value within range
int len = SMALLEST_LONG.length();
SMALLEST_LONG.getChars(0, len, buffer, offset);
return (offset + len);
}
buffer[offset++] = '-';
value = -value;
} else {
if (value <= MAX_INT_AS_LONG) {
return outputInt((int) value, buffer, offset);
}
}
/* Ok: real long print. Need to first figure out length
* in characters, and then print in from end to beginning
*/
int origOffset = offset;
offset += calcLongStrLength(value);
int ptr = offset;
// First, with long arithmetics:
while (value > MAX_INT_AS_LONG) { // full triplet
ptr -= 3;
long newValue = value / THOUSAND_L;
int triplet = (int) (value - newValue * THOUSAND_L);
outputFullTriplet(triplet, buffer, ptr);
value = newValue;
}
// Then with int arithmetics:
int ivalue = (int) value;
while (ivalue >= 1000) { // still full triplet
ptr -= 3;
int newValue = ivalue / 1000;
int triplet = ivalue - (newValue * 1000);
outputFullTriplet(triplet, buffer, ptr);
ivalue = newValue;
}
// And finally, if anything remains, partial triplet
outputLeadingTriplet(ivalue, buffer, origOffset);
return offset;
}
public static int outputLong(long value, byte[] buffer, int offset)
{
if (value < 0L) {
if (value > MIN_INT_AS_LONG) {
return outputInt((int) value, buffer, offset);
}
if (value == Long.MIN_VALUE) {
// Special case: no matching positive value within range
int len = SMALLEST_LONG.length();
for (int i = 0; i < len; ++i) {
buffer[offset++] = (byte) SMALLEST_LONG.charAt(i);
}
return offset;
}
buffer[offset++] = '-';
value = -value;
} else {
if (value <= MAX_INT_AS_LONG) {
return outputInt((int) value, buffer, offset);
}
}
int origOffset = offset;
offset += calcLongStrLength(value);
int ptr = offset;
// First, with long arithmetics:
while (value > MAX_INT_AS_LONG) { // full triplet
ptr -= 3;
long newValue = value / THOUSAND_L;
int triplet = (int) (value - newValue * THOUSAND_L);
outputFullTriplet(triplet, buffer, ptr);
value = newValue;
}
// Then with int arithmetics:
int ivalue = (int) value;
while (ivalue >= 1000) { // still full triplet
ptr -= 3;
int newValue = ivalue / 1000;
int triplet = ivalue - (newValue * 1000);
outputFullTriplet(triplet, buffer, ptr);
ivalue = newValue;
}
outputLeadingTriplet(ivalue, buffer, origOffset);
return offset;
}
/*
/**********************************************************
/* Secondary convenience serialization methods
/**********************************************************
*/
/* !!! 05-Aug-2008, tatus: Any ways to further optimize
* these? (or need: only called by diagnostics methods?)
*/
public static String toString(int value)
{
// Lookup table for small values
if (value < sSmallIntStrs.length) {
if (value >= 0) {
return sSmallIntStrs[value];
}
int v2 = -value - 1;
if (v2 < sSmallIntStrs2.length) {
return sSmallIntStrs2[v2];
}
}
return Integer.toString(value);
}
public static String toString(long value)
{
if (value <= Integer.MAX_VALUE &&
value >= Integer.MIN_VALUE) {
return toString((int) value);
}
return Long.toString(value);
}
public static String toString(double value)
{
return Double.toString(value);
}
/*
/**********************************************************
/* Internal methods
/**********************************************************
*/
private static int outputLeadingTriplet(int triplet, char[] buffer, int offset)
{
int digitOffset = (triplet << 2);
char c = LEADING_TRIPLETS[digitOffset++];
if (c != NULL_CHAR) {
buffer[offset++] = c;
}
c = LEADING_TRIPLETS[digitOffset++];
if (c != NULL_CHAR) {
buffer[offset++] = c;
}
// Last is required to be non-empty
buffer[offset++] = LEADING_TRIPLETS[digitOffset];
return offset;
}
private static int outputLeadingTriplet(int triplet, byte[] buffer, int offset)
{
int digitOffset = (triplet << 2);
char c = LEADING_TRIPLETS[digitOffset++];
if (c != NULL_CHAR) {
buffer[offset++] = (byte) c;
}
c = LEADING_TRIPLETS[digitOffset++];
if (c != NULL_CHAR) {
buffer[offset++] = (byte) c;
}
// Last is required to be non-empty
buffer[offset++] = (byte) LEADING_TRIPLETS[digitOffset];
return offset;
}
private static int outputFullTriplet(int triplet, char[] buffer, int offset)
{
int digitOffset = (triplet << 2);
buffer[offset++] = FULL_TRIPLETS[digitOffset++];
buffer[offset++] = FULL_TRIPLETS[digitOffset++];
buffer[offset++] = FULL_TRIPLETS[digitOffset];
return offset;
}
private static int outputFullTriplet(int triplet, byte[] buffer, int offset)
{
int digitOffset = (triplet << 2);
buffer[offset++] = FULL_TRIPLETS_B[digitOffset++];
buffer[offset++] = FULL_TRIPLETS_B[digitOffset++];
buffer[offset++] = FULL_TRIPLETS_B[digitOffset];
return offset;
}
/**
*
* Pre-conditions: posValue is positive, and larger than
* Integer.MAX_VALUE (about 2 billions).
*/
private static int calcLongStrLength(long posValue)
{
int len = 10;
long comp = TEN_BILLION_L;
// 19 is longest, need to worry about overflow
while (posValue >= comp) {
if (len == 19) {
break;
}
++len;
comp = (comp << 3) + (comp << 1); // 10x
}
return len;
}
}