]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.common/src/org/simantics/db/common/utils/ValueType.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.db.common / src / org / simantics / db / common / utils / ValueType.java
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
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.db.common.utils;\r
13 \r
14 public abstract class ValueType {\r
15 \r
16     private ValueType() {\r
17     }    \r
18 \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
23 \r
24     public boolean supportsNativeArray() {\r
25         return false;\r
26     }\r
27     public void serializeNativeArray(ByteBuffer buffer, Object obj, int length) {\r
28         // TODO Throw exception\r
29     }\r
30 \r
31     public Object deserializeNativeArray(ByteBuffer buffer, int length) {\r
32         // TODO Throw exception\r
33         return null;\r
34     }\r
35 \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
41     }\r
42 \r
43     public Object deserialize(byte[] bytes) {\r
44         return deserialize(new ByteBuffer(bytes));\r
45     }    \r
46 \r
47     public static class BooleanType extends ValueType {\r
48         public BooleanType() {}       \r
49 \r
50         @Override\r
51         public int getConstantSize() {\r
52             return 1;\r
53         }        \r
54         @Override\r
55         public void serialize(ByteBuffer buffer, Object obj) {\r
56             buffer.needs(1);\r
57             buffer.putByte( (Boolean)obj == true ? (byte)1 : (byte)0 );\r
58 \r
59         }\r
60         @Override\r
61         public void  unsafeSerialize(ByteBuffer buffer, Object obj) {\r
62             buffer.putByte( (Boolean)obj == true ? (byte)1 : (byte)0 );            \r
63         }\r
64         @Override\r
65         public Object deserialize(ByteBuffer buffer) {\r
66             return buffer.getByte() != 0;\r
67         }\r
68     }\r
69 \r
70     public static class ByteType extends ValueType {\r
71         public ByteType() {}       \r
72 \r
73         @Override\r
74         public int getConstantSize() {\r
75             return 1;\r
76         }        \r
77         @Override\r
78         public void serialize(ByteBuffer buffer, Object obj) {\r
79             buffer.needs(1);\r
80             buffer.putByte((Byte)obj);\r
81 \r
82         }\r
83         @Override\r
84         public void  unsafeSerialize(ByteBuffer buffer, Object obj) {\r
85             buffer.putByte((Byte)obj);            \r
86         }\r
87         @Override\r
88         public Object deserialize(ByteBuffer buffer) {\r
89             return buffer.getByte();\r
90         }\r
91     }\r
92 \r
93     public static class IntegerType extends ValueType {\r
94         public IntegerType() {}       \r
95 \r
96         @Override\r
97         public int getConstantSize() {\r
98             return 4;\r
99         }        \r
100         @Override\r
101         public void serialize(ByteBuffer buffer, Object obj) {\r
102             buffer.needs(4);\r
103             buffer.putInt((Integer)obj);\r
104 \r
105         }\r
106         @Override\r
107         public void  unsafeSerialize(ByteBuffer buffer, Object obj) {\r
108             buffer.putInt((Integer)obj);            \r
109         }\r
110         @Override\r
111         public Object deserialize(ByteBuffer buffer) {\r
112             return buffer.getInt();\r
113         }\r
114     }\r
115 \r
116     public static class LongType extends ValueType {\r
117         public LongType() {}       \r
118 \r
119         @Override\r
120         public int getConstantSize() {\r
121             return 8;\r
122         }        \r
123         @Override\r
124         public void serialize(ByteBuffer buffer, Object obj) {\r
125             buffer.needs(8);\r
126             buffer.putLong((Long)obj);\r
127 \r
128         }\r
129         @Override\r
130         public void  unsafeSerialize(ByteBuffer buffer, Object obj) {\r
131             buffer.putLong((Long)obj);            \r
132         }\r
133         @Override\r
134         public Object deserialize(ByteBuffer buffer) {\r
135             return buffer.getLong();\r
136         }\r
137     }\r
138     \r
139     public static class FloatType extends ValueType {\r
140         public FloatType() {}       \r
141 \r
142         @Override\r
143         public int getConstantSize() {\r
144             return 4;\r
145         }        \r
146         @Override\r
147         public void serialize(ByteBuffer buffer, Object obj) {\r
148             buffer.needs(4);\r
149             buffer.putFloat((Float)obj);\r
150 \r
151         }\r
152         @Override\r
153         public void  unsafeSerialize(ByteBuffer buffer, Object obj) {\r
154             buffer.putFloat((Float)obj);            \r
155         }\r
156         @Override\r
157         public Object deserialize(ByteBuffer buffer) {\r
158             return buffer.getFloat();\r
159         }\r
160     }\r
161 \r
162     public static class DoubleType extends ValueType {\r
163         public DoubleType() {}       \r
164 \r
165         @Override\r
166         public int getConstantSize() {\r
167             return 8;\r
168         }        \r
169         @Override\r
170         public void serialize(ByteBuffer buffer, Object obj) {\r
171             buffer.needs(8);\r
172             buffer.putDouble((Double)obj);\r
173 \r
174         }\r
175         @Override\r
176         public void  unsafeSerialize(ByteBuffer buffer, Object obj) {\r
177             buffer.putDouble((Double)obj);            \r
178         }\r
179         @Override\r
180         public Object deserialize(ByteBuffer buffer) {\r
181             return buffer.getDouble();\r
182         }\r
183         public boolean supportsNativeArray() {\r
184             return true;\r
185         }\r
186         public void serializeNativeArray(ByteBuffer buffer, Object obj, int length) {\r
187             double[] array = (double[])obj;\r
188             if(length < 0)\r
189                 buffer.putInt(array.length);\r
190             else\r
191                 ; // TODO check\r
192             for(double d : array)\r
193                 buffer.putDouble(d);\r
194         }\r
195 \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
200             return ret;\r
201         }\r
202     }\r
203 \r
204     public static class StringType extends ValueType {\r
205         public StringType() {}       \r
206 \r
207         @Override\r
208         public int getConstantSize() {\r
209             return -1;\r
210         }        \r
211         @Override\r
212         public void serialize(ByteBuffer buffer, Object obj) {\r
213             buffer.putString((String)obj);\r
214 \r
215         }\r
216         @Override\r
217         public void  unsafeSerialize(ByteBuffer buffer, Object obj) {\r
218             // TODO Throw exception\r
219         }\r
220         @Override\r
221         public Object deserialize(ByteBuffer buffer) {\r
222             return buffer.getString();\r
223         }\r
224     }\r
225 \r
226     public static class ProductType extends ValueType {\r
227         public final ValueType[] baseTypes;\r
228         private int constantSize;\r
229 \r
230         public ProductType(ValueType[] baseTypes) {\r
231             this.baseTypes = baseTypes;\r
232             constantSize = 0;\r
233             for(ValueType b : baseTypes) {\r
234                 int temp = b.getConstantSize();\r
235                 if(temp==-1) {\r
236                     constantSize = -1;\r
237                     break;\r
238                 }\r
239                 constantSize += temp;\r
240             }\r
241         }\r
242 \r
243         @Override\r
244         public int getConstantSize() {\r
245             return constantSize;\r
246         }        \r
247         @Override\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
252             }\r
253             else {\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
259             }\r
260         }\r
261         @Override\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
268         }\r
269         @Override\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
274             return ret;\r
275         }\r
276     }\r
277 \r
278     public static class Construction {\r
279         int constructor;\r
280         Object value;\r
281     }\r
282 \r
283     public static class SumType extends ValueType {\r
284         public final ValueType[] baseTypes;\r
285         private int constantSize;\r
286 \r
287         public SumType(ValueType[] baseTypes) {\r
288             this.baseTypes = baseTypes;\r
289             constantSize = -2;\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
295                     else {\r
296                         constantSize = -1;\r
297                         break;\r
298                     }\r
299                 }\r
300             }\r
301             if(constantSize >= 0)\r
302                 constantSize += 4;\r
303         }\r
304 \r
305         @Override\r
306         public int getConstantSize() {\r
307             return constantSize;\r
308         }        \r
309         @Override\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
314             }\r
315             else {\r
316                 Construction construction = (Construction)obj;\r
317                 // FIXME validate construction.constructor\r
318                 buffer.needs(4);\r
319                 buffer.putInt(construction.constructor);\r
320                 baseTypes[construction.constructor].serialize(buffer, construction.value);\r
321             }\r
322         }\r
323         @Override\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
329         }\r
330         @Override\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
336             return ret;\r
337         }\r
338     }\r
339 \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
344 \r
345         public VariableLengthArrayType(ValueType baseType) {\r
346             this.baseType = baseType;\r
347             baseTypeConstantSize = baseType.getConstantSize();\r
348             supportsNativeArray = baseType.supportsNativeArray();\r
349         }\r
350 \r
351         @Override\r
352         public int getConstantSize() {\r
353             return -1;\r
354         }        \r
355 \r
356         @Override\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
365                 }\r
366                 else if(supportsNativeArray) \r
367                     baseType.serializeNativeArray(buffer, obj, -1);\r
368                 else\r
369                     ; // TODO exc\r
370 \r
371             }\r
372             else {\r
373                 Object[] subobjects = (Object[])obj;              \r
374                 buffer.needs(4);\r
375                 buffer.putInt(subobjects.length);\r
376                 for(Object subobj : subobjects)\r
377                     baseType.serialize(buffer, subobj);\r
378             }\r
379         }\r
380         @Override\r
381         public void  unsafeSerialize(ByteBuffer buffer, Object obj) {\r
382             // TODO Throw exception\r
383         }\r
384         @Override\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
389             else {\r
390                 Object[] ret = new Object[length];\r
391                 for(int i=0;i<length;++i)\r
392                     ret[i] = baseType.deserialize(buffer);\r
393                 return ret;\r
394             }\r
395         }\r
396     }\r
397 \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
403 \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
411             }\r
412         }\r
413 \r
414         @Override\r
415         public int getConstantSize() {\r
416             return constantSize;\r
417         }        \r
418 \r
419         @Override\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
424             }\r
425             else {\r
426                 Object[] subobjects = (Object[])obj;              \r
427                 // FIXME checks\r
428                 for(Object subobj : subobjects)\r
429                     baseType.serialize(buffer, subobj);\r
430             }\r
431         }\r
432         @Override\r
433         public void  unsafeSerialize(ByteBuffer buffer, Object obj) {\r
434             if(supportsNativeArray)\r
435                 baseType.serializeNativeArray(buffer, obj, dimension);\r
436             else {\r
437                 Object[] subobjects = (Object[])obj;              \r
438                 // FIXME checks\r
439                 for(Object subobj : subobjects)\r
440                     baseType.unsafeSerialize(buffer, subobj);\r
441             }\r
442         }\r
443         @Override\r
444         public Object deserialize(ByteBuffer buffer) {\r
445             if(supportsNativeArray) \r
446                 return baseType.deserializeNativeArray(buffer, dimension);\r
447             else {\r
448                 Object[] ret = new Object[dimension];\r
449                 for(int i=0;i<dimension;++i)\r
450                     ret[i] = baseType.deserialize(buffer);\r
451                 return ret;\r
452             }\r
453         }\r
454     }    \r
455 \r
456     static final private class ByteBuffer {\r
457         public byte[] bytes;\r
458         public int    offset;\r
459 \r
460         public ByteBuffer(int capacity) {\r
461             this.bytes = new byte[capacity];\r
462             this.offset = 0;\r
463         }\r
464 \r
465         public ByteBuffer(byte[] bytes) {\r
466             this.bytes = bytes;\r
467             this.offset = 0;\r
468         }\r
469 \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
476                 bytes = newBytes;\r
477             }\r
478         }\r
479 \r
480         public byte[] content() {\r
481             if(offset == bytes.length)\r
482                 return bytes;\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
487             return newBytes;\r
488         }\r
489 \r
490         public void putByte(byte v) {\r
491             bytes[offset] = v;\r
492             offset += 1;\r
493         }\r
494         public void putShort(short v) {\r
495             bytes[offset] = (byte) v;\r
496             bytes[offset+1] = (byte) (v >>> 8);\r
497             offset += 2;\r
498         }\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
504             offset += 4;\r
505         }\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
515             offset += 8;\r
516         }\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
523             offset += 4;\r
524         }\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
535             offset += 8;\r
536         }\r
537         public void putString(String str) {\r
538 \r
539             // UTF-16 -> modified UTF-8\r
540 \r
541             int length = 4;\r
542             for(int i=0;i<str.length();++i) {\r
543                 char c = str.charAt(i);\r
544                 if(c < 0x80)\r
545                     length += 1;\r
546                 else if(c < 0x800)\r
547                     length += 2;\r
548                 else \r
549                     length += 3;\r
550             }\r
551             needs(length);\r
552             putInt(str.length());\r
553             for(int i=0;i<str.length();++i) {\r
554                 char c = str.charAt(i);\r
555                 if(c < 0x80) {\r
556                     bytes[offset] = (byte)c;\r
557                     offset += 1;\r
558                 }\r
559                 else if(c < 0x800) {\r
560                     bytes[offset]   = (byte)(0xc0 + (c >>> 6));\r
561                     bytes[offset+1] = (byte)(0x80 + (c & 0x3f));\r
562                     offset += 2;\r
563                 }\r
564                 else {\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
569                     offset += 3;\r
570                 }\r
571             }\r
572         }\r
573         public byte getByte() {\r
574             ++offset;\r
575             return bytes[offset-1];\r
576         }\r
577         public short getShort() {\r
578             int v = bytes[offset] & 0xFF;\r
579             v += (bytes[offset+1] & 0xFF) << 8;\r
580             offset += 2;\r
581             return (short)v;\r
582         }\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
588             offset += 4;\r
589             return v;\r
590         }\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
600             offset += 8;\r
601             return v;\r
602         }\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
608             offset += 4;\r
609             return Float.intBitsToFloat(v);\r
610         }\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
620             offset += 8;\r
621             return Double.longBitsToDouble(v);\r
622         }\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
628                 int c;\r
629                 if(b0 >= 0) {\r
630                     c = b0;\r
631                     offset += 1;\r
632                 }\r
633                 else if(b0 < 0xe0-256) {\r
634                     c = ((b0 & 0x1f) << 6) +\r
635                         (bytes[offset+1] & 0x3f);\r
636                     offset += 2;\r
637                 }\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
642                     offset += 3;\r
643                 }\r
644                 else\r
645                     c = 0; // FIXME\r
646                 chars[i] = (char)c;\r
647             }\r
648             return new String(chars);\r
649         }\r
650         \r
651     }\r
652     \r
653 }\r