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