1 /*******************************************************************************
\r
2 * Copyright (c) 2010 Association for Decentralized Information Management in
\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
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.databoard.type;
14 import java.util.HashSet;
\r
15 import java.util.Set;
\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
27 public @Referable class UnionType extends Datatype {
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
35 public static final Component[] NO_COMPONENTS = new Component[0];
\r
37 public Component[] components = NO_COMPONENTS;
41 public UnionType(Component...components) {
42 if (components.length==0) throw new IllegalArgumentException("need atleast 1 tag type");
43 this.components = components;
46 public void addComponent(String name, Datatype type)
\r
48 Component c = new Component(name, type);
\r
49 if (components == null) {
\r
50 components = new Component[] { c };
\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
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
71 protected void collectSubtypes(Set<Datatype> subtypes,
72 Set<Datatype> recursiveSubtypes) {
73 if(!subtypes.add(this)) {
74 recursiveSubtypes.add(this);
77 for(Component component : components)
78 component.type.collectSubtypes(subtypes, recursiveSubtypes);
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;
89 if (components.length!= other.components.length) return false;
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;
99 if (compareHistory==null) compareHistory = new HashSet<IdentityPair<Datatype, Datatype>>(1);
101 IdentityPair<Datatype, Datatype> pair = new IdentityPair<Datatype, Datatype>(this, other);
102 if (compareHistory.contains(pair)) return true;
103 compareHistory.add(pair);
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;
114 public int hashCode() {
116 for (Component c : components)
117 hash = hash*7 + c.name.hashCode();
122 public void accept(Visitor1 v, Object obj) {
127 public <T> T accept(Visitor<T> v) {
128 return v.visit(this);
131 public int getComponentCount() {
132 return components.length;
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
142 if (path instanceof NameReference) {
\r
143 NameReference nr = (NameReference) path;
\r
144 return getComponent( nr.name ).type.getComponentType(path.childReference);
\r
146 if (path instanceof LabelReference) {
\r
147 LabelReference lr = (LabelReference) path;
\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
155 throw new IllegalArgumentException();
\r
158 public Component getComponent(int i) {
159 return components[i];
162 public Component[] getComponents() {
169 * @param fieldName component name
\r
170 * @return component index or <code>null</code> if one does not exist
\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
181 * @param fieldName component name
\r
182 * @return component index or -1 if one does not exist
\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
192 * Get component Datatype by field name
\r
194 * @return datatype or <code>null</code>
\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
203 * Get component by name.
\r
205 * @param fieldName component name
\r
206 * @return component or <code>null</code> if one does not exist
\r
208 public Component getComponent(String fieldName) {
\r
209 for (Component c : components)
\r
210 if (c.name.equals(fieldName)) return c;
\r
215 public Datatype getComponentType(int index) {
\r
216 return components[index].type;
\r
220 * UnionType is enumeration if all its components are empty records
\r
221 * @return true if enumeration type
\r
223 public boolean isEnumeration() {
\r
224 boolean isEnum = true;
\r
225 for (Component c : components) isEnum &= c.type.equals( Datatypes.VOID );
\r
229 @SuppressWarnings("unchecked")
\r
231 public <T extends Datatype> T getChildType(ChildReference reference) throws ReferenceException {
\r
232 if (reference==null) return (T) this;
\r
234 if (reference instanceof LabelReference) {
\r
235 LabelReference lr = (LabelReference) reference;
\r
236 int tag = getComponentIndex( lr.label );
\r
238 if (tag<0 && lr.label.equals("uv")) {
\r
239 throw new ReferenceException("Cannot get component reference without an instance");
\r
242 return components[tag].type.getChildType(reference.getChildReference());
\r
245 if (reference instanceof ComponentReference) {
\r
246 throw new ReferenceException("Cannot get component reference without an instance");
\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
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
263 throw new ReferenceException(reference.getClass()+" is not a reference of UnionType");
\r