/******************************************************************************* * Copyright (c) 2010 Association for Decentralized Information Management in * Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.databoard.type; import java.util.Set; import org.simantics.databoard.accessor.error.ReferenceException; import org.simantics.databoard.accessor.reference.ChildReference; import org.simantics.databoard.accessor.reference.IndexReference; import org.simantics.databoard.accessor.reference.KeyReference; import org.simantics.databoard.accessor.reference.LabelReference; import org.simantics.databoard.accessor.reference.NameReference; import org.simantics.databoard.util.IdentityPair; import org.simantics.databoard.util.Limit; import org.simantics.databoard.util.ObjectUtils; import org.simantics.databoard.util.Range; import org.simantics.databoard.util.RangeException; public class ArrayType extends Datatype { /** Metadata key for array length */ public static final String KEY_LENGTH = "length"; private transient Range _length; private transient String _lengthIsForStr; public Datatype componentType; public ArrayType() {} public ArrayType(Datatype componentType) { this.componentType = componentType; } public ArrayType(Datatype componentType, String length) { this.componentType = componentType; setLength(length); } public ArrayType(Datatype componentType, Range length) { this.componentType = componentType; setLength(length); } @Override public int getComponentCount() { return 1; } @Override public Datatype getComponentType(int index) { if (index!=0) throw new IllegalArgumentException(); return componentType; } @Override public Datatype getComponentType(ChildReference path) { if (path==null) return this; if (path instanceof KeyReference) throw new IllegalArgumentException("KeyReference is not supported in ArrayType"); if (path instanceof NameReference) throw new IllegalArgumentException("NameReference is not supported in ArrayType"); if (path instanceof IndexReference && ((IndexReference) path).index!=0) throw new IllegalArgumentException("Index out of bounds"); if (path instanceof LabelReference && !((LabelReference) path).label.equals("v")) throw new IllegalArgumentException("Unknown label"); return componentType.getComponentType(path.childReference); } @Override protected void collectSubtypes(Set subtypes, Set recursiveSubtypes) { componentType.collectSubtypes(subtypes, recursiveSubtypes); } @Override protected boolean deepEquals(Object obj, Set> compareHistory) { if ( this==obj ) return true; if ( !hasEqualMetadata(obj) ) return false; if (obj instanceof ArrayType == false) return false; ArrayType other = (ArrayType) obj; return componentType.deepEquals(other.componentType, compareHistory); } @Override public int hashCode() { if (componentType==this) return 0; return 0x234ae + metadataHashCode() + 13* ObjectUtils.hashCode(componentType); } @Override public void accept(Visitor1 v, Object obj) { v.visit(this, obj); } @Override public T accept(Visitor v) { return v.visit(this); } public Datatype componentType() { return componentType; } @Deprecated public Datatype getComponentType() { return componentType; } public void setComponentType(Datatype componentType) { this.componentType = componentType; } public int minLength() { Range length = getLength(); if (length==null) return 0; Limit l = length.getLower(); int value = l.getValue().intValue(); if (l.isExclusive()) value++; return value; } public int maxLength() { Range length = getLength(); if (length==null) return Integer.MAX_VALUE; Limit l = length.getUpper(); int value = l.getValue().intValue(); if (l.isExclusive()) value--; return value; } public Range getLength() { String lengthStr = metadata.get( KEY_LENGTH ); if (lengthStr == null) return null; if (_length != null && lengthStr!=null && lengthStr==_lengthIsForStr) return _length; try { _lengthIsForStr = lengthStr; _length = Range.valueOf( lengthStr ); } catch (RangeException e) { _length = null; } return _length; } public String getLengthStr() { return metadata.get( KEY_LENGTH ); } public void setLength(String length) { _length = null; _lengthIsForStr = null; if ( length == null ) { metadata.remove( KEY_LENGTH ); } else { metadata.put( KEY_LENGTH, length ); } } public void setLength(Range range) { if (range==null) { metadata.remove( KEY_LENGTH ); _length = null; _lengthIsForStr = null; } else { _length = range; _lengthIsForStr = range.toString(); metadata.put( KEY_LENGTH, _lengthIsForStr ); } } @SuppressWarnings("unchecked") @Override public T getChildType(ChildReference reference) throws ReferenceException { if (reference==null) return (T) this; if (reference instanceof LabelReference) { LabelReference lr = (LabelReference) reference; try { Integer.valueOf( lr.label ); return componentType.getChildType(reference.getChildReference()); } catch ( NumberFormatException nfe ) { throw new ReferenceException(nfe); } } else if (reference instanceof IndexReference) { return componentType.getChildType(reference.getChildReference()); } throw new ReferenceException(reference.getClass().getName()+" is not a reference of an array"); } }