]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.databoard/src/org/simantics/databoard/type/UnionType.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / type / UnionType.java
diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/type/UnionType.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/type/UnionType.java
new file mode 100644 (file)
index 0000000..005fb03
--- /dev/null
@@ -0,0 +1,266 @@
+/*******************************************************************************\r
+ *  Copyright (c) 2010 Association for Decentralized Information Management in\r
+ *  Industry THTH ry.\r
+ *  All rights reserved. This program and the accompanying materials\r
+ *  are made available under the terms of the Eclipse Public License v1.0\r
+ *  which accompanies this distribution, and is available at\r
+ *  http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ *  Contributors:\r
+ *      VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.databoard.type;
+
+import java.util.HashSet;\r
+import java.util.Set;\r
+\r
+import org.simantics.databoard.Datatypes;\r
+import org.simantics.databoard.accessor.error.ReferenceException;\r
+import org.simantics.databoard.accessor.reference.ChildReference;\r
+import org.simantics.databoard.accessor.reference.ComponentReference;\r
+import org.simantics.databoard.accessor.reference.IndexReference;\r
+import org.simantics.databoard.accessor.reference.LabelReference;\r
+import org.simantics.databoard.accessor.reference.NameReference;\r
+import org.simantics.databoard.annotations.Referable;\r
+import org.simantics.databoard.util.IdentityPair;\r
+
+public @Referable class UnionType extends Datatype {
+       \r
+       public static UnionType newEnum(String...choices) {\r
+               UnionType result = new UnionType();\r
+               for ( String choice : choices ) result.addComponent(choice, Datatypes.VOID);            \r
+               return result;\r
+       }\r
+       \r
+       public static final Component[] NO_COMPONENTS = new Component[0];\r
+       
+    public Component[] components = NO_COMPONENTS;
+    
+    public UnionType() {}
+    
+    public UnionType(Component...components) {
+       if (components.length==0) throw new IllegalArgumentException("need atleast 1 tag type");
+       this.components = components;
+    }
+    \r
+    public void addComponent(String name, Datatype type)\r
+    {\r
+       Component c = new Component(name, type);\r
+       if (components == null) {\r
+               components = new Component[] { c };\r
+       } else {\r
+               Component[] newComponents = new Component[ components.length +1 ];\r
+               System.arraycopy(components, 0, newComponents, 0, components.length);\r
+               newComponents[ components.length ] = c;\r
+               components = newComponents;     \r
+       }       \r
+    }\r
+    \r
+    public void removeComponent(String tagName) {\r
+       int index = getComponentIndex2(tagName);\r
+       if (index<0) return;\r
+               Component[] newComponents = new Component[ components.length -1 ];\r
+               if (index>0) System.arraycopy(components, 0, newComponents, 0, index);\r
+               if (index<newComponents.length) System.arraycopy(components, index+1, newComponents, index, newComponents.length - index);\r
+               components = newComponents;     \r
+               // xxx untested\r
+    }\r
+\r
+    
+    @Override
+    protected void collectSubtypes(Set<Datatype> subtypes,
+               Set<Datatype> recursiveSubtypes) {
+       if(!subtypes.add(this)) {
+               recursiveSubtypes.add(this);
+               return;
+       }
+       for(Component component : components)
+               component.type.collectSubtypes(subtypes, recursiveSubtypes);
+    }
+    
+    @Override
+    protected boolean deepEquals(Object obj,
+               Set<IdentityPair<Datatype, Datatype>> compareHistory) {         
+               if (this==obj) return true;\r
+               if ( !hasEqualMetadata(obj) ) return false;\r
+               if (obj instanceof UnionType == false) return false;
+               UnionType other = (UnionType) obj;
+                               
+               if (components.length!= other.components.length) return false;
+               // Verify names
+               for (int i = 0; i<components.length; i++) {
+                       Component lc = components[i];
+                       Component rc = other.components[i];
+                       if (!lc.name.equals(rc.name)) return false;
+                       
+               }
+
+               // Verify types
+               if (compareHistory==null) compareHistory = new HashSet<IdentityPair<Datatype, Datatype>>(1);
+
+               IdentityPair<Datatype, Datatype> pair = new IdentityPair<Datatype, Datatype>(this, other);
+               if (compareHistory.contains(pair)) return true;
+               compareHistory.add(pair);
+               
+               for (int i = 0; i<components.length; i++) {
+                       Component lc = components[i];
+                       Component rc = other.components[i];
+                       if (!lc.type.deepEquals(rc.type, compareHistory)) return false;
+               }
+               return true;
+       }
+       
+       @Override
+       public int hashCode() {
+               int hash = 42342345;
+               for (Component c : components) 
+                       hash = hash*7 + c.name.hashCode();
+               return hash;
+       }
+    
+       @Override
+       public void accept(Visitor1 v, Object obj) {
+           v.visit(this, obj);        
+       }
+
+       @Override
+       public <T> T accept(Visitor<T> v) {
+           return v.visit(this);
+       }
+       
+       public int getComponentCount() {
+               return components.length;
+       }\r
+       \r
+       @Override\r
+       public Datatype getComponentType(ChildReference path) {\r
+               if (path==null) return this;\r
+               if (path instanceof IndexReference) {\r
+                       IndexReference ir = (IndexReference) path;\r
+                       return components[ir.index].type.getComponentType(path.childReference);\r
+               }\r
+               if (path instanceof NameReference) {\r
+                       NameReference nr = (NameReference) path;\r
+                       return getComponent( nr.name ).type.getComponentType(path.childReference);\r
+               }\r
+               if (path instanceof LabelReference) {\r
+                       LabelReference lr = (LabelReference) path;                      \r
+                       try {\r
+                               Integer i = new Integer(lr.label);\r
+                               return getComponent( i ).type.getComponentType(path.childReference);\r
+                       } catch (NumberFormatException nfe) {\r
+                               return getComponent( lr.label ).type.getComponentType(path.childReference);\r
+                       }\r
+               }\r
+               throw new IllegalArgumentException();\r
+       }
+       
+       public Component getComponent(int i) {
+               return components[i];
+       }
+       
+       public Component[] getComponents() {
+               return components;
+       }
+           \r
+    /**\r
+     * Get tag by name.\r
+     * \r
+     * @param fieldName component name\r
+     * @return component index or <code>null</code> if one does not exist\r
+     */\r
+    public Integer getComponentIndex(String fieldName) {\r
+        for (int i=0; i<components.length; i++)\r
+            if (components[i].name.equals(fieldName)) return i;\r
+        return null;\r
+    }\r
+    \r
+    /**\r
+     * Get tag by name.\r
+     * \r
+     * @param fieldName component name\r
+     * @return component index or -1 if one does not exist\r
+     */\r
+    public int getComponentIndex2(String fieldName) {\r
+        for (int i=0; i<components.length; i++)\r
+            if (components[i].name.equals(fieldName)) return i;\r
+        return -1;\r
+    }\r
+    \r
+\r
+    /**\r
+     * Get component Datatype by field name\r
+     * @param fieldName\r
+     * @return datatype or <code>null</code>\r
+     */\r
+    public Datatype getComponentType(String fieldName) {\r
+       int index = getComponentIndex2(fieldName);\r
+       if (index<0) return null;\r
+       return components[index].type;\r
+    }\r
+    \r
+    /**\r
+     * Get component by name.\r
+     * \r
+     * @param fieldName component name\r
+     * @return component or <code>null</code> if one does not exist\r
+     */\r
+    public Component getComponent(String fieldName) {\r
+        for (Component c : components)\r
+            if (c.name.equals(fieldName)) return c;\r
+        return null;\r
+    }\r
+\r
+       @Override\r
+       public Datatype getComponentType(int index) {\r
+               return components[index].type;  \r
+       }\r
+       \r
+       /**\r
+        * UnionType is enumeration if all its components are empty records\r
+        * @return true if enumeration type\r
+        */\r
+       public boolean isEnumeration() {\r
+               boolean isEnum = true;\r
+               for (Component c : components) isEnum &= c.type.equals( Datatypes.VOID );\r
+               return isEnum;\r
+       }\r
+\r
+       @SuppressWarnings("unchecked")\r
+       @Override\r
+       public <T extends Datatype> T getChildType(ChildReference reference) throws ReferenceException {\r
+               if (reference==null) return (T) this;\r
+               \r
+               if (reference instanceof LabelReference) {\r
+                       LabelReference lr = (LabelReference) reference;\r
+                       int tag = getComponentIndex( lr.label );\r
+                       \r
+                       if (tag<0 && lr.label.equals("uv")) {\r
+                               throw new ReferenceException("Cannot get component reference without an instance");\r
+                       }\r
+                       \r
+                       return components[tag].type.getChildType(reference.getChildReference());                                                \r
+               }\r
+               \r
+               if (reference instanceof ComponentReference) {\r
+                       throw new ReferenceException("Cannot get component reference without an instance");\r
+               }\r
+               \r
+               if (reference instanceof IndexReference) {\r
+                       IndexReference ir = (IndexReference) reference;\r
+                       int tag = ir.index;\r
+                       if (tag<0 || tag>=getComponentCount()) throw new ReferenceException("Tag index out of bounds");\r
+                       return components[tag].type.getChildType(reference.getChildReference());\r
+               }\r
+               \r
+               if (reference instanceof NameReference) {\r
+                       NameReference nr = (NameReference) reference;\r
+                       int tag = getComponentIndex2( nr.name );\r
+                       if (tag<0) throw new ReferenceException("Tag by name \""+nr.name+"\" is not found");\r
+                       return components[tag].type.getChildType(reference.getChildReference());\r
+               }\r
+               \r
+               throw new ReferenceException(reference.getClass()+" is not a reference of UnionType");\r
+       }\r
+       
+}