Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.objectfabric.ImmutableWriter Maven / Gradle / Ivy
/**
* This file is part of ObjectFabric (http://objectfabric.org).
*
* ObjectFabric is licensed under the Apache License, Version 2.0, the terms
* of which may be found at http://www.apache.org/licenses/LICENSE-2.0.html.
*
* Copyright ObjectFabric Inc.
*
* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
* WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
package org.objectfabric;
import org.objectfabric.ThreadAssert.SingleThreaded;
@SingleThreaded
class ImmutableWriter extends Continuation {
private Buff _buff;
// TODO add caches e.g. for long, String (add UID?) to avoid sending again
// Debug
static final int DEBUG_OVERHEAD;
private static boolean _checkCommunications = true;
protected ImmutableWriter(List interruptionStack) {
super(interruptionStack);
}
final Buff getBuff() {
return _buff;
}
final void setBuff(Buff buff) {
_buff = buff;
}
//
void reset() {
if (Debug.COMMUNICATIONS && getCheckCommunications())
ThreadAssert.getOrCreateCurrent().resetWriterDebugCounter(this);
}
private final int remaining() {
/*
* TODO: always say 0 the first time to test all interruption sites.
*/
return _buff.limit() - _buff.position();
}
private final void putBoolean(boolean value) {
_buff.putByte(value ? (byte) 1 : (byte) 0);
}
final void putByte(byte value) {
_buff.putByte(value);
}
//
/*
* Fixed lengths.
*/
private static final int BYTE_LENGTH = 1;
public final boolean canWriteByte() {
int needed = BYTE_LENGTH;
if (Debug.COMMUNICATIONS && getCheckCommunications()) {
Helper.instance().setExpectedClass(Immutable.BYTE_INDEX);
needed += ImmutableWriter.DEBUG_OVERHEAD;
}
return remaining() >= needed;
}
public final void writeByte(byte value) {
writeByte(value, 0);
}
public final void writeByte(byte value, int tag) {
if (Debug.COMMUNICATIONS && getCheckCommunications())
writeDebugInfo(Immutable.BYTE_INDEX, tag);
_buff.putByte(value);
}
public final boolean canWriteByteBoxed() {
int needed = BOOLEAN_LENGTH + BYTE_LENGTH;
if (Debug.COMMUNICATIONS && getCheckCommunications()) {
Helper.instance().setExpectedClass(Immutable.BYTE_BOXED_INDEX);
needed += ImmutableWriter.DEBUG_OVERHEAD;
}
return remaining() >= needed;
}
public final void writeByteBoxed(Byte value) {
if (Debug.COMMUNICATIONS && getCheckCommunications())
writeDebugInfo(Immutable.BYTE_BOXED_INDEX, 0);
if (value == null) // Marker
putBoolean(false);
else {
putBoolean(true);
_buff.putByte(value); // Marker
}
}
//
private static final int BOOLEAN_LENGTH = 1;
public final boolean canWriteBoolean() {
int needed = BOOLEAN_LENGTH;
if (Debug.COMMUNICATIONS && getCheckCommunications()) {
Helper.instance().setExpectedClass(Immutable.BOOLEAN_INDEX);
needed += ImmutableWriter.DEBUG_OVERHEAD;
}
return remaining() >= needed;
}
public final void writeBoolean(boolean value) {
if (Debug.COMMUNICATIONS && getCheckCommunications())
writeDebugInfo(Immutable.BOOLEAN_INDEX, 0);
putBoolean(value);
}
public final boolean canWriteBooleanBoxed() {
int needed = BOOLEAN_LENGTH + BOOLEAN_LENGTH;
if (Debug.COMMUNICATIONS && getCheckCommunications()) {
Helper.instance().setExpectedClass(Immutable.BOOLEAN_BOXED_INDEX);
needed += ImmutableWriter.DEBUG_OVERHEAD;
}
return remaining() >= needed;
}
public final void writeBooleanBoxed(Boolean value) {
if (Debug.COMMUNICATIONS && getCheckCommunications())
writeDebugInfo(Immutable.BOOLEAN_BOXED_INDEX, 0);
if (value == null) // Marker
putBoolean(false);
else {
putBoolean(true);
putBoolean(value); // Marker
}
}
//
private static final int SHORT_LENGTH = Short.SIZE / 8;
public final boolean canWriteShort() {
int needed = SHORT_LENGTH;
if (Debug.COMMUNICATIONS && getCheckCommunications()) {
Helper.instance().setExpectedClass(Immutable.SHORT_INDEX);
needed += ImmutableWriter.DEBUG_OVERHEAD;
}
return remaining() >= needed;
}
public final void writeShort(short value) {
if (Debug.COMMUNICATIONS && getCheckCommunications())
writeDebugInfo(Immutable.SHORT_INDEX, 0);
_buff.putShort(value);
}
public final boolean canWriteShortBoxed() {
int needed = BOOLEAN_LENGTH + SHORT_LENGTH;
if (Debug.COMMUNICATIONS && getCheckCommunications()) {
Helper.instance().setExpectedClass(Immutable.SHORT_BOXED_INDEX);
needed += ImmutableWriter.DEBUG_OVERHEAD;
}
return remaining() >= needed;
}
public final void writeShortBoxed(Short value) {
if (Debug.COMMUNICATIONS && getCheckCommunications())
writeDebugInfo(Immutable.SHORT_BOXED_INDEX, 0);
if (value == null) // Marker
putBoolean(false);
else {
putBoolean(true);
_buff.putShort(value); // Marker
}
}
//
private static final int CHARACTER_LENGTH = Character.SIZE / 8;
public final boolean canWriteCharacter() {
int needed = CHARACTER_LENGTH;
if (Debug.COMMUNICATIONS && getCheckCommunications()) {
Helper.instance().setExpectedClass(Immutable.CHARACTER_INDEX);
needed += ImmutableWriter.DEBUG_OVERHEAD;
}
return remaining() >= needed;
}
public final void writeCharacter(char value) {
if (Debug.COMMUNICATIONS && getCheckCommunications())
writeDebugInfo(Immutable.CHARACTER_INDEX, 0);
_buff.putChar(value);
}
public final boolean canWriteCharacterBoxed() {
int needed = BOOLEAN_LENGTH + CHARACTER_LENGTH;
if (Debug.COMMUNICATIONS && getCheckCommunications()) {
Helper.instance().setExpectedClass(Immutable.CHARACTER_BOXED_INDEX);
needed += ImmutableWriter.DEBUG_OVERHEAD;
}
return remaining() >= needed;
}
public final void writeCharacterBoxed(Character value) {
if (Debug.COMMUNICATIONS && getCheckCommunications())
writeDebugInfo(Immutable.CHARACTER_BOXED_INDEX, 0);
if (value == null) // Marker
putBoolean(false);
else {
putBoolean(true);
_buff.putChar(value); // Marker
}
}
//
private static final int INTEGER_LENGTH = Integer.SIZE / 8;
public final boolean canWriteInteger() {
int needed = INTEGER_LENGTH;
if (Debug.COMMUNICATIONS && getCheckCommunications()) {
Helper.instance().setExpectedClass(Immutable.INTEGER_INDEX);
needed += ImmutableWriter.DEBUG_OVERHEAD;
}
return remaining() >= needed;
}
public final void writeInteger(int value) {
if (Debug.COMMUNICATIONS && getCheckCommunications())
writeDebugInfo(Immutable.INTEGER_INDEX, 0);
_buff.putInt(value);
}
public final boolean canWriteIntegerBoxed() {
int needed = BOOLEAN_LENGTH + INTEGER_LENGTH;
if (Debug.COMMUNICATIONS && getCheckCommunications()) {
Helper.instance().setExpectedClass(Immutable.INTEGER_BOXED_INDEX);
needed += ImmutableWriter.DEBUG_OVERHEAD;
}
return remaining() >= needed;
}
public final void writeIntegerBoxed(Integer value) {
if (Debug.COMMUNICATIONS && getCheckCommunications())
writeDebugInfo(Immutable.INTEGER_BOXED_INDEX, 0);
if (value == null) // Marker
putBoolean(false);
else {
putBoolean(true);
_buff.putInt(value); // Marker
}
}
//
private static final int LONG_LENGTH = Long.SIZE / 8;
public final boolean canWriteLong() {
int needed = LONG_LENGTH;
if (Debug.COMMUNICATIONS && getCheckCommunications()) {
Helper.instance().setExpectedClass(Immutable.LONG_INDEX);
needed += ImmutableWriter.DEBUG_OVERHEAD;
}
return remaining() >= needed;
}
public final void writeLong(long value) {
if (Debug.COMMUNICATIONS && getCheckCommunications())
writeDebugInfo(Immutable.LONG_INDEX, 0);
_buff.putLong(value);
}
public final boolean canWriteLongBoxed() {
int needed = BOOLEAN_LENGTH + LONG_LENGTH;
if (Debug.COMMUNICATIONS && getCheckCommunications()) {
Helper.instance().setExpectedClass(Immutable.LONG_BOXED_INDEX);
needed += ImmutableWriter.DEBUG_OVERHEAD;
}
return remaining() >= needed;
}
public final void writeLongBoxed(Long value) {
if (Debug.COMMUNICATIONS && getCheckCommunications())
writeDebugInfo(Immutable.LONG_BOXED_INDEX, 0);
if (value == null) // Marker
putBoolean(false);
else {
putBoolean(true);
_buff.putLong(value); // Marker
}
}
//
private static final int FLOAT_LENGTH = Float.SIZE / 8;
public final boolean canWriteFloat() {
int needed = FLOAT_LENGTH;
if (Debug.COMMUNICATIONS && getCheckCommunications()) {
Helper.instance().setExpectedClass(Immutable.FLOAT_INDEX);
needed += ImmutableWriter.DEBUG_OVERHEAD;
}
return remaining() >= needed;
}
public final void writeFloat(float value) {
if (Debug.COMMUNICATIONS && getCheckCommunications())
writeDebugInfo(Immutable.FLOAT_INDEX, 0);
int i = Platform.get().floatToInt(value);
_buff.putInt(i);
}
public final boolean canWriteFloatBoxed() {
int needed = BOOLEAN_LENGTH + FLOAT_LENGTH;
if (Debug.COMMUNICATIONS && getCheckCommunications()) {
Helper.instance().setExpectedClass(Immutable.FLOAT_BOXED_INDEX);
needed += ImmutableWriter.DEBUG_OVERHEAD;
}
return remaining() >= needed;
}
public final void writeFloatBoxed(Float value) {
if (Debug.COMMUNICATIONS && getCheckCommunications())
writeDebugInfo(Immutable.FLOAT_BOXED_INDEX, 0);
if (value == null) // Marker
putBoolean(false);
else {
putBoolean(true);
int i = Platform.get().floatToInt(value); // Marker
_buff.putInt(i);
}
}
//
private static final int DOUBLE_LENGTH = Double.SIZE / 8;
public final boolean canWriteDouble() {
int needed = DOUBLE_LENGTH;
if (Debug.COMMUNICATIONS && getCheckCommunications()) {
Helper.instance().setExpectedClass(Immutable.DOUBLE_INDEX);
needed += ImmutableWriter.DEBUG_OVERHEAD;
}
return remaining() >= needed;
}
public final void writeDouble(double value) {
if (Debug.COMMUNICATIONS && getCheckCommunications())
writeDebugInfo(Immutable.DOUBLE_INDEX, 0);
long l = Platform.get().doubleToLong(value);
_buff.putLong(l);
}
public final boolean canWriteDoubleBoxed() {
int needed = BOOLEAN_LENGTH + DOUBLE_LENGTH;
if (Debug.COMMUNICATIONS && getCheckCommunications()) {
Helper.instance().setExpectedClass(Immutable.DOUBLE_BOXED_INDEX);
needed += ImmutableWriter.DEBUG_OVERHEAD;
}
return remaining() >= needed;
}
public final void writeDoubleBoxed(Double value) {
if (Debug.COMMUNICATIONS && getCheckCommunications())
writeDebugInfo(Immutable.DOUBLE_BOXED_INDEX, 0);
if (value == null) // Marker
putBoolean(false);
else {
putBoolean(true);
long l = Platform.get().doubleToLong(value); // Marker
_buff.putLong(l);
}
}
//
private static final int DATE_LENGTH = LONG_LENGTH;
public final boolean canWriteDate() {
int needed = DATE_LENGTH;
if (Debug.COMMUNICATIONS && getCheckCommunications()) {
Helper.instance().setExpectedClass(Immutable.DATE_INDEX);
needed += ImmutableWriter.DEBUG_OVERHEAD;
}
return remaining() >= needed;
}
public final void writeDate(java.util.Date value) {
if (Debug.COMMUNICATIONS && getCheckCommunications())
writeDebugInfo(Immutable.DATE_INDEX, 0);
if (value == null) // Marker
_buff.putLong(-1);
else
_buff.putLong(value.getTime() * 10000 + 621355968000000000L);
}
/*
* Non fixed lengths.
*/
public final void writeString(String value) {
writeString(value, 0, true);
}
public final void writeString(String value, int tag) {
writeString(value, tag, true);
}
/*
* Interruptible string encoding with null & EOF codes to avoid sending length.
*/
static final int STRING_ENC_DOES_NOT_FIT_ON_1_BYTE_MASK = 1 << 7;
static final int STRING_ENC_DOES_NOT_FIT_ON_2_BYTES_MASK = 1 << 6;
static final int STRING_ENC_EOF_MASK = 1 << 5;
static final int STRING_ENC_NULL_MASK = 1 << 4;
private final void writeString(String value, int tag, boolean debug) {
int index = Debug.COMMUNICATIONS && getCheckCommunications() && debug ? -1 : 0;
if (interrupted())
index = resumeInt();
if (Debug.COMMUNICATIONS && getCheckCommunications() && debug) {
if (index < 0) {
if (!canWriteDebugInfo()) {
interruptInt(-1);
return;
}
Helper.instance().setExpectedClass(Immutable.STRING_INDEX);
writeDebugInfo(Immutable.STRING_INDEX, tag);
index = 0;
}
}
if (value == null) {
if (remaining() == 0) {
interruptInt(0);
return;
}
int mask = STRING_ENC_DOES_NOT_FIT_ON_1_BYTE_MASK;
mask |= STRING_ENC_DOES_NOT_FIT_ON_2_BYTES_MASK;
mask |= STRING_ENC_EOF_MASK;
mask |= STRING_ENC_NULL_MASK;
_buff.putByte((byte) mask);
return;
}
for (;;) {
if (index == value.length()) {
if (remaining() == 0) {
interruptInt(index);
return;
}
int mask = STRING_ENC_DOES_NOT_FIT_ON_1_BYTE_MASK;
mask |= STRING_ENC_DOES_NOT_FIT_ON_2_BYTES_MASK;
mask |= STRING_ENC_EOF_MASK;
_buff.putByte((byte) mask);
return;
}
char c = value.charAt(index);
if (c < 128) { // Char fits in 7 bits -> 1 byte
if (remaining() == 0) {
interruptInt(index);
return;
}
_buff.putByte((byte) c);
} else if (c < 16384) { // Char fits in 14 bits -> 2 bytes
if (remaining() < 2) {
interruptInt(index);
return;
}
_buff.putByte((byte) (STRING_ENC_DOES_NOT_FIT_ON_1_BYTE_MASK | (c >> 8)));
_buff.putByte((byte) (c & 0xff));
} else { // Others -> 3 bytes
if (remaining() < 3) {
interruptInt(index);
return;
}
int mask = STRING_ENC_DOES_NOT_FIT_ON_1_BYTE_MASK;
mask |= STRING_ENC_DOES_NOT_FIT_ON_2_BYTES_MASK;
_buff.putByte((byte) mask);
_buff.putChar(c);
}
index++;
}
}
//
public final void writeBinary(byte[] value) {
writeBinary(value, Immutable.BINARY_INDEX);
}
private final void writeBinary(byte[] value, int classId) {
int index = Debug.COMMUNICATIONS && getCheckCommunications() ? -2 : -1;
if (interrupted())
index = resumeInt();
if (Debug.COMMUNICATIONS && getCheckCommunications()) {
if (index == -2) {
if (!canWriteDebugInfo()) {
interruptInt(-2);
return;
}
Helper.instance().setExpectedClass(classId);
writeDebugInfo(classId, 0);
}
}
if (index < 0) {
if (remaining() < INTEGER_LENGTH) {
interruptInt(-1);
return;
}
if (value == null) {
_buff.putInt(-1);
return;
}
_buff.putInt(value.length);
index = 0;
}
// TODO use put(byte[])
for (; index < value.length; index++) {
if (remaining() == 0) {
interruptInt(index);
return;
}
_buff.putByte(value[index]);
}
}
//
public final void writeBigInteger(java.math.BigInteger value) {
if (value == null) // Marker
writeBinary(null, Immutable.BIG_INTEGER_INDEX);
else
writeBinary(value.toByteArray(), Immutable.BIG_INTEGER_INDEX);
}
//
public final void writeDecimal(java.math.BigDecimal value) {
if (value == null) // Marker
writeBinary(null, Immutable.DECIMAL_INDEX);
else {
byte[] array;
if (interrupted())
array = (byte[]) resume();
else {
byte[] t = value.unscaledValue().toByteArray();
array = new byte[t.length + 4];
Platform.arraycopy(t, 0, array, 0, t.length);
int scale = value.scale();
array[array.length - 4] = (byte) (scale & 0xff);
array[array.length - 3] = (byte) ((scale >>> 8) & 0xff);
array[array.length - 2] = (byte) ((scale >>> 16) & 0xff);
array[array.length - 1] = (byte) ((scale >>> 24) & 0xff);
}
writeBinary(array, Immutable.DECIMAL_INDEX);
if (interrupted())
interrupt(array);
}
}
// Debug
static boolean getCheckCommunications() {
if (!Debug.COMMUNICATIONS)
throw new IllegalStateException();
return _checkCommunications;
}
static void setCheckCommunications(boolean value) {
if (!Debug.COMMUNICATIONS)
throw new IllegalStateException();
_checkCommunications = value;
}
private final boolean canWriteDebugInfo() {
if (!Debug.COMMUNICATIONS || !getCheckCommunications())
throw new IllegalStateException();
return remaining() >= DEBUG_OVERHEAD;
}
static {
int value = 0;
value += LONG_LENGTH; // debugCounter
value += BYTE_LENGTH; // classId
value += INTEGER_LENGTH; // tag
DEBUG_OVERHEAD = value;
}
private final void writeDebugInfo(int classId, int tag) {
if (!Debug.COMMUNICATIONS || !getCheckCommunications())
throw new IllegalStateException();
if (Debug.COMMUNICATIONS_LOG_ALL) {
String name = Immutable.ALL.get(classId).toString();
long counter = ThreadAssert.getOrCreateCurrent().getWriterDebugCounter(this);
String c = Platform.get().simpleClassName(this);
Log.write(c + ", " + counter + ", class: " + name + ", tag: " + tag);
}
Debug.assertion(classId == Helper.instance().getExpectedClass());
long debugCounter = ThreadAssert.getOrCreateCurrent().getAndIncrementWriterDebugCounter(this);
_buff.putLong(debugCounter);
_buff.putByte((byte) classId);
_buff.putInt(tag);
}
}