/*
* Copyright (c) 2013-2014, Parallel Universe Software Co. All rights reserved.
*
* This program and the accompanying materials are dual-licensed under
* either the terms of the Eclipse Public License v1.0 as published by
* the Eclipse Foundation
*
* or (per the licensee's choosing)
*
* under the terms of the GNU Lesser General Public License version 3.0
* as published by the Free Software Foundation.
*/
package co.paralleluniverse.data.record;
import com.google.common.reflect.TypeToken;
import java.lang.reflect.Array;
import java.util.Objects;
/**
* A {@link Record record}'s field.
*
* @param <R> The {@link RecordType}
* @param <V> The field {@link #typeClass() type}.
* @author pron
*/
public abstract class Field<R, V> {
public static final int TRANSIENT = 1;
public static <R> BooleanField<R> booleanField(String name, int id, int flags) {
return new BooleanField<R>(name, id, flags);
}
public static <R> BooleanField<R> booleanField(String name, int id) {
return booleanField(name, id, 0);
}
public static <R> ByteField<R> byteField(String name, int id, int flags) {
return new ByteField<R>(name, id, flags);
}
public static <R> ByteField<R> byteField(String name, int id) {
return byteField(name, id, 0);
}
public static <R> ShortField<R> shortField(String name, int id, int flags) {
return new ShortField<R>(name, id, flags);
}
public static <R> ShortField<R> shortField(String name, int id) {
return shortField(name, id, 0);
}
public static <R> IntField<R> intField(String name, int id, int flags) {
return new IntField<R>(name, id, flags);
}
public static <R> IntField<R> intField(String name, int id) {
return intField(name, id, 0);
}
public static <R> LongField<R> longField(String name, int id, int flags) {
return new LongField<R>(name, id, flags);
}
public static <R> LongField<R> longField(String name, int id) {
return longField(name, id, 0);
}
public static <R> FloatField<R> floatField(String name, int id, int flags) {
return new FloatField<R>(name, id, flags);
}
public static <R> FloatField<R> floatField(String name, int id) {
return floatField(name, id, 0);
}
public static <R> DoubleField<R> doubleField(String name, int id, int flags) {
return new DoubleField<R>(name, id, flags);
}
public static <R> DoubleField<R> doubleField(String name, int id) {
return doubleField(name, id, 0);
}
public static <R> CharField<R> charField(String name, int id, int flags) {
return new CharField<R>(name, id, flags);
}
public static <R> CharField<R> charField(String name, int id) {
return charField(name, id, 0);
}
public static <R, V> ObjectField<R, V> objectField(String name, TypeToken<V> type, int id, int flags) {
return new ObjectField<R, V>(name, type.getRawType(), id, flags);
}
public static <R, V> ObjectField<R, V> objectField(String name, TypeToken<V> type, int id) {
return objectField(name, type, id, 0);
}
public static <R, V> ObjectField<R, V> objectField(String name, Class<V> type, int id, int flags) {
return new ObjectField<R, V>(name, type, id, flags);
}
public static <R, V> ObjectField<R, V> objectField(String name, Class<V> type, int id) {
return objectField(name, type, id, 0);
}
public static <R> BooleanArrayField<R> booleanArrayField(String name, int length, int id, int flags) {
return new BooleanArrayField<R>(name, length, id, flags);
}
public static <R> BooleanArrayField<R> booleanArrayField(String name, int length, int id) {
return booleanArrayField(name, length, id, 0);
}
public static <R> ByteArrayField<R> byteArrayField(String name, int length, int id, int flags) {
return new ByteArrayField<R>(name, length, id, flags);
}
public static <R> ByteArrayField<R> byteArrayField(String name, int length, int id) {
return byteArrayField(name, length, id, 0);
}
public static <R> ShortArrayField<R> shortArrayField(String name, int length, int id, int flags) {
return new ShortArrayField<R>(name, length, id, flags);
}
public static <R> ShortArrayField<R> shortArrayField(String name, int length, int id) {
return shortArrayField(name, length, id, 0);
}
public static <R> IntArrayField<R> intArrayField(String name, int length, int id, int flags) {
return new IntArrayField<R>(name, length, id, flags);
}
public static <R> IntArrayField<R> intArrayField(String name, int length, int id) {
return intArrayField(name, length, id, 0);
}
public static <R> LongArrayField<R> longArrayField(String name, int length, int id, int flags) {
return new LongArrayField<R>(name, length, id, flags);
}
public static <R> LongArrayField<R> longArrayField(String name, int length, int id) {
return longArrayField(name, length, id, 0);
}
public static <R> FloatArrayField<R> floatArrayField(String name, int length, int id, int flags) {
return new FloatArrayField<R>(name, length, id, flags);
}
public static <R> FloatArrayField<R> floatArrayField(String name, int length, int id) {
return floatArrayField(name, length, id, 0);
}
public static <R> DoubleArrayField<R> doubleArrayField(String name, int length, int id, int flags) {
return new DoubleArrayField<R>(name, length, id, flags);
}
public static <R> DoubleArrayField<R> doubleArrayField(String name, int length, int id) {
return doubleArrayField(name, length, id, 0);
}
public static <R> CharArrayField<R> charArrayField(String name, int length, int id, int flags) {
return new CharArrayField<R>(name, length, id, flags);
}
public static <R> CharArrayField<R> charArrayField(String name, int length, int id) {
return charArrayField(name, length, id, 0);
}
public static <R, V> ObjectArrayField<R, V> objectArrayField(String name, Class<V> type, int length, int id, int flags) {
return new ObjectArrayField<R, V>(name, type, length, id, flags);
}
public static <R, V> ObjectArrayField<R, V> objectArrayField(String name, Class<V> type, int length, int id) {
return ObjectArrayField.objectArrayField(name, type, length, id, 0);
}
///////////////////////////////////
static final int BOOLEAN = 1;
static final int BYTE = 2;
static final int SHORT = 3;
static final int INT = 4;
static final int LONG = 5;
static final int FLOAT = 6;
static final int DOUBLE = 7;
static final int CHAR = 8;
static final int OBJECT = 9;
static final int BOOLEAN_ARRAY = 11;
static final int BYTE_ARRAY = 12;
static final int SHORT_ARRAY = 13;
static final int INT_ARRAY = 14;
static final int LONG_ARRAY = 15;
static final int FLOAT_ARRAY = 16;
static final int DOUBLE_ARRAY = 17;
static final int CHAR_ARRAY = 18;
static final int OBJECT_ARRAY = 19;
//
static final int BOOLEAN_SIZE = 1;
static final int BYTE_SIZE = 1;
static final int SHORT_SIZE = 2;
static final int CHAR_SIZE = 2;
static final int INT_SIZE = 4;
static final int FLOAT_SIZE = 4;
static final int LONG_SIZE = 8;
static final int DOUBLE_SIZE = 8;
//
final String name;
final int id;
final int flags;
Field(String name, int id, int flags) {
this.name = name;
this.id = id;
this.flags = flags;
}
/**
* The field's id. Ids are unique for fields of the same type in the same {@link RecordType}.
*
* @return the field's id
*/
public final int id() {
if (id == -1)
throw new UnsupportedOperationException("id not set");
return id;
}
/**
* The field's name
*/
public final String name() {
return name;
}
/**
* The field's flags.
*/
public int flags() {
return flags;
}
/**
* Whether or not the field is transient.
*/
public boolean isTransient() {
return (flags & TRANSIENT) != 0;
}
abstract int type();
abstract int size();
/**
* The field's type
*/
public abstract Class<?> typeClass();
abstract void set(Record<? extends R> record, V value);
abstract V get(Record<? extends R> record);
@Override
public final int hashCode() {
int hash = 5;
hash = 97 * hash + type();
hash = 97 * hash + id;
hash = 97 * hash + Objects.hashCode(name);
return hash;
}
@Override
public String toString() {
return name;
}
//////////////
/**
* Represents a scalar field
*
* @param <R> The {@link RecordType}
* @param <V> The field {@link #typeClass() type}.
*/
public static abstract class ScalarField<R, V> extends Field<R, V> {
ScalarField(String name, int id, int flags) {
super(name, id, flags);
}
@Override
public final boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof Field))
return false;
final Field other = (Field) obj;
return id == other.id && type() == other.type() && Objects.equals(name(), other.name());
}
}
/**
* Represents an array field
*
* @param <R> The {@link RecordType}
* @param <V> The field {@link #typeClass() type}.
*/
public static abstract class ArrayField<R, V> extends Field<R, V[]> {
/**
* The array length
*/
public final int length;
ArrayField(String name, int length, int id, int flags) {
super(name, id, flags);
this.length = length;
}
abstract V get(Record<? extends R> record, int index);
abstract void set(Record<? extends R> record, int index, V value);
abstract void get(Record<? extends R> record, V[] target, int offset);
abstract void set(Record<? extends R> record, V[] source, int offset);
@Override
final V[] get(Record<? extends R> record) {
final V[] array = (V[]) new Object[length];
get(record, array, 0);
return array;
}
@Override
final void set(Record<? extends R> record, V[] array) {
set(record, array, 0);
}
@Override
public final boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof ArrayField))
return false;
final ArrayField other = (ArrayField) obj;
return id == other.id && type() == other.type() && length == other.length && Objects.equals(name(), other.name());
}
}
////////////////
/**
* A scalar {@code boolean} field
*
* @param <R> the record type
*/
public static final class BooleanField<R> extends ScalarField<R, Boolean> {
BooleanField(String name, int id, int flags) {
super(name, id, flags);
}
@Override
int type() {
return BOOLEAN;
}
@Override
int size() {
return BOOLEAN_SIZE;
}
@Override
public Class<?> typeClass() {
return boolean.class;
}
@Override
void set(Record<? extends R> record, Boolean value) {
record.set(this, value.booleanValue());
}
@Override
Boolean get(Record<? extends R> record) {
return record.get(this);
}
}
/**
* A scalar {@code byte} field
*
* @param <R> the record type
*/
public static final class ByteField<R> extends ScalarField<R, Byte> {
ByteField(String name, int id, int flags) {
super(name, id, flags);
}
@Override
int type() {
return BYTE;
}
@Override
int size() {
return BYTE_SIZE;
}
@Override
public Class<?> typeClass() {
return byte.class;
}
@Override
void set(Record<? extends R> record, Byte value) {
record.set(this, value.byteValue());
}
@Override
Byte get(Record<? extends R> record) {
return record.get(this);
}
}
/**
* A scalar {@code short} field
*
* @param <R> the record type
*/
public static final class ShortField<R> extends ScalarField<R, Short> {
ShortField(String name, int id, int flags) {
super(name, id, flags);
}
@Override
int type() {
return SHORT;
}
@Override
int size() {
return SHORT_SIZE;
}
@Override
public Class<?> typeClass() {
return short.class;
}
@Override
void set(Record<? extends R> record, Short value) {
record.set(this, value.shortValue());
}
@Override
Short get(Record<? extends R> record) {
return record.get(this);
}
}
/**
* A scalar {@code int} field
*
* @param <R> the record type
*/
public static final class IntField<R> extends ScalarField<R, Integer> {
IntField(String name, int id, int flags) {
super(name, id, flags);
}
@Override
int type() {
return INT;
}
@Override
int size() {
return INT_SIZE;
}
@Override
public Class<?> typeClass() {
return int.class;
}
@Override
void set(Record<? extends R> record, Integer value) {
record.set(this, value.intValue());
}
@Override
Integer get(Record<? extends R> record) {
return record.get(this);
}
}
/**
* A scalar {@code long} field
*
* @param <R> the record type
*/
public static final class LongField<R> extends ScalarField<R, Long> {
LongField(String name, int id, int flags) {
super(name, id, flags);
}
@Override
int type() {
return LONG;
}
@Override
int size() {
return LONG_SIZE;
}
@Override
public Class<?> typeClass() {
return long.class;
}
@Override
void set(Record<? extends R> record, Long value) {
record.set(this, value.longValue());
}
@Override
Long get(Record<? extends R> record) {
return record.get(this);
}
}
/**
* A scalar {@code flaot} field
*
* @param <R> the record type
*/
public static final class FloatField<R> extends ScalarField<R, Float> {
FloatField(String name, int id, int flags) {
super(name, id, flags);
}
@Override
int type() {
return FLOAT;
}
@Override
int size() {
return FLOAT_SIZE;
}
@Override
public Class<?> typeClass() {
return float.class;
}
@Override
void set(Record<? extends R> record, Float value) {
record.set(this, value.floatValue());
}
@Override
Float get(Record<? extends R> record) {
return record.get(this);
}
}
/**
* A scalar {@code double} field
*
* @param <R> the record type
*/
public static final class DoubleField<R> extends ScalarField<R, Double> {
DoubleField(String name, int id, int flags) {
super(name, id, flags);
}
@Override
int type() {
return DOUBLE;
}
@Override
int size() {
return DOUBLE_SIZE;
}
@Override
public Class<?> typeClass() {
return double.class;
}
@Override
void set(Record<? extends R> record, Double value) {
record.set(this, value.doubleValue());
}
@Override
Double get(Record<? extends R> record) {
return record.get(this);
}
}
/**
* A scalar {@code char} field
*
* @param <R> the record type
*/
public static final class CharField<R> extends ScalarField<R, Character> {
CharField(String name, int id, int flags) {
super(name, id, flags);
}
@Override
int type() {
return CHAR;
}
@Override
int size() {
return CHAR_SIZE;
}
@Override
public Class<?> typeClass() {
return char.class;
}
@Override
void set(Record<? extends R> record, Character value) {
record.set(this, value.charValue());
}
@Override
Character get(Record<? extends R> record) {
return record.get(this);
}
}
/**
* A scalar {@code Object} field
*
* @param <R> the record type
* @param <V> the field's type
*/
public static class ObjectField<R, V> extends ScalarField<R, V> {
private final Class<?> clazz;
ObjectField(String name, Class<?> clazz, int id, int flags) {
super(name, id, flags);
this.clazz = clazz;
}
@Override
int type() {
return OBJECT;
}
@Override
int size() {
return 0;
}
@Override
public Class<?> typeClass() {
return clazz;
}
@Override
void set(Record<? extends R> record, V value) {
record.set(this, value);
}
@Override
V get(Record<? extends R> record) {
return record.get(this);
}
}
//////////////////////////
/**
* A {@code boolean} array field
*
* @param <R> the record type
*/
public static final class BooleanArrayField<R> extends ArrayField<R, Boolean> {
BooleanArrayField(String name, int length, int id, int flags) {
super(name, length, id, flags);
}
@Override
int type() {
return BOOLEAN_ARRAY;
}
@Override
int size() {
return BOOLEAN_SIZE * length;
}
@Override
public Class<?> typeClass() {
return boolean[].class;
}
@Override
Boolean get(Record<? extends R> record, int index) {
return record.get(this, index);
}
@Override
void set(Record<? extends R> record, int index, Boolean value) {
record.set(this, index, value.booleanValue());
}
@Override
void get(Record<? extends R> record, Boolean[] target, int offset) {
for (int i = 0; i < length; i++)
target[offset + i] = record.get(this, i);
}
@Override
void set(Record<? extends R> record, Boolean[] source, int offset) {
for (int i = 0; i < length; i++)
record.set(this, i, source[offset + i].booleanValue());
}
}
/**
* A {@code byte} array field
*
* @param <R> the record type
*/
public static final class ByteArrayField<R> extends ArrayField<R, Byte> {
ByteArrayField(String name, int length, int id, int flags) {
super(name, length, id, flags);
}
@Override
int type() {
return BYTE_ARRAY;
}
@Override
int size() {
return BYTE_SIZE * length;
}
@Override
public Class<?> typeClass() {
return byte[].class;
}
@Override
Byte get(Record<? extends R> record, int index) {
return record.get(this, index);
}
@Override
void set(Record<? extends R> record, int index, Byte value) {
record.set(this, index, value.byteValue());
}
@Override
void get(Record<? extends R> record, Byte[] target, int offset) {
for (int i = 0; i < length; i++)
target[offset + i] = record.get(this, i);
}
@Override
void set(Record<? extends R> record, Byte[] source, int offset) {
for (int i = 0; i < length; i++)
record.set(this, i, source[offset + i].byteValue());
}
}
/**
* A {@code short} array field
*
* @param <R> the record type
*/
public static final class ShortArrayField<R> extends ArrayField<R, Short> {
ShortArrayField(String name, int length, int id, int flags) {
super(name, length, id, flags);
}
@Override
int type() {
return SHORT_ARRAY;
}
@Override
int size() {
return SHORT_SIZE * length;
}
@Override
public Class<?> typeClass() {
return short[].class;
}
@Override
Short get(Record<? extends R> record, int index) {
return record.get(this, index);
}
@Override
void set(Record<? extends R> record, int index, Short value) {
record.set(this, index, value.shortValue());
}
@Override
void get(Record<? extends R> record, Short[] target, int offset) {
for (int i = 0; i < length; i++)
target[offset + i] = record.get(this, i);
}
@Override
void set(Record<? extends R> record, Short[] source, int offset) {
for (int i = 0; i < length; i++)
record.set(this, i, source[offset + i].shortValue());
}
}
/**
* An {@code int} array field
*
* @param <R> the record type
*/
public static final class IntArrayField<R> extends ArrayField<R, Integer> {
IntArrayField(String name, int length, int id, int flags) {
super(name, length, id, flags);
}
@Override
int type() {
return INT_ARRAY;
}
@Override
int size() {
return INT_SIZE * length;
}
@Override
public Class<?> typeClass() {
return int[].class;
}
@Override
Integer get(Record<? extends R> record, int index) {
return record.get(this, index);
}
@Override
void set(Record<? extends R> record, int index, Integer value) {
record.set(this, index, value.intValue());
}
@Override
void get(Record<? extends R> record, Integer[] target, int offset) {
for (int i = 0; i < length; i++)
target[offset + i] = record.get(this, i);
}
@Override
void set(Record<? extends R> record, Integer[] source, int offset) {
for (int i = 0; i < length; i++)
record.set(this, i, source[offset + i].intValue());
}
}
/**
* A {@code long} array field
*
* @param <R> the record type
*/
public static final class LongArrayField<R> extends ArrayField<R, Long> {
LongArrayField(String name, int length, int id, int flags) {
super(name, length, id, flags);
}
@Override
int type() {
return LONG_ARRAY;
}
@Override
int size() {
return LONG_SIZE * length;
}
@Override
public Class<?> typeClass() {
return long[].class;
}
@Override
Long get(Record<? extends R> record, int index) {
return record.get(this, index);
}
@Override
void set(Record<? extends R> record, int index, Long value) {
record.set(this, index, value.longValue());
}
@Override
void get(Record<? extends R> record, Long[] target, int offset) {
for (int i = 0; i < length; i++)
target[offset + i] = record.get(this, i);
}
@Override
void set(Record<? extends R> record, Long[] source, int offset) {
for (int i = 0; i < length; i++)
record.set(this, i, source[offset + i].longValue());
}
}
/**
* A {@code float} array field
*
* @param <R> the record type
*/
public static final class FloatArrayField<R> extends ArrayField<R, Float> {
FloatArrayField(String name, int length, int id, int flags) {
super(name, length, id, flags);
}
@Override
int type() {
return FLOAT_ARRAY;
}
@Override
int size() {
return FLOAT_SIZE * length;
}
@Override
public Class<?> typeClass() {
return float[].class;
}
@Override
Float get(Record<? extends R> record, int index) {
return record.get(this, index);
}
@Override
void set(Record<? extends R> record, int index, Float value) {
record.set(this, index, value.floatValue());
}
@Override
void get(Record<? extends R> record, Float[] target, int offset) {
for (int i = 0; i < length; i++)
target[offset + i] = record.get(this, i);
}
@Override
void set(Record<? extends R> record, Float[] source, int offset) {
for (int i = 0; i < length; i++)
record.set(this, i, source[offset + i].floatValue());
}
}
/**
* A {@code double} array field
*
* @param <R> the record type
*/
public static final class DoubleArrayField<R> extends ArrayField<R, Double> {
DoubleArrayField(String name, int length, int id, int flags) {
super(name, length, id, flags);
}
@Override
int type() {
return DOUBLE_ARRAY;
}
@Override
int size() {
return DOUBLE_SIZE * length;
}
@Override
public Class<?> typeClass() {
return double[].class;
}
@Override
Double get(Record<? extends R> record, int index) {
return record.get(this, index);
}
@Override
void set(Record<? extends R> record, int index, Double value) {
record.set(this, index, value.doubleValue());
}
@Override
void get(Record<? extends R> record, Double[] target, int offset) {
for (int i = 0; i < length; i++)
target[offset + i] = record.get(this, i);
}
@Override
void set(Record<? extends R> record, Double[] source, int offset) {
for (int i = 0; i < length; i++)
record.set(this, i, source[offset + i].doubleValue());
}
}
/**
* A {@code char} array field
*
* @param <R> the record type
*/
public static final class CharArrayField<R> extends ArrayField<R, Character> {
CharArrayField(String name, int length, int id, int flags) {
super(name, length, id, flags);
}
@Override
int type() {
return CHAR_ARRAY;
}
@Override
int size() {
return CHAR_SIZE * length;
}
@Override
public Class<?> typeClass() {
return char[].class;
}
@Override
Character get(Record<? extends R> record, int index) {
return record.get(this, index);
}
@Override
void set(Record<? extends R> record, int index, Character value) {
record.set(this, index, value.charValue());
}
@Override
void get(Record<? extends R> record, Character[] target, int offset) {
for (int i = 0; i < length; i++)
target[offset + i] = record.get(this, i);
}
@Override
void set(Record<? extends R> record, Character[] source, int offset) {
for (int i = 0; i < length; i++)
record.set(this, i, source[offset + i].charValue());
}
}
/**
* An {@code Object} array field
*
* @param <R> the record type
* @param <V> the field's element type
*/
public static final class ObjectArrayField<R, V> extends ArrayField<R, V> {
private final Class<V[]> clazz;
ObjectArrayField(String name, Class<V> elemClazz, int length, int id, int flags) {
super(name, length, id, flags);
this.clazz = (Class<V[]>) Array.newInstance(elemClazz, 0).getClass();
}
@Override
int type() {
return OBJECT_ARRAY;
}
@Override
int size() {
return 0;
}
@Override
public Class<?> typeClass() {
return clazz;
}
@Override
V get(Record<? extends R> record, int index) {
return record.get(this, index);
}
@Override
void set(Record<? extends R> record, int index, V value) {
record.set(this, index, value);
}
@Override
void get(Record<? extends R> record, V[] target, int offset) {
for (int i = 0; i < length; i++)
target[offset + i] = record.get(this, i);
}
@Override
void set(Record<? extends R> record, V[] source, int offset) {
for (int i = 0; i < length; i++)
record.set(this, i, source[offset + i]);
}
}
}