javolution.util.Index Maven / Gradle / Ivy
/*
* Javolution - Java(TM) Solution for Real-Time and Embedded Systems
* Copyright (C) 2012 - Javolution (http://javolution.org/)
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software is
* freely granted, provided that this notice is preserved.
*/
package javolution.util;
import java.io.IOException;
import java.io.ObjectStreamException;
import javolution.lang.Configurable;
import javolution.lang.MathLib;
import javolution.lang.Realtime;
import javolution.lang.ValueType;
import javolution.text.Cursor;
import javolution.text.DefaultTextFormat;
import javolution.text.TextContext;
import javolution.text.TextFormat;
import javolution.text.TypeFormat;
import javolution.util.internal.table.ConstantTableImpl;
/**
* A non-negative number representing a position in an arrangement.
* [code]
* interface Vector {
* Vector getSubVector(List indices);
* // e.g. getSubVector(Index.rangeOf(0, n)) for the n first elements.
* ...
* }[/code]
* Index performance is on-par with the primitive {@code int} type
* for small values and similar to {@link Integer} instances for large
* values. Small indexes have no adverse effect on the garbage collector
* and have fast {@link #equals(Object) equals} method due to their unicity.
*
* @author Jean-Marie Dautelle
* @version 5.1, July 26, 2007
*/
@Realtime
@DefaultTextFormat(Index.Decimal.class)
public final class Index extends Number implements Comparable,
ValueType {
/**
* Default text format for indices (decimal value representation).
*/
public static class Decimal extends TextFormat {
@Override
public Appendable format(Index obj, Appendable dest) throws IOException {
return TypeFormat.format(obj.intValue(), dest);
}
@Override
public Index parse(CharSequence csq, Cursor cursor)
throws IllegalArgumentException {
return Index.of(TypeFormat.parseInt(csq, cursor));
}
}
/**
* Holds the number of unique preallocated instances (default {@code 1024}).
* This number is configurable, for example with
* {@code -Djavolution.util.Index#UNIQUE=0} there is no unique instance.
*/
public static final Configurable UNIQUE = new Configurable() {
@Override
protected Integer getDefault() {
return 1024;
}
@Override
protected Integer initialized(Integer value) {
return MathLib.min(value, 65536); // Hard-limiting
}
@Override
protected Integer reconfigured(Integer oldCount, Integer newCount) {
throw new UnsupportedOperationException(
"Unicity reconfiguration not supported.");
}
};
/**
* Holds the index zero (value 0
).
*/
public static final Index ZERO = new Index(0);
private static final long serialVersionUID = 0x600L; // Version.
private static final Index[] INSTANCES = new Index[UNIQUE.get()];
static {
INSTANCES[0] = ZERO;
for (int i = 1; i < INSTANCES.length; i++) {
INSTANCES[i] = new Index(i);
}
}
private static final ConstantTable INSTANCES_TABLE = new ConstantTable(
new ConstantTableImpl(INSTANCES));
/**
* Returns the index for the specified {@code int} non-negative
* value (returns a preallocated instance if the specified value is
* small).
*
* @param value the index value.
* @return the corresponding index.
* @throws IndexOutOfBoundsException if value < 0
*/
public static Index of(int value) {
return (value < INSTANCES.length) ? INSTANCES[value] : new Index(value);
}
/**
* Returns the indices having the specified {@code int} non-negative
* values (convenience method).
*
* @param values the indices values.
* @return the corresponding table.
*/
public static FastTable listOf(int... values) {
Index[] indices = new Index[values.length];
for (int i = 0; i < indices.length; i++) {
indices[i] = Index.of(values[i]);
}
return new ConstantTable(new ConstantTableImpl(indices));
}
/**
* Returns the indices having the specified range of {@code int} non-negative
* values (convenience method). A sub-table view over preallocated
* instances is returned when possible.
*
* @param fromIndex low endpoint (inclusive) of the list to return.
* @param toIndex high endpoint (exclusive) of the list to return.
* @return the corresponding indices.
*/
public static ConstantTable rangeOf(int fromIndex, int toIndex) {
if (toIndex <= INSTANCES.length)
return INSTANCES_TABLE.subTable(fromIndex, toIndex); // Optimization.
Index[] indices = new Index[toIndex - fromIndex];
for (int i = fromIndex, j = 0; i < toIndex; i++) {
indices[j++] = Index.of(i);
}
return new ConstantTable(new ConstantTableImpl(indices));
}
/**
* Holds the index value.
*/
private final int value;
/**
* Creates an index having the specified value.
*/
private Index(int value) {
this.value = value;
}
/**
* Compares this index with the specified index for order. Returns a
* negative integer, zero, or a positive integer as this index is less
* than, equal to, or greater than the specified index.
*
* @param that the index to be compared.
* @return a negative integer, zero, or a positive integer as this index
* is less than, equal to, or greater than the specified index.
*/
public int compareTo(Index that) {
return this.value - that.value;
}
/**
* Compares this index with the specified integer value for order. Returns a
* negative integer, zero, or a positive integer as this index is less
* than, equal to, or greater than the specified value.
*
* @param value the value to be compared.
* @return a negative integer, zero, or a positive integer as this index
* is less than, equal to, or greater than the specified value.
*/
public int compareTo(int value) {
return this.value - value;
}
/**
* Returns a copy of this index or this
if the indexes
* is small (in permanent memory) in order to maintain unicity.
*/
public Index copy() {
return value < INSTANCES.length ? this : new Index(value);
}
/**
* Returns the index value as double
.
*
* @return the index value.
*/
public double doubleValue() {
return (double) value;
}
/**
* Indicates if this index is equals to the one specified (for small
* indices this method is equivalent to ==
).
*/
@Override
public boolean equals(Object obj) {
return (this.value < INSTANCES.length) ? (this == obj)
: ((obj instanceof Index) ? (((Index) obj).value == value)
: false);
}
/**
* Returns the index value as float
.
*
* @return the index value.
*/
public float floatValue() {
return (float) value;
}
/**
* Returns the hash code for this index.
*/
@Override
public int hashCode() {
return value;
}
/**
* Returns the index value as int
.
*
* @return the index value.
*/
public int intValue() {
return value;
}
/**
* Indicates if this index is zero.
*
* @return {@code this == ZERO}
*/
public boolean isZero() {
return this == ZERO;
}
/**
* Returns the index value as long
.
*
* @return the index value.
*/
public long longValue() {
return value;
}
/**
* Returns the index after this one.
*/
public Index next() {
return Index.of(value + 1);
}
/**
* Returns the index before this one.
*
* @throws IndexOutOfBoundsException if (this == Index.ZERO)
*/
public Index previous() {
return Index.of(value - 1);
}
/**
* Ensures index unicity during deserialization.
*/
protected final Object readResolve() throws ObjectStreamException {
return Index.of(value);
}
/**
* Returns the {@link String} representation of this index.
*
* @return {@code TextContext.getFormat(Index.class).format(this)}
*/
@Override
public String toString() {
return TextContext.getFormat(Index.class).format(this);
}
}