summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/com/amazon/carbonado/raw/DataDecoder.java57
-rw-r--r--src/main/java/com/amazon/carbonado/raw/DataEncoder.java150
2 files changed, 148 insertions, 59 deletions
diff --git a/src/main/java/com/amazon/carbonado/raw/DataDecoder.java b/src/main/java/com/amazon/carbonado/raw/DataDecoder.java
index 5ea5c1d..407df0c 100644
--- a/src/main/java/com/amazon/carbonado/raw/DataDecoder.java
+++ b/src/main/java/com/amazon/carbonado/raw/DataDecoder.java
@@ -18,6 +18,7 @@
package com.amazon.carbonado.raw;
+import java.math.BigDecimal;
import java.math.BigInteger;
import java.io.EOFException;
@@ -391,6 +392,62 @@ public class DataDecoder {
}
/**
+ * Decodes a BigDecimal.
+ *
+ * @param src source of encoded data
+ * @param srcOffset offset into encoded data
+ * @param valueRef decoded BigDecimal is stored in element 0, which may be null
+ * @return amount of bytes read from source
+ * @throws CorruptEncodingException if source data is corrupt
+ * @since 1.2
+ */
+ public static int decode(byte[] src, int srcOffset, BigDecimal[] valueRef)
+ throws CorruptEncodingException
+ {
+ try {
+ final int originalOffset = srcOffset;
+
+ int b = src[srcOffset++] & 0xff;
+ if (b >= 0xf8) {
+ valueRef[0] = null;
+ return 1;
+ }
+
+ int scale;
+ if (b <= 0x7f) {
+ scale = b;
+ } else if (b <= 0xbf) {
+ scale = ((b & 0x3f) << 8) | (src[srcOffset++] & 0xff);
+ } else if (b <= 0xdf) {
+ scale = ((b & 0x1f) << 16) | ((src[srcOffset++] & 0xff) << 8) |
+ (src[srcOffset++] & 0xff);
+ } else if (b <= 0xef) {
+ scale = ((b & 0x0f) << 24) | ((src[srcOffset++] & 0xff) << 16) |
+ ((src[srcOffset++] & 0xff) << 8) | (src[srcOffset++] & 0xff);
+ } else {
+ scale = ((src[srcOffset++] & 0xff) << 24) |
+ ((src[srcOffset++] & 0xff) << 16) |
+ ((src[srcOffset++] & 0xff) << 8) | (src[srcOffset++] & 0xff);
+ }
+
+ if ((scale & 1) != 0) {
+ scale = (~(scale >> 1)) | (1 << 31);
+ } else {
+ scale >>>= 1;
+ }
+
+ BigInteger[] unscaledRef = new BigInteger[1];
+ int amt = decode(src, srcOffset, unscaledRef);
+
+ valueRef[0] = new BigDecimal(unscaledRef[0], scale);
+
+ return (srcOffset + amt) - originalOffset;
+ } catch (IndexOutOfBoundsException e) {
+ throw new CorruptEncodingException(null, e);
+ }
+ }
+
+ /**
* Decodes the given byte array.
*
* @param src source of encoded data
diff --git a/src/main/java/com/amazon/carbonado/raw/DataEncoder.java b/src/main/java/com/amazon/carbonado/raw/DataEncoder.java
index 7f4f5d3..4b6cab4 100644
--- a/src/main/java/com/amazon/carbonado/raw/DataEncoder.java
+++ b/src/main/java/com/amazon/carbonado/raw/DataEncoder.java
@@ -18,6 +18,7 @@
package com.amazon.carbonado.raw;
+import java.math.BigDecimal;
import java.math.BigInteger;
import java.io.IOException;
@@ -328,7 +329,7 @@ public class DataEncoder {
byte[] bytes = value.toByteArray();
// Write the byte array length first, in a variable amount of bytes.
- int amt = encodeLength(bytes.length, dst, dstOffset);
+ int amt = encodeUnsignedVarInt(bytes.length, dst, dstOffset);
// Now write the byte array.
System.arraycopy(bytes, 0, dst, dstOffset + amt, bytes.length);
@@ -347,20 +348,42 @@ public class DataEncoder {
if (value == null) {
return 1;
}
-
int byteCount = (value.bitLength() >> 3) + 1;
+ return unsignedVarIntLength(byteCount) + byteCount;
+ }
- if (byteCount < 128) {
- return 1 + byteCount;
- } else if (byteCount < 16384) {
- return 2 + byteCount;
- } else if (byteCount < 2097152) {
- return 3 + byteCount;
- } else if (byteCount < 268435456) {
- return 4 + byteCount;
- } else {
- return 5 + byteCount;
+ /**
+ * Encodes the given optional BigDecimal into a variable amount of
+ * bytes. If the BigDecimal is null, exactly 1 byte is written. Otherwise,
+ * the amount written can be determined by calling calculateEncodedLength.
+ *
+ * @param value BigDecimal value to encode, may be null
+ * @param dst destination for encoded bytes
+ * @param dstOffset offset into destination array
+ * @return amount of bytes written
+ * @since 1.2
+ */
+ public static int encode(BigDecimal value, byte[] dst, int dstOffset) {
+ if (value == null) {
+ dst[dstOffset] = NULL_BYTE_HIGH;
+ return 1;
+ }
+ int amt = encodeSignedVarInt(value.scale(), dst, dstOffset);
+ return amt + encode(value.unscaledValue(), dst, dstOffset + amt);
+ }
+
+ /**
+ * Returns the amount of bytes required to encode the given BigDecimal.
+ *
+ * @param value BigDecimal value to encode, may be null
+ * @return amount of bytes needed to encode
+ * @since 1.2
+ */
+ public static int calculateEncodedLength(BigDecimal value) {
+ if (value == null) {
+ return 1;
}
+ return signedVarIntLength(value.scale()) + calculateEncodedLength(value.unscaledValue());
}
/**
@@ -401,7 +424,7 @@ public class DataEncoder {
}
// Write the value length first, in a variable amount of bytes.
- int amt = encodeLength(valueLength, dst, dstOffset);
+ int amt = encodeUnsignedVarInt(valueLength, dst, dstOffset);
// Now write the value.
System.arraycopy(value, valueOffset, dst, dstOffset + amt, valueLength);
@@ -428,19 +451,7 @@ public class DataEncoder {
* @return amount of bytes needed to encode
*/
public static int calculateEncodedLength(byte[] value, int valueOffset, int valueLength) {
- if (value == null) {
- return 1;
- } else if (valueLength < 128) {
- return 1 + valueLength;
- } else if (valueLength < 16384) {
- return 2 + valueLength;
- } else if (valueLength < 2097152) {
- return 3 + valueLength;
- } else if (valueLength < 268435456) {
- return 4 + valueLength;
- } else {
- return 5 + valueLength;
- }
+ return value == null ? 1 : (unsignedVarIntLength(valueLength) + valueLength);
}
/**
@@ -467,7 +478,7 @@ public class DataEncoder {
int valueLength = value.length();
// Write the value length first, in a variable amount of bytes.
- dstOffset += encodeLength(valueLength, dst, dstOffset);
+ dstOffset += encodeUnsignedVarInt(valueLength, dst, dstOffset);
for (int i = 0; i < valueLength; i++) {
int c = value.charAt(i);
@@ -508,19 +519,7 @@ public class DataEncoder {
}
int valueLength = value.length();
- int encodedLen;
-
- if (valueLength < 128) {
- encodedLen = 1;
- } else if (valueLength < 16384) {
- encodedLen = 2;
- } else if (valueLength < 2097152) {
- encodedLen = 3;
- } else if (valueLength < 268435456) {
- encodedLen = 4;
- } else {
- encodedLen = 5;
- }
+ int encodedLen = unsignedVarIntLength(valueLength);
for (int i = 0; i < valueLength; i++) {
int c = value.charAt(i);
@@ -546,35 +545,68 @@ public class DataEncoder {
return encodedLen;
}
- private static int encodeLength(int valueLength, byte[] dst, int dstOffset) {
- if (valueLength < 128) {
- dst[dstOffset] = (byte)valueLength;
+ private static int encodeUnsignedVarInt(int value, byte[] dst, int dstOffset) {
+ if (value < 128) {
+ dst[dstOffset] = (byte)value;
return 1;
- } else if (valueLength < 16384) {
- dst[dstOffset++] = (byte)((valueLength >> 8) | 0x80);
- dst[dstOffset] = (byte)valueLength;
+ } else if (value < 16384) {
+ dst[dstOffset++] = (byte)((value >> 8) | 0x80);
+ dst[dstOffset] = (byte)value;
return 2;
- } else if (valueLength < 2097152) {
- dst[dstOffset++] = (byte)((valueLength >> 16) | 0xc0);
- dst[dstOffset++] = (byte)(valueLength >> 8);
- dst[dstOffset] = (byte)valueLength;
+ } else if (value < 2097152) {
+ dst[dstOffset++] = (byte)((value >> 16) | 0xc0);
+ dst[dstOffset++] = (byte)(value >> 8);
+ dst[dstOffset] = (byte)value;
return 3;
- } else if (valueLength < 268435456) {
- dst[dstOffset++] = (byte)((valueLength >> 24) | 0xe0);
- dst[dstOffset++] = (byte)(valueLength >> 16);
- dst[dstOffset++] = (byte)(valueLength >> 8);
- dst[dstOffset] = (byte)valueLength;
+ } else if (value < 268435456) {
+ dst[dstOffset++] = (byte)((value >> 24) | 0xe0);
+ dst[dstOffset++] = (byte)(value >> 16);
+ dst[dstOffset++] = (byte)(value >> 8);
+ dst[dstOffset] = (byte)value;
return 4;
} else {
dst[dstOffset++] = (byte)0xf0;
- dst[dstOffset++] = (byte)(valueLength >> 24);
- dst[dstOffset++] = (byte)(valueLength >> 16);
- dst[dstOffset++] = (byte)(valueLength >> 8);
- dst[dstOffset] = (byte)valueLength;
+ dst[dstOffset++] = (byte)(value >> 24);
+ dst[dstOffset++] = (byte)(value >> 16);
+ dst[dstOffset++] = (byte)(value >> 8);
+ dst[dstOffset] = (byte)value;
return 5;
}
}
+ private static int unsignedVarIntLength(int value) {
+ if (value < 128) {
+ return 1;
+ } else if (value < 16384) {
+ return 2;
+ } else if (value < 2097152) {
+ return 3;
+ } else if (value < 268435456) {
+ return 4;
+ } else {
+ return 5;
+ }
+ }
+
+ private static int encodeSignedVarInt(int value, byte[] dst, int dstOffset) {
+ value = (value < 0 ? (((~value) << 1) | 1) : (value << 1));
+ if (value < 0) {
+ dst[dstOffset++] = (byte)0xf0;
+ dst[dstOffset++] = (byte)(value >> 24);
+ dst[dstOffset++] = (byte)(value >> 16);
+ dst[dstOffset++] = (byte)(value >> 8);
+ dst[dstOffset] = (byte)value;
+ return 5;
+ } else {
+ return encodeUnsignedVarInt(value, dst, dstOffset);
+ }
+ }
+
+ private static int signedVarIntLength(int value) {
+ value = (value < 0 ? ~value : value) << 1;
+ return value < 0 ? 5 : unsignedVarIntLength(value);
+ }
+
/**
* Writes a positive length value in up to five bytes.
*