1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.db.common.utils;
14 public abstract class ValueType {
19 public abstract int getConstantSize(); // returns -1 if not constant size
20 public abstract void serialize(ByteBuffer buffer, Object obj);
21 public abstract void unsafeSerialize(ByteBuffer buffer, Object obj);
22 public abstract Object deserialize(ByteBuffer buffer);
24 public boolean supportsNativeArray() {
27 public void serializeNativeArray(ByteBuffer buffer, Object obj, int length) {
28 // TODO Throw exception
31 public Object deserializeNativeArray(ByteBuffer buffer, int length) {
32 // TODO Throw exception
36 public byte[] serialize(Object obj) {
37 int constantSize = getConstantSize();
38 ByteBuffer buffer = new ByteBuffer(constantSize >= 0 ? constantSize : 0);
39 serialize(buffer, obj);
40 return buffer.content();
43 public Object deserialize(byte[] bytes) {
44 return deserialize(new ByteBuffer(bytes));
47 public static class BooleanType extends ValueType {
48 public BooleanType() {}
51 public int getConstantSize() {
55 public void serialize(ByteBuffer buffer, Object obj) {
57 buffer.putByte( (Boolean)obj == true ? (byte)1 : (byte)0 );
61 public void unsafeSerialize(ByteBuffer buffer, Object obj) {
62 buffer.putByte( (Boolean)obj == true ? (byte)1 : (byte)0 );
65 public Object deserialize(ByteBuffer buffer) {
66 return buffer.getByte() != 0;
70 public static class ByteType extends ValueType {
74 public int getConstantSize() {
78 public void serialize(ByteBuffer buffer, Object obj) {
80 buffer.putByte((Byte)obj);
84 public void unsafeSerialize(ByteBuffer buffer, Object obj) {
85 buffer.putByte((Byte)obj);
88 public Object deserialize(ByteBuffer buffer) {
89 return buffer.getByte();
93 public static class IntegerType extends ValueType {
94 public IntegerType() {}
97 public int getConstantSize() {
101 public void serialize(ByteBuffer buffer, Object obj) {
103 buffer.putInt((Integer)obj);
107 public void unsafeSerialize(ByteBuffer buffer, Object obj) {
108 buffer.putInt((Integer)obj);
111 public Object deserialize(ByteBuffer buffer) {
112 return buffer.getInt();
116 public static class LongType extends ValueType {
120 public int getConstantSize() {
124 public void serialize(ByteBuffer buffer, Object obj) {
126 buffer.putLong((Long)obj);
130 public void unsafeSerialize(ByteBuffer buffer, Object obj) {
131 buffer.putLong((Long)obj);
134 public Object deserialize(ByteBuffer buffer) {
135 return buffer.getLong();
139 public static class FloatType extends ValueType {
140 public FloatType() {}
143 public int getConstantSize() {
147 public void serialize(ByteBuffer buffer, Object obj) {
149 buffer.putFloat((Float)obj);
153 public void unsafeSerialize(ByteBuffer buffer, Object obj) {
154 buffer.putFloat((Float)obj);
157 public Object deserialize(ByteBuffer buffer) {
158 return buffer.getFloat();
162 public static class DoubleType extends ValueType {
163 public DoubleType() {}
166 public int getConstantSize() {
170 public void serialize(ByteBuffer buffer, Object obj) {
172 buffer.putDouble((Double)obj);
176 public void unsafeSerialize(ByteBuffer buffer, Object obj) {
177 buffer.putDouble((Double)obj);
180 public Object deserialize(ByteBuffer buffer) {
181 return buffer.getDouble();
183 public boolean supportsNativeArray() {
186 public void serializeNativeArray(ByteBuffer buffer, Object obj, int length) {
187 double[] array = (double[])obj;
189 buffer.putInt(array.length);
192 for(double d : array)
196 public Object deserializeNativeArray(ByteBuffer buffer, int length) {
197 double[] ret = new double[length];
198 for(int i=0;i<length;++i)
199 ret[i] = buffer.getDouble();
204 public static class StringType extends ValueType {
205 public StringType() {}
208 public int getConstantSize() {
212 public void serialize(ByteBuffer buffer, Object obj) {
213 buffer.putString((String)obj);
217 public void unsafeSerialize(ByteBuffer buffer, Object obj) {
218 // TODO Throw exception
221 public Object deserialize(ByteBuffer buffer) {
222 return buffer.getString();
226 public static class ProductType extends ValueType {
227 public final ValueType[] baseTypes;
228 private int constantSize;
230 public ProductType(ValueType[] baseTypes) {
231 this.baseTypes = baseTypes;
233 for(ValueType b : baseTypes) {
234 int temp = b.getConstantSize();
239 constantSize += temp;
244 public int getConstantSize() {
248 public void serialize(ByteBuffer buffer, Object obj) {
249 if(constantSize >= 0) {
250 buffer.needs(constantSize);
251 unsafeSerialize(buffer, obj);
254 Object[] subobjects = (Object[])obj;
255 // FIXME Catch cast exception
256 // FIXME Check length
257 for(int i=0;i<baseTypes.length;++i)
258 baseTypes[i].serialize(buffer, subobjects[i]);
262 public void unsafeSerialize(ByteBuffer buffer, Object obj) {
263 Object[] subobjects = (Object[])obj;
264 // FIXME Catch cast exception
265 // FIXME Check length
266 for(int i=0;i<baseTypes.length;++i)
267 baseTypes[i].unsafeSerialize(buffer, subobjects[i]);
270 public Object deserialize(ByteBuffer buffer) {
271 Object[] ret = new Object[baseTypes.length];
272 for(int i=0;i<baseTypes.length;++i)
273 ret[i] = baseTypes[i].deserialize(buffer);
278 public static class Construction {
283 public static class SumType extends ValueType {
284 public final ValueType[] baseTypes;
285 private int constantSize;
287 public SumType(ValueType[] baseTypes) {
288 this.baseTypes = baseTypes;
290 for(ValueType b : baseTypes) {
291 int temp = b.getConstantSize();
292 if(temp != constantSize) {
293 if(constantSize==-2 && temp >= 0)
301 if(constantSize >= 0)
306 public int getConstantSize() {
310 public void serialize(ByteBuffer buffer, Object obj) {
311 if(constantSize >= 0) {
312 buffer.needs(constantSize);
313 unsafeSerialize(buffer, obj);
316 Construction construction = (Construction)obj;
317 // FIXME validate construction.constructor
319 buffer.putInt(construction.constructor);
320 baseTypes[construction.constructor].serialize(buffer, construction.value);
324 public void unsafeSerialize(ByteBuffer buffer, Object obj) {
325 Construction construction = (Construction)obj;
326 // FIXME validate construction.constructor
327 buffer.putInt(construction.constructor);
328 baseTypes[construction.constructor].unsafeSerialize(buffer, construction.value);
331 public Object deserialize(ByteBuffer buffer) {
332 Construction ret = new Construction();
333 ret.constructor = buffer.getInt();
334 // FIXME validate construction.constructor
335 ret.value = baseTypes[ret.constructor].deserialize(buffer);
340 public static class VariableLengthArrayType extends ValueType {
341 public final ValueType baseType;
342 private int baseTypeConstantSize;
343 private boolean supportsNativeArray;
345 public VariableLengthArrayType(ValueType baseType) {
346 this.baseType = baseType;
347 baseTypeConstantSize = baseType.getConstantSize();
348 supportsNativeArray = baseType.supportsNativeArray();
352 public int getConstantSize() {
357 public void serialize(ByteBuffer buffer, Object obj) {
358 if(baseTypeConstantSize >= 0) {
359 if(obj instanceof Object[]) {
360 Object[] subobjects = (Object[])obj;
361 buffer.needs(4 + subobjects.length * baseTypeConstantSize);
362 buffer.putInt(subobjects.length);
363 for(Object subobj : subobjects)
364 baseType.unsafeSerialize(buffer, subobj);
366 else if(supportsNativeArray)
367 baseType.serializeNativeArray(buffer, obj, -1);
373 Object[] subobjects = (Object[])obj;
375 buffer.putInt(subobjects.length);
376 for(Object subobj : subobjects)
377 baseType.serialize(buffer, subobj);
381 public void unsafeSerialize(ByteBuffer buffer, Object obj) {
382 // TODO Throw exception
385 public Object deserialize(ByteBuffer buffer) {
386 int length = buffer.getInt();
387 if(supportsNativeArray)
388 return baseType.deserializeNativeArray(buffer, length);
390 Object[] ret = new Object[length];
391 for(int i=0;i<length;++i)
392 ret[i] = baseType.deserialize(buffer);
398 public static class FixedLengthArrayType extends ValueType {
399 public final ValueType baseType;
400 public final int dimension;
401 private int constantSize;
402 private boolean supportsNativeArray;
404 public FixedLengthArrayType(ValueType baseType, int dimension) {
405 this.baseType = baseType;
406 this.dimension = dimension;
407 constantSize = baseType.getConstantSize();
408 if(constantSize >= 0) {
409 constantSize *= dimension;
410 supportsNativeArray = baseType.supportsNativeArray();
415 public int getConstantSize() {
420 public void serialize(ByteBuffer buffer, Object obj) {
421 if(constantSize >= 0) {
422 buffer.needs(constantSize);
423 unsafeSerialize(buffer, obj);
426 Object[] subobjects = (Object[])obj;
428 for(Object subobj : subobjects)
429 baseType.serialize(buffer, subobj);
433 public void unsafeSerialize(ByteBuffer buffer, Object obj) {
434 if(supportsNativeArray)
435 baseType.serializeNativeArray(buffer, obj, dimension);
437 Object[] subobjects = (Object[])obj;
439 for(Object subobj : subobjects)
440 baseType.unsafeSerialize(buffer, subobj);
444 public Object deserialize(ByteBuffer buffer) {
445 if(supportsNativeArray)
446 return baseType.deserializeNativeArray(buffer, dimension);
448 Object[] ret = new Object[dimension];
449 for(int i=0;i<dimension;++i)
450 ret[i] = baseType.deserialize(buffer);
456 static final private class ByteBuffer {
460 public ByteBuffer(int capacity) {
461 this.bytes = new byte[capacity];
465 public ByteBuffer(byte[] bytes) {
470 public void needs(int size) {
471 if(offset + size > bytes.length) {
472 // FIXME bytes = Arrays.copyOf(bytes, newSize);
473 byte[] newBytes = new byte[offset*2 + size];
474 for(int i=0;i<bytes.length;++i)
475 newBytes[i] = bytes[i];
480 public byte[] content() {
481 if(offset == bytes.length)
483 // FIXME bytes = Arrays.copyOf(bytes, offset);
484 byte[] newBytes = new byte[offset];
485 for(int i=0;i<offset;++i)
486 newBytes[i] = bytes[i];
490 public void putByte(byte v) {
494 public void putShort(short v) {
495 bytes[offset] = (byte) v;
496 bytes[offset+1] = (byte) (v >>> 8);
499 public void putInt(int v) {
500 bytes[offset] = (byte) v;
501 bytes[offset+1] = (byte) (v >>> 8);
502 bytes[offset+2] = (byte) (v >>> 16);
503 bytes[offset+3] = (byte) (v >>> 24);
506 public void putLong(long v) {
507 bytes[offset] = (byte) v;
508 bytes[offset+1] = (byte) (v >>> 8);
509 bytes[offset+2] = (byte) (v >>> 16);
510 bytes[offset+3] = (byte) (v >>> 24);
511 bytes[offset+4] = (byte) (v >>> 32);
512 bytes[offset+5] = (byte) (v >>> 40);
513 bytes[offset+6] = (byte) (v >>> 48);
514 bytes[offset+7] = (byte) (v >>> 56);
517 public void putFloat(float _v) {
518 int v = Float.floatToIntBits(_v);
519 bytes[offset] = (byte) v;
520 bytes[offset+1] = (byte) (v >>> 8);
521 bytes[offset+2] = (byte) (v >>> 16);
522 bytes[offset+3] = (byte) (v >>> 24);
525 public void putDouble(double _v) {
526 long v = Double.doubleToLongBits(_v);
527 bytes[offset] = (byte) v;
528 bytes[offset+1] = (byte) (v >>> 8);
529 bytes[offset+2] = (byte) (v >>> 16);
530 bytes[offset+3] = (byte) (v >>> 24);
531 bytes[offset+4] = (byte) (v >>> 32);
532 bytes[offset+5] = (byte) (v >>> 40);
533 bytes[offset+6] = (byte) (v >>> 48);
534 bytes[offset+7] = (byte) (v >>> 56);
537 public void putString(String str) {
539 // UTF-16 -> modified UTF-8
542 for(int i=0;i<str.length();++i) {
543 char c = str.charAt(i);
552 putInt(str.length());
553 for(int i=0;i<str.length();++i) {
554 char c = str.charAt(i);
556 bytes[offset] = (byte)c;
560 bytes[offset] = (byte)(0xc0 + (c >>> 6));
561 bytes[offset+1] = (byte)(0x80 + (c & 0x3f));
565 // FIXME handle range D800 - DFFF
566 bytes[offset] = (byte)(0xe0 + (c >>> 12));
567 bytes[offset+1] = (byte)(0x80 + ((c >>> 6) & 0x3f));
568 bytes[offset+2] = (byte)(0x80 + (c & 0x3f));
573 public byte getByte() {
575 return bytes[offset-1];
577 public short getShort() {
578 int v = bytes[offset] & 0xFF;
579 v += (bytes[offset+1] & 0xFF) << 8;
583 public int getInt() {
584 int v = bytes[offset] & 0xFF;
585 v += (bytes[offset+1] & 0xFF) << 8;
586 v += (bytes[offset+2] & 0xFF) << 16;
587 v += (bytes[offset+3] & 0xFF) << 24;
591 public long getLong() {
592 long v = bytes[offset] & 0xFFL;
593 v += (bytes[offset+1] & 0xFFL) << 8;
594 v += (bytes[offset+2] & 0xFFL) << 16;
595 v += (bytes[offset+3] & 0xFFL) << 24;
596 v += (bytes[offset+4] & 0xFFL) << 32;
597 v += (bytes[offset+5] & 0xFFL) << 40;
598 v += (bytes[offset+6] & 0xFFL) << 48;
599 v += (bytes[offset+7] & 0xFFL) << 56;
603 public float getFloat() {
604 int v = bytes[offset] & 0xFF;
605 v += (bytes[offset+1] & 0xFF) << 8;
606 v += (bytes[offset+2] & 0xFF) << 16;
607 v += (bytes[offset+3] & 0xFF) << 24;
609 return Float.intBitsToFloat(v);
611 public double getDouble() {
612 long v = bytes[offset] & 0xFFL;
613 v += (bytes[offset+1] & 0xFFL) << 8;
614 v += (bytes[offset+2] & 0xFFL) << 16;
615 v += (bytes[offset+3] & 0xFFL) << 24;
616 v += (bytes[offset+4] & 0xFFL) << 32;
617 v += (bytes[offset+5] & 0xFFL) << 40;
618 v += (bytes[offset+6] & 0xFFL) << 48;
619 v += (bytes[offset+7] & 0xFFL) << 56;
621 return Double.longBitsToDouble(v);
623 public String getString() {
624 int length = getInt();
625 char[] chars = new char[length];
626 for(int i=0;i<length;++i) {
627 int b0 = (int)bytes[offset];
633 else if(b0 < 0xe0-256) {
634 c = ((b0 & 0x1f) << 6) +
635 (bytes[offset+1] & 0x3f);
638 else if(b0 < 0xf0-256) {
639 c = ((b0 & 0x0f) << 12) +
640 ((bytes[offset+1] & 0x3f) << 6) +
641 (bytes[offset+2] & 0x3f);
648 return new String(chars);