]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/serialization/impl/ArraySerializer.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / serialization / impl / ArraySerializer.java
1 package org.simantics.databoard.serialization.impl;\r
2 \r
3 import gnu.trove.map.hash.TObjectIntHashMap;\r
4 \r
5 import java.io.DataInput;\r
6 import java.io.DataOutput;\r
7 import java.io.IOException;\r
8 import java.util.ArrayList;\r
9 import java.util.Iterator;\r
10 import java.util.List;\r
11 \r
12 import org.simantics.databoard.binding.ArrayBinding;\r
13 import org.simantics.databoard.binding.Binding;\r
14 import org.simantics.databoard.binding.error.BindingException;\r
15 import org.simantics.databoard.binding.impl.ArrayListBinding;\r
16 import org.simantics.databoard.binding.util.IsReferableQuery;\r
17 import org.simantics.databoard.binding.util.Result;\r
18 import org.simantics.databoard.serialization.SerializationException;\r
19 import org.simantics.databoard.serialization.Serializer;\r
20 import org.simantics.databoard.serialization.Serializer.CompositeSerializer;\r
21 import org.simantics.databoard.type.ArrayType;\r
22 import org.simantics.databoard.util.Range;\r
23 \r
24 public class ArraySerializer extends CompositeSerializer {\r
25 \r
26         Range length;\r
27         Integer fixedLength;\r
28         Integer fixedSize;\r
29         Integer fixedSizeOfComponent;\r
30         public Serializer componentSerializer;\r
31         boolean componentImmutable;\r
32         ArrayBinding binding;\r
33         DefaultValueIterator componentValueItr;\r
34         \r
35         /**\r
36          * \r
37          * @param binding\r
38          * @param componentSerializer (optional) can be set after\r
39          */\r
40         public ArraySerializer(ArrayBinding binding, Serializer componentSerializer) {\r
41                 super( IsReferableQuery.isReferable( binding.type() ) != Result.No );\r
42                 ArrayType arrayType = (ArrayType) binding.type();\r
43                 this.componentSerializer = componentSerializer;\r
44                 this.binding = binding;\r
45                 this.length = arrayType.getLength();\r
46                 this.componentImmutable = binding.getComponentBinding().isImmutable();\r
47                 this.componentValueItr = new DefaultValueIterator();\r
48                 componentValueItr.binding = binding.componentBinding;\r
49         }\r
50         \r
51         @Override\r
52         public void finalizeConstruction() {\r
53                 fixedSizeOfComponent = componentSerializer.getConstantSize();\r
54                 if (fixedSizeOfComponent!=null && length!=null && length.getLower().equals(length.getUpper()) && length.getLower().getValue()!=null)\r
55                 {\r
56                         fixedLength = length.getLower().getValue().intValue();\r
57                         fixedSize = fixedLength * fixedSizeOfComponent;\r
58                 }               \r
59         }\r
60 \r
61         @Override\r
62         public Object deserialize(DataInput in, List<Object> identities) throws IOException {\r
63                 try {\r
64                         int length = fixedLength != null ? fixedLength : in.readInt();  \r
65                         if (length<0) throw new SerializationException("Cannot use negative array length");\r
66                         assertRemainingBytes(in, ((long)length)*componentSerializer.getMinSize());                      \r
67 \r
68                         ArrayList<Object> temp = new ArrayList<Object>(length);\r
69                         for(int i=0;i<length;++i)\r
70                                 temp.add(componentSerializer.deserialize(in, identities));\r
71                         return binding instanceof ArrayListBinding ? temp : binding.create(temp);\r
72                 } catch (BindingException e) {\r
73                         throw new IOException( e ); \r
74                 }\r
75         }\r
76         \r
77         public Object deserializeToTry(DataInput in, List<Object> identities, Object obj) throws IOException\r
78         {\r
79                 try {\r
80                         int length = fixedLength != null ? fixedLength : in.readInt();\r
81                         if (length<0) throw new SerializationException("Cannot use negative array length");\r
82                         assertRemainingBytes(in, ((long)length)*componentSerializer.getMinSize());                      \r
83                         \r
84                         int oldLen = binding.size(obj);\r
85                         \r
86                         if (oldLen!=length) {\r
87                                 if ( binding.isResizable() ) {\r
88                                         binding.setSize(obj, length);\r
89                                 } else {\r
90                                         obj = binding.create(length, componentValueItr);\r
91                                         oldLen = length;\r
92                                 }\r
93                         }\r
94                         \r
95                         if ( componentImmutable ) {\r
96                                 for(int i=0;i<length;i++) {\r
97                                         Object component = componentSerializer.deserialize(in, identities);\r
98                                         binding.set(obj, i, component);\r
99                                 }\r
100                         } else {\r
101                                 for(int i=0;i<length;i++) {\r
102                                         Object component = binding.get(obj, i);\r
103                                         component = componentSerializer.deserializeToTry(in, identities, component);\r
104                                         binding.set(obj, i, component); \r
105                                 }\r
106                                 if (oldLen>length) binding.setSize(obj, length);                                \r
107                         }\r
108                         \r
109                         return obj;\r
110                 } catch (BindingException e) {\r
111                         throw new IOException( e ); \r
112                 }\r
113                 \r
114         }       \r
115 \r
116         @Override\r
117         public void deserializeTo(DataInput in, List<Object> identities, Object obj) throws IOException {\r
118                 try {\r
119                         int length = fixedLength != null ? fixedLength : in.readInt();\r
120                         if (length<0) throw new SerializationException("Cannot use negative array length");\r
121                         assertRemainingBytes(in, ((long)length)*componentSerializer.getMinSize());                      \r
122                         \r
123                         int oldLen = binding.size(obj);\r
124                         \r
125                         if (oldLen!=length) {\r
126                                 if ( binding.isResizable() ) {\r
127                                         binding.setSize(obj, length);\r
128                                 } else {\r
129                                         throw new IOException("Cannot resize array");\r
130                                 }\r
131                         }\r
132                         \r
133                         if ( componentImmutable ) {\r
134                                 for(int i=0;i<length;i++) {\r
135                                         Object component = componentSerializer.deserialize(in, identities);\r
136                                         binding.set(obj, i, component);\r
137                                 }\r
138                         } else {\r
139                                 for(int i=0;i<length;i++) {\r
140                                         Object component = binding.get(obj, i);\r
141                                         component = componentSerializer.deserializeToTry(in, identities, component);\r
142                                         binding.set(obj, i, component); \r
143                                 }\r
144                                 if (oldLen>length) binding.setSize(obj, length);                                \r
145                         }\r
146                 } catch (BindingException e) {\r
147                         throw new IOException( e ); \r
148                 }               \r
149         }\r
150         \r
151         @Override\r
152         public void skip(DataInput in, List<Object> identities)\r
153         throws IOException {\r
154                 if (fixedSize!=null) {\r
155                         in.skipBytes(fixedSize);\r
156                         return;\r
157                 }\r
158                 int length = fixedLength != null ? fixedLength : in.readInt();\r
159                 \r
160                 if (fixedSizeOfComponent!=null) {\r
161                         // Skip all elements\r
162                         in.skipBytes(length * fixedSizeOfComponent);\r
163                 } else {\r
164                         // Skip each element individualy\r
165                         for(int i=0;i<length;++i)\r
166                                 componentSerializer.skip(in, identities);\r
167                 }\r
168         }\r
169 \r
170         @Override\r
171         public void serialize(DataOutput out, TObjectIntHashMap<Object> identities, Object obj) throws IOException {\r
172                 try {\r
173                         int length = binding.size(obj);\r
174                         if (fixedLength==null) {\r
175                                 out.writeInt(length);\r
176                         } else { \r
177                                 if (length!=fixedLength)\r
178                                         throw new SerializationException("Unexpected array length "+length+", size is restricted to "+fixedLength);\r
179                         }\r
180                         \r
181                         // Serialize elements\r
182                         for(int i=0;i<length;++i)\r
183                                 componentSerializer.serialize(out, identities, binding.get(obj, i));\r
184                 } catch (BindingException e) {\r
185                         throw new IOException( e ); \r
186                 }\r
187         }\r
188 \r
189         @Override\r
190         public Integer getConstantSize() {\r
191                 return fixedSize;\r
192         }\r
193 \r
194         @Override\r
195         public int getSize(Object obj, TObjectIntHashMap<Object> identities) throws IOException {\r
196                 try {\r
197                         if (fixedSize!=null) return fixedSize;\r
198                         int length = binding.size(obj);\r
199                         if (fixedSizeOfComponent!=null)\r
200                                 return 4 + fixedSizeOfComponent * length;\r
201                         int result = 4;\r
202                         for(int i=0;i<length;++i)\r
203                                 result += componentSerializer.getSize(binding.get(obj, i), identities);\r
204                         return result;\r
205                 } catch (BindingException e) {\r
206                         throw new IOException( e ); \r
207                 }\r
208         }\r
209 \r
210         @Override\r
211         public int getMinSize() {\r
212                 return fixedSize != null ? fixedSize : 4;\r
213         }\r
214         \r
215 }\r
216 \r
217 /**\r
218  * Default value iterator iterates default values.\r
219  * The iterator is infinite.\r
220  * \r
221  * @author toni.kalajainen\r
222  */\r
223 class DefaultValueIterator implements Iterator<Object> {\r
224         \r
225         Binding binding;\r
226 \r
227         @Override\r
228         public boolean hasNext() {\r
229                 return true;\r
230         }\r
231 \r
232         @Override\r
233         public Object next() {\r
234                 try {\r
235                         return binding.createDefault();\r
236                 } catch (BindingException e) {\r
237                         return null;\r
238                 }\r
239         }\r
240 \r
241         @Override\r
242         public void remove() {\r
243         }\r
244         \r
245 }