]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - 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
diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/serialization/impl/ArraySerializer.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/serialization/impl/ArraySerializer.java
new file mode 100644 (file)
index 0000000..3831882
--- /dev/null
@@ -0,0 +1,245 @@
+package org.simantics.databoard.serialization.impl;\r
+\r
+import gnu.trove.map.hash.TObjectIntHashMap;\r
+\r
+import java.io.DataInput;\r
+import java.io.DataOutput;\r
+import java.io.IOException;\r
+import java.util.ArrayList;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+\r
+import org.simantics.databoard.binding.ArrayBinding;\r
+import org.simantics.databoard.binding.Binding;\r
+import org.simantics.databoard.binding.error.BindingException;\r
+import org.simantics.databoard.binding.impl.ArrayListBinding;\r
+import org.simantics.databoard.binding.util.IsReferableQuery;\r
+import org.simantics.databoard.binding.util.Result;\r
+import org.simantics.databoard.serialization.SerializationException;\r
+import org.simantics.databoard.serialization.Serializer;\r
+import org.simantics.databoard.serialization.Serializer.CompositeSerializer;\r
+import org.simantics.databoard.type.ArrayType;\r
+import org.simantics.databoard.util.Range;\r
+\r
+public class ArraySerializer extends CompositeSerializer {\r
+\r
+       Range length;\r
+       Integer fixedLength;\r
+       Integer fixedSize;\r
+       Integer fixedSizeOfComponent;\r
+       public Serializer componentSerializer;\r
+       boolean componentImmutable;\r
+       ArrayBinding binding;\r
+       DefaultValueIterator componentValueItr;\r
+       \r
+       /**\r
+        * \r
+        * @param binding\r
+        * @param componentSerializer (optional) can be set after\r
+        */\r
+       public ArraySerializer(ArrayBinding binding, Serializer componentSerializer) {\r
+               super( IsReferableQuery.isReferable( binding.type() ) != Result.No );\r
+               ArrayType arrayType = (ArrayType) binding.type();\r
+               this.componentSerializer = componentSerializer;\r
+               this.binding = binding;\r
+               this.length = arrayType.getLength();\r
+               this.componentImmutable = binding.getComponentBinding().isImmutable();\r
+               this.componentValueItr = new DefaultValueIterator();\r
+               componentValueItr.binding = binding.componentBinding;\r
+       }\r
+       \r
+       @Override\r
+       public void finalizeConstruction() {\r
+               fixedSizeOfComponent = componentSerializer.getConstantSize();\r
+               if (fixedSizeOfComponent!=null && length!=null && length.getLower().equals(length.getUpper()) && length.getLower().getValue()!=null)\r
+               {\r
+                       fixedLength = length.getLower().getValue().intValue();\r
+                       fixedSize = fixedLength * fixedSizeOfComponent;\r
+               }               \r
+       }\r
+\r
+       @Override\r
+       public Object deserialize(DataInput in, List<Object> identities) throws IOException {\r
+               try {\r
+                       int length = fixedLength != null ? fixedLength : in.readInt();  \r
+                       if (length<0) throw new SerializationException("Cannot use negative array length");\r
+                       assertRemainingBytes(in, ((long)length)*componentSerializer.getMinSize());                      \r
+\r
+                       ArrayList<Object> temp = new ArrayList<Object>(length);\r
+                       for(int i=0;i<length;++i)\r
+                               temp.add(componentSerializer.deserialize(in, identities));\r
+                       return binding instanceof ArrayListBinding ? temp : binding.create(temp);\r
+               } catch (BindingException e) {\r
+                       throw new IOException( e ); \r
+               }\r
+       }\r
+       \r
+       public Object deserializeToTry(DataInput in, List<Object> identities, Object obj) throws IOException\r
+       {\r
+               try {\r
+                       int length = fixedLength != null ? fixedLength : in.readInt();\r
+                       if (length<0) throw new SerializationException("Cannot use negative array length");\r
+                       assertRemainingBytes(in, ((long)length)*componentSerializer.getMinSize());                      \r
+                       \r
+                       int oldLen = binding.size(obj);\r
+                       \r
+                       if (oldLen!=length) {\r
+                               if ( binding.isResizable() ) {\r
+                                       binding.setSize(obj, length);\r
+                               } else {\r
+                                       obj = binding.create(length, componentValueItr);\r
+                                       oldLen = length;\r
+                               }\r
+                       }\r
+                       \r
+                       if ( componentImmutable ) {\r
+                               for(int i=0;i<length;i++) {\r
+                                       Object component = componentSerializer.deserialize(in, identities);\r
+                                       binding.set(obj, i, component);\r
+                               }\r
+                       } else {\r
+                               for(int i=0;i<length;i++) {\r
+                                       Object component = binding.get(obj, i);\r
+                                       component = componentSerializer.deserializeToTry(in, identities, component);\r
+                                       binding.set(obj, i, component); \r
+                               }\r
+                               if (oldLen>length) binding.setSize(obj, length);                                \r
+                       }\r
+                       \r
+                       return obj;\r
+               } catch (BindingException e) {\r
+                       throw new IOException( e ); \r
+               }\r
+               \r
+       }       \r
+\r
+       @Override\r
+       public void deserializeTo(DataInput in, List<Object> identities, Object obj) throws IOException {\r
+               try {\r
+                       int length = fixedLength != null ? fixedLength : in.readInt();\r
+                       if (length<0) throw new SerializationException("Cannot use negative array length");\r
+                       assertRemainingBytes(in, ((long)length)*componentSerializer.getMinSize());                      \r
+                       \r
+                       int oldLen = binding.size(obj);\r
+                       \r
+                       if (oldLen!=length) {\r
+                               if ( binding.isResizable() ) {\r
+                                       binding.setSize(obj, length);\r
+                               } else {\r
+                                       throw new IOException("Cannot resize array");\r
+                               }\r
+                       }\r
+                       \r
+                       if ( componentImmutable ) {\r
+                               for(int i=0;i<length;i++) {\r
+                                       Object component = componentSerializer.deserialize(in, identities);\r
+                                       binding.set(obj, i, component);\r
+                               }\r
+                       } else {\r
+                               for(int i=0;i<length;i++) {\r
+                                       Object component = binding.get(obj, i);\r
+                                       component = componentSerializer.deserializeToTry(in, identities, component);\r
+                                       binding.set(obj, i, component); \r
+                               }\r
+                               if (oldLen>length) binding.setSize(obj, length);                                \r
+                       }\r
+               } catch (BindingException e) {\r
+                       throw new IOException( e ); \r
+               }               \r
+       }\r
+       \r
+       @Override\r
+       public void skip(DataInput in, List<Object> identities)\r
+       throws IOException {\r
+               if (fixedSize!=null) {\r
+                       in.skipBytes(fixedSize);\r
+                       return;\r
+               }\r
+               int length = fixedLength != null ? fixedLength : in.readInt();\r
+               \r
+               if (fixedSizeOfComponent!=null) {\r
+                       // Skip all elements\r
+                       in.skipBytes(length * fixedSizeOfComponent);\r
+               } else {\r
+                       // Skip each element individualy\r
+                       for(int i=0;i<length;++i)\r
+                               componentSerializer.skip(in, identities);\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public void serialize(DataOutput out, TObjectIntHashMap<Object> identities, Object obj) throws IOException {\r
+               try {\r
+                       int length = binding.size(obj);\r
+                       if (fixedLength==null) {\r
+                               out.writeInt(length);\r
+                       } else { \r
+                               if (length!=fixedLength)\r
+                                       throw new SerializationException("Unexpected array length "+length+", size is restricted to "+fixedLength);\r
+                       }\r
+                       \r
+                       // Serialize elements\r
+                       for(int i=0;i<length;++i)\r
+                               componentSerializer.serialize(out, identities, binding.get(obj, i));\r
+               } catch (BindingException e) {\r
+                       throw new IOException( e ); \r
+               }\r
+       }\r
+\r
+       @Override\r
+       public Integer getConstantSize() {\r
+               return fixedSize;\r
+       }\r
+\r
+       @Override\r
+       public int getSize(Object obj, TObjectIntHashMap<Object> identities) throws IOException {\r
+               try {\r
+                       if (fixedSize!=null) return fixedSize;\r
+                       int length = binding.size(obj);\r
+                       if (fixedSizeOfComponent!=null)\r
+                               return 4 + fixedSizeOfComponent * length;\r
+                       int result = 4;\r
+                       for(int i=0;i<length;++i)\r
+                               result += componentSerializer.getSize(binding.get(obj, i), identities);\r
+                       return result;\r
+               } catch (BindingException e) {\r
+                       throw new IOException( e ); \r
+               }\r
+       }\r
+\r
+       @Override\r
+       public int getMinSize() {\r
+               return fixedSize != null ? fixedSize : 4;\r
+       }\r
+       \r
+}\r
+\r
+/**\r
+ * Default value iterator iterates default values.\r
+ * The iterator is infinite.\r
+ * \r
+ * @author toni.kalajainen\r
+ */\r
+class DefaultValueIterator implements Iterator<Object> {\r
+       \r
+       Binding binding;\r
+\r
+       @Override\r
+       public boolean hasNext() {\r
+               return true;\r
+       }\r
+\r
+       @Override\r
+       public Object next() {\r
+               try {\r
+                       return binding.createDefault();\r
+               } catch (BindingException e) {\r
+                       return null;\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public void remove() {\r
+       }\r
+       \r
+}
\ No newline at end of file