]> gerrit.simantics Code Review - simantics/platform.git/blob - 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
1 /*******************************************************************************\r
2  *  Copyright (c) 2010 Association for Decentralized Information Management in\r
3  *  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.databoard.type;
13
14 import java.util.HashSet;\r
15 import java.util.Set;\r
16 \r
17 import org.simantics.databoard.Datatypes;\r
18 import org.simantics.databoard.accessor.error.ReferenceException;\r
19 import org.simantics.databoard.accessor.reference.ChildReference;\r
20 import org.simantics.databoard.accessor.reference.ComponentReference;\r
21 import org.simantics.databoard.accessor.reference.IndexReference;\r
22 import org.simantics.databoard.accessor.reference.LabelReference;\r
23 import org.simantics.databoard.accessor.reference.NameReference;\r
24 import org.simantics.databoard.annotations.Referable;\r
25 import org.simantics.databoard.util.IdentityPair;\r
26
27 public @Referable class UnionType extends Datatype {
28         \r
29         public static UnionType newEnum(String...choices) {\r
30                 UnionType result = new UnionType();\r
31                 for ( String choice : choices ) result.addComponent(choice, Datatypes.VOID);            \r
32                 return result;\r
33         }\r
34         \r
35         public static final Component[] NO_COMPONENTS = new Component[0];\r
36         
37     public Component[] components = NO_COMPONENTS;
38     
39     public UnionType() {}
40     
41     public UnionType(Component...components) {
42         if (components.length==0) throw new IllegalArgumentException("need atleast 1 tag type");
43         this.components = components;
44     }
45     \r
46     public void addComponent(String name, Datatype type)\r
47     {\r
48         Component c = new Component(name, type);\r
49         if (components == null) {\r
50                 components = new Component[] { c };\r
51         } else {\r
52                 Component[] newComponents = new Component[ components.length +1 ];\r
53                 System.arraycopy(components, 0, newComponents, 0, components.length);\r
54                 newComponents[ components.length ] = c;\r
55                 components = newComponents;     \r
56         }       \r
57     }\r
58     \r
59     public void removeComponent(String tagName) {\r
60         int index = getComponentIndex2(tagName);\r
61         if (index<0) return;\r
62                 Component[] newComponents = new Component[ components.length -1 ];\r
63                 if (index>0) System.arraycopy(components, 0, newComponents, 0, index);\r
64                 if (index<newComponents.length) System.arraycopy(components, index+1, newComponents, index, newComponents.length - index);\r
65                 components = newComponents;     \r
66                 // xxx untested\r
67     }\r
68 \r
69     
70     @Override
71     protected void collectSubtypes(Set<Datatype> subtypes,
72                 Set<Datatype> recursiveSubtypes) {
73         if(!subtypes.add(this)) {
74                 recursiveSubtypes.add(this);
75                 return;
76         }
77         for(Component component : components)
78                 component.type.collectSubtypes(subtypes, recursiveSubtypes);
79     }
80     
81     @Override
82     protected boolean deepEquals(Object obj,
83                 Set<IdentityPair<Datatype, Datatype>> compareHistory) {         
84                 if (this==obj) return true;\r
85                 if ( !hasEqualMetadata(obj) ) return false;\r
86                 if (obj instanceof UnionType == false) return false;
87                 UnionType other = (UnionType) obj;
88                                 
89                 if (components.length!= other.components.length) return false;
90                 // Verify names
91                 for (int i = 0; i<components.length; i++) {
92                         Component lc = components[i];
93                         Component rc = other.components[i];
94                         if (!lc.name.equals(rc.name)) return false;
95                         
96                 }
97
98                 // Verify types
99                 if (compareHistory==null) compareHistory = new HashSet<IdentityPair<Datatype, Datatype>>(1);
100
101                 IdentityPair<Datatype, Datatype> pair = new IdentityPair<Datatype, Datatype>(this, other);
102                 if (compareHistory.contains(pair)) return true;
103                 compareHistory.add(pair);
104                 
105                 for (int i = 0; i<components.length; i++) {
106                         Component lc = components[i];
107                         Component rc = other.components[i];
108                         if (!lc.type.deepEquals(rc.type, compareHistory)) return false;
109                 }
110                 return true;
111         }
112         
113         @Override
114         public int hashCode() {
115                 int hash = 42342345;
116                 for (Component c : components) 
117                         hash = hash*7 + c.name.hashCode();
118                 return hash;
119         }
120     
121         @Override
122         public void accept(Visitor1 v, Object obj) {
123             v.visit(this, obj);        
124         }
125
126         @Override
127         public <T> T accept(Visitor<T> v) {
128             return v.visit(this);
129         }
130         
131         public int getComponentCount() {
132                 return components.length;
133         }\r
134         \r
135         @Override\r
136         public Datatype getComponentType(ChildReference path) {\r
137                 if (path==null) return this;\r
138                 if (path instanceof IndexReference) {\r
139                         IndexReference ir = (IndexReference) path;\r
140                         return components[ir.index].type.getComponentType(path.childReference);\r
141                 }\r
142                 if (path instanceof NameReference) {\r
143                         NameReference nr = (NameReference) path;\r
144                         return getComponent( nr.name ).type.getComponentType(path.childReference);\r
145                 }\r
146                 if (path instanceof LabelReference) {\r
147                         LabelReference lr = (LabelReference) path;                      \r
148                         try {\r
149                                 Integer i = new Integer(lr.label);\r
150                                 return getComponent( i ).type.getComponentType(path.childReference);\r
151                         } catch (NumberFormatException nfe) {\r
152                                 return getComponent( lr.label ).type.getComponentType(path.childReference);\r
153                         }\r
154                 }\r
155                 throw new IllegalArgumentException();\r
156         }
157         
158         public Component getComponent(int i) {
159                 return components[i];
160         }
161         
162         public Component[] getComponents() {
163                 return components;
164         }
165             \r
166     /**\r
167      * Get tag by name.\r
168      * \r
169      * @param fieldName component name\r
170      * @return component index or <code>null</code> if one does not exist\r
171      */\r
172     public Integer getComponentIndex(String fieldName) {\r
173         for (int i=0; i<components.length; i++)\r
174             if (components[i].name.equals(fieldName)) return i;\r
175         return null;\r
176     }\r
177     \r
178     /**\r
179      * Get tag by name.\r
180      * \r
181      * @param fieldName component name\r
182      * @return component index or -1 if one does not exist\r
183      */\r
184     public int getComponentIndex2(String fieldName) {\r
185         for (int i=0; i<components.length; i++)\r
186             if (components[i].name.equals(fieldName)) return i;\r
187         return -1;\r
188     }\r
189     \r
190 \r
191     /**\r
192      * Get component Datatype by field name\r
193      * @param fieldName\r
194      * @return datatype or <code>null</code>\r
195      */\r
196     public Datatype getComponentType(String fieldName) {\r
197         int index = getComponentIndex2(fieldName);\r
198         if (index<0) return null;\r
199         return components[index].type;\r
200     }\r
201     \r
202     /**\r
203      * Get component by name.\r
204      * \r
205      * @param fieldName component name\r
206      * @return component or <code>null</code> if one does not exist\r
207      */\r
208     public Component getComponent(String fieldName) {\r
209         for (Component c : components)\r
210             if (c.name.equals(fieldName)) return c;\r
211         return null;\r
212     }\r
213 \r
214         @Override\r
215         public Datatype getComponentType(int index) {\r
216                 return components[index].type;  \r
217         }\r
218         \r
219         /**\r
220          * UnionType is enumeration if all its components are empty records\r
221          * @return true if enumeration type\r
222          */\r
223         public boolean isEnumeration() {\r
224                 boolean isEnum = true;\r
225                 for (Component c : components) isEnum &= c.type.equals( Datatypes.VOID );\r
226                 return isEnum;\r
227         }\r
228 \r
229         @SuppressWarnings("unchecked")\r
230         @Override\r
231         public <T extends Datatype> T getChildType(ChildReference reference) throws ReferenceException {\r
232                 if (reference==null) return (T) this;\r
233                 \r
234                 if (reference instanceof LabelReference) {\r
235                         LabelReference lr = (LabelReference) reference;\r
236                         int tag = getComponentIndex( lr.label );\r
237                         \r
238                         if (tag<0 && lr.label.equals("uv")) {\r
239                                 throw new ReferenceException("Cannot get component reference without an instance");\r
240                         }\r
241                         \r
242                         return components[tag].type.getChildType(reference.getChildReference());                                                \r
243                 }\r
244                 \r
245                 if (reference instanceof ComponentReference) {\r
246                         throw new ReferenceException("Cannot get component reference without an instance");\r
247                 }\r
248                 \r
249                 if (reference instanceof IndexReference) {\r
250                         IndexReference ir = (IndexReference) reference;\r
251                         int tag = ir.index;\r
252                         if (tag<0 || tag>=getComponentCount()) throw new ReferenceException("Tag index out of bounds");\r
253                         return components[tag].type.getChildType(reference.getChildReference());\r
254                 }\r
255                 \r
256                 if (reference instanceof NameReference) {\r
257                         NameReference nr = (NameReference) reference;\r
258                         int tag = getComponentIndex2( nr.name );\r
259                         if (tag<0) throw new ReferenceException("Tag by name \""+nr.name+"\" is not found");\r
260                         return components[tag].type.getChildType(reference.getChildReference());\r
261                 }\r
262                 \r
263                 throw new ReferenceException(reference.getClass()+" is not a reference of UnionType");\r
264         }\r
265         
266 }