/******************************************************************************* * Copyright 2014 Analog Devices, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ********************************************************************************/ package com.analog.lyric.dimple.parameters; import java.util.Iterator; import java.util.concurrent.atomic.AtomicInteger; import net.jcip.annotations.ThreadSafe; import com.analog.lyric.dimple.exceptions.DimpleException; import org.eclipse.jdt.annotation.Nullable; @ThreadSafe public abstract class AbstractParameterList<Key extends IParameterKey> implements IParameterList<Key> { private static final long serialVersionUID = 1L; /*---------------- * Object methods */ @Override public abstract AbstractParameterList<Key> clone(); /*------------------ * Iterable methods */ private class IteratorImpl implements Iterator<Parameter<Key>> { private final AtomicInteger _index = new AtomicInteger(0); private final @Nullable Key[] _keys = getKeys(); @Override public boolean hasNext() { return _index.get() < size(); } @Override public Parameter<Key> next() { int i = _index.getAndIncrement(); boolean shared = true; SharedParameterValue value = getSharedValue(i); if (value == null) { shared = false; value = new SharedParameterValue(get(i)); } final Key[] keys = _keys; return new Parameter<Key>(keys != null ? keys[i] : null, i, value, isFixed(i), shared); } @Override public void remove() { throw new UnsupportedOperationException("remove"); } } @Override public Iterator<Parameter<Key>> iterator() { return new IteratorImpl(); } /*------------------------------ * IFactorParameterList methods */ @Override public double get(Key key) { assertHasKeys("get"); return get(key.ordinal()); } @Override public @Nullable SharedParameterValue getSharedValue(Key key) { assertHasKeys("getSharedValue"); return getSharedValue(key.ordinal()); } @Override public double[] getValues() { double[] values = new double[size()]; for (int i = values.length; --i>=0; ) { values[i] = get(i); } return values; } @Override public boolean hasKeys() { return getKeys() != null; } @Override public boolean isFixed(Key key) { assertHasKeys("isFixed"); return isFixed(key.ordinal()); } @Override public boolean isShared(Key key) { assertHasKeys("isShared"); return isShared(key.ordinal()); } @Override public void set(Key key, double value) { assertHasKeys("set"); set(key.ordinal(), value); } @Override public void setAll(Iterable<Parameter<Key>> values) { for (Parameter<Key> value : values) { Key key = value.key(); if (key != null) { set(key, value.value()); } else { set(value.index(), value.value()); } } } @Override public void setAll(double ... values) { for (int i = 0, end = values.length; i < end; ++i) { set(i, values[i]); } } @Override public void setAllToDefault() { if (hasKeys()) { Key[] keys = getKeys(); if (keys != null) { for (int i = 0, end = keys.length; i < end; ++i) { if (!isFixed(i)) { set(i, keys[i].defaultValue()); } } } } } @Override public void setAllMissing() { for (int i = 0, end = size(); i < end; ++ i) { if (!isFixed(i)) { set(i, Double.NaN); } } } @Override public void setFixed(Key key, boolean fixed) { assertHasKeys("setFixed"); setFixed(key.ordinal(), fixed); } @Override public void setShared(Key key, boolean shared) { assertHasKeys("setShared"); setShared(key.ordinal(), shared); } @Override public void setSharedValue(Key key, @Nullable SharedParameterValue value) { assertHasKeys("setSharedValue"); setSharedValue(key.ordinal(), value); } /*------------------------- * Subclass helper methods */ protected void assertHasKeys(String operation) { if (!hasKeys()) { throw expectedKeys(operation); } } protected UnsupportedOperationException expectedKeys(String operation) { throw new UnsupportedOperationException( String.format("Attempt to invoke '%s' with key on keyless parameter list", operation)); } protected void assertNotFixed(int index) { if (isFixed(index)) { throw expectedNotFixed(index); } } protected DimpleException expectedNotFixed(int index) { Key[] keys = getKeys(); return new DimpleException("Attempt to modify fixed parameter '%s'.", keys != null ? keys[index] : index); } protected void assertIndexInRange(int index) { if (index < 0 || index >= size()) { throw indexOutOfRange(index); } } protected IndexOutOfBoundsException indexOutOfRange(int index) { return new IndexOutOfBoundsException( String.format("Parameter index '%d' is out of allowed range [0,%d]", index, size() - 1)); } /** * Subclasses can override this to respond to changes to option with given index. * This should be called *after* the value has changed. * <p> * Subclasses that implement {@link #set(int, double)} or that implement modification without * call that method, should invoke this after the value has been set. */ protected void valueChanged(int index) { } }