]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/type/UnionType.java
Added addFirst/After/Before + remove SCL functions for Ordered Sets
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / type / UnionType.java
1 /*******************************************************************************
2  *  Copyright (c) 2010 Association for Decentralized Information Management in
3  *  Industry THTH ry.
4  *  All rights reserved. This program and the accompanying materials
5  *  are made available under the terms of the Eclipse Public License v1.0
6  *  which accompanies this distribution, and is available at
7  *  http://www.eclipse.org/legal/epl-v10.html
8  *
9  *  Contributors:
10  *      VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.databoard.type;
13
14 import java.util.HashSet;
15 import java.util.Set;
16
17 import org.simantics.databoard.Datatypes;
18 import org.simantics.databoard.accessor.error.ReferenceException;
19 import org.simantics.databoard.accessor.reference.ChildReference;
20 import org.simantics.databoard.accessor.reference.ComponentReference;
21 import org.simantics.databoard.accessor.reference.IndexReference;
22 import org.simantics.databoard.accessor.reference.LabelReference;
23 import org.simantics.databoard.accessor.reference.NameReference;
24 import org.simantics.databoard.annotations.Referable;
25 import org.simantics.databoard.util.IdentityPair;
26
27 public @Referable class UnionType extends Datatype {
28         
29         public static UnionType newEnum(String...choices) {
30                 UnionType result = new UnionType();
31                 for ( String choice : choices ) result.addComponent(choice, Datatypes.VOID);            
32                 return result;
33         }
34         
35         public static final Component[] NO_COMPONENTS = new Component[0];
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     
46     public void addComponent(String name, Datatype type)
47     {
48         Component c = new Component(name, type);
49         if (components == null) {
50                 components = new Component[] { c };
51         } else {
52                 Component[] newComponents = new Component[ components.length +1 ];
53                 System.arraycopy(components, 0, newComponents, 0, components.length);
54                 newComponents[ components.length ] = c;
55                 components = newComponents;     
56         }       
57     }
58     
59     public void removeComponent(String tagName) {
60         int index = getComponentIndex2(tagName);
61         if (index<0) return;
62                 Component[] newComponents = new Component[ components.length -1 ];
63                 if (index>0) System.arraycopy(components, 0, newComponents, 0, index);
64                 if (index<newComponents.length) System.arraycopy(components, index+1, newComponents, index, newComponents.length - index);
65                 components = newComponents;     
66                 // xxx untested
67     }
68
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;
85                 if ( !hasEqualMetadata(obj) ) return false;
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         }
134         
135         @Override
136         public Datatype getComponentType(ChildReference path) {
137                 if (path==null) return this;
138                 if (path instanceof IndexReference) {
139                         IndexReference ir = (IndexReference) path;
140                         return components[ir.index].type.getComponentType(path.childReference);
141                 }
142                 if (path instanceof NameReference) {
143                         NameReference nr = (NameReference) path;
144                         return getComponent( nr.name ).type.getComponentType(path.childReference);
145                 }
146                 if (path instanceof LabelReference) {
147                         LabelReference lr = (LabelReference) path;                      
148                         try {
149                                 Integer i = new Integer(lr.label);
150                                 return getComponent( i ).type.getComponentType(path.childReference);
151                         } catch (NumberFormatException nfe) {
152                                 return getComponent( lr.label ).type.getComponentType(path.childReference);
153                         }
154                 }
155                 throw new IllegalArgumentException();
156         }
157         
158         public Component getComponent(int i) {
159                 return components[i];
160         }
161         
162         public Component[] getComponents() {
163                 return components;
164         }
165             
166     /**
167      * Get tag by name.
168      * 
169      * @param fieldName component name
170      * @return component index or <code>null</code> if one does not exist
171      */
172     public Integer getComponentIndex(String fieldName) {
173         for (int i=0; i<components.length; i++)
174             if (components[i].name.equals(fieldName)) return i;
175         return null;
176     }
177     
178     /**
179      * Get tag by name.
180      * 
181      * @param fieldName component name
182      * @return component index or -1 if one does not exist
183      */
184     public int getComponentIndex2(String fieldName) {
185         for (int i=0; i<components.length; i++)
186             if (components[i].name.equals(fieldName)) return i;
187         return -1;
188     }
189     
190
191     /**
192      * Get component Datatype by field name
193      * @param fieldName
194      * @return datatype or <code>null</code>
195      */
196     public Datatype getComponentType(String fieldName) {
197         int index = getComponentIndex2(fieldName);
198         if (index<0) return null;
199         return components[index].type;
200     }
201     
202     /**
203      * Get component by name.
204      * 
205      * @param fieldName component name
206      * @return component or <code>null</code> if one does not exist
207      */
208     public Component getComponent(String fieldName) {
209         for (Component c : components)
210             if (c.name.equals(fieldName)) return c;
211         return null;
212     }
213
214         @Override
215         public Datatype getComponentType(int index) {
216                 return components[index].type;  
217         }
218         
219         /**
220          * UnionType is enumeration if all its components are empty records
221          * @return true if enumeration type
222          */
223         public boolean isEnumeration() {
224                 boolean isEnum = true;
225                 for (Component c : components) isEnum &= c.type.equals( Datatypes.VOID );
226                 return isEnum;
227         }
228
229         @SuppressWarnings("unchecked")
230         @Override
231         public <T extends Datatype> T getChildType(ChildReference reference) throws ReferenceException {
232                 if (reference==null) return (T) this;
233                 
234                 if (reference instanceof LabelReference) {
235                         LabelReference lr = (LabelReference) reference;
236                         int tag = getComponentIndex( lr.label );
237                         
238                         if (tag<0 && lr.label.equals("uv")) {
239                                 throw new ReferenceException("Cannot get component reference without an instance");
240                         }
241                         
242                         return components[tag].type.getChildType(reference.getChildReference());                                                
243                 }
244                 
245                 if (reference instanceof ComponentReference) {
246                         throw new ReferenceException("Cannot get component reference without an instance");
247                 }
248                 
249                 if (reference instanceof IndexReference) {
250                         IndexReference ir = (IndexReference) reference;
251                         int tag = ir.index;
252                         if (tag<0 || tag>=getComponentCount()) throw new ReferenceException("Tag index out of bounds");
253                         return components[tag].type.getChildType(reference.getChildReference());
254                 }
255                 
256                 if (reference instanceof NameReference) {
257                         NameReference nr = (NameReference) reference;
258                         int tag = getComponentIndex2( nr.name );
259                         if (tag<0) throw new ReferenceException("Tag by name \""+nr.name+"\" is not found");
260                         return components[tag].type.getChildType(reference.getChildReference());
261                 }
262                 
263                 throw new ReferenceException(reference.getClass()+" is not a reference of UnionType");
264         }
265         
266 }