AbstractIndexedValue.java
package org.djunits.value;
import org.djunits.Throw;
import org.djunits.unit.Unit;
import org.djunits.value.base.Scalar;
import org.djunits.value.storage.AbstractStorage;
import org.djunits.value.storage.StorageType;
/**
* AbstractIndexedValue.java.
* <p>
* Copyright (c) 2019-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
* BSD-style license. See <a href="https://djunits.org/docs/license.html">DJUNITS License</a>.
* <p>
* @author <a href="https://www.tudelft.nl/averbraeck" target="_blank">Alexander Verbraeck</a>
* @param <U> the unit type
* @param <S> the scalar type for the U unit
* @param <T> the value type for this unit
* @param <D> the data storage type
*/
public abstract class AbstractIndexedValue<U extends Unit<U>, S extends Scalar<U, S>,
T extends AbstractIndexedValue<U, S, T, D>, D extends AbstractStorage<D>> extends AbstractValue<U, T>
implements IndexedValue<U, S, T>, Cloneable
{
/** */
private static final long serialVersionUID = 20190927L;
/** If set, any modification of the data must be preceded by replacing the data with a local copy. */
private boolean copyOnWrite = false;
/** helper flag to indicate whether the data is mutable or not. */
private boolean mutable = false;
/**
* Construct a new AbstractIndexedValue.
* @param unit U; the unit
*/
protected AbstractIndexedValue(final U unit)
{
super(unit);
}
/**
* Retrieve the data object. Method can only be used within package and by subclasses.
* @return D; the internal data
*/
protected abstract D getData();
/**
* Set the data object. Method can only be used within package and by subclasses.
* @param data D; the internal data
*/
protected abstract void setData(D data);
/** {@inheritDoc} */
@Override
public final StorageType getStorageType()
{
return getData().getStorageType();
}
/**
* Check the copyOnWrite flag and, if it is set, make a deep copy of the data and clear the flag.
* @throws ValueRuntimeException if the vector is immutable
*/
protected final void checkCopyOnWrite()
{
Throw.when(!this.mutable, ValueRuntimeException.class, "Immutable Vector cannot be modified");
if (isCopyOnWrite())
{
setData(getData().copy());
setCopyOnWrite(false);
}
}
/**
* Retrieve the value of the copyOnWrite flag.
* @return boolean
*/
protected final boolean isCopyOnWrite()
{
return this.copyOnWrite;
}
/**
* Change the copyOnWrite flag.
* @param copyOnWrite boolean; the new value for the copyOnWrite flag
*/
protected final void setCopyOnWrite(final boolean copyOnWrite)
{
this.copyOnWrite = copyOnWrite;
}
/** {@inheritDoc} */
@Override
public final boolean isMutable()
{
return this.mutable;
}
/**
* Set helper flag to indicate whether the data is mutable or not.
* @param mutable boolean; helper flag to indicate whether the data is mutable or not
*/
protected final void setMutable(final boolean mutable)
{
this.mutable = mutable;
}
/** {@inheritDoc} */
@Override
public final T immutable()
{
if (isMutable())
{
setCopyOnWrite(true);
}
T result = clone();
result.setCopyOnWrite(false);
result.setMutable(false);
return result;
}
/** {@inheritDoc} */
@Override
public final T mutable()
{
if (isMutable())
{
setCopyOnWrite(true);
}
T result = clone();
result.setCopyOnWrite(true);
result.setMutable(true);
return result;
}
/** {@inheritDoc} */
@Override
public final boolean isDense()
{
return getData().isDense();
}
/** {@inheritDoc} */
@Override
public final boolean isSparse()
{
return getData().isSparse();
}
/** {@inheritDoc} */
@Override
public final int cardinality()
{
return getData().cardinality();
}
/** {@inheritDoc} */
@SuppressWarnings("unchecked")
@Override
public T clone()
{
try
{
T result = (T) super.clone();
result.setData(getData().copy());
result.setCopyOnWrite(false);
return result;
}
catch (CloneNotSupportedException exception)
{
throw new RuntimeException(exception);
}
}
}