All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.calcite.linq4j.tree.Primitive Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to you 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 org.apache.calcite.linq4j.tree;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.AbstractList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Enumeration of Java's primitive types.
 *
 * 

There are fields for the native class (e.g. int, also * known as {@link Integer#TYPE}) and the boxing class * (e.g. {@link Integer}).

*/ public enum Primitive { BOOLEAN(Boolean.TYPE, Boolean.class, 1, false, false, null, null, true, -1), BYTE(Byte.TYPE, Byte.class, 2, (byte) 0, Byte.MIN_VALUE, null, null, Byte.MAX_VALUE, Byte.SIZE), CHAR(Character.TYPE, Character.class, 2, (char) 0, Character.MIN_VALUE, null, null, Character.MAX_VALUE, Character.SIZE), SHORT(Short.TYPE, Short.class, 2, (short) 0, Short.MIN_VALUE, null, null, Short.MAX_VALUE, Short.SIZE), INT(Integer.TYPE, Integer.class, 2, 0, Integer.MIN_VALUE, null, null, Integer.MAX_VALUE, Integer.SIZE), LONG(Long.TYPE, Long.class, 2, 0L, Long.MIN_VALUE, null, null, Long.MAX_VALUE, Long.SIZE), FLOAT(Float.TYPE, Float.class, 2, 0F, -Float.MAX_VALUE, -Float.MIN_VALUE, Float.MIN_VALUE, Float.MAX_VALUE, Float.SIZE), DOUBLE(Double.TYPE, Double.class, 2, 0D, -Double.MAX_VALUE, -Double.MIN_VALUE, Double.MIN_VALUE, Double.MAX_VALUE, Double.SIZE), VOID(Void.TYPE, Void.class, 3, null, null, null, null, null, -1), OTHER(null, null, 4, null, null, null, null, null, -1); public final Class primitiveClass; public final Class boxClass; public final String primitiveName; // e.g. "int" public final String boxName; private final int family; /** The default value of this primitive class. This is the value * taken by uninitialized fields, for instance; 0 for {@code int}, false for * {@code boolean}, etc. */ public final Object defaultValue; /** The minimum value of this primitive class. */ public final Object min; /** The largest value that is less than zero. Null if not applicable for this * type. */ public final Object maxNegative; /** The smallest value that is greater than zero. Null if not applicable for * this type. */ public final Object minPositive; /** The maximum value of this primitive class. */ public final Object max; /** The size of a value of this type, in bits. Null if not applicable for this * type. */ public final int size; private static final Map PRIMITIVE_MAP = new HashMap<>(); private static final Map BOX_MAP = new HashMap<>(); static { Primitive[] values = Primitive.values(); for (Primitive value : values) { if (value.primitiveClass != null) { PRIMITIVE_MAP.put(value.primitiveClass, value); } if (value.boxClass != null) { BOX_MAP.put(value.boxClass, value); } } } Primitive(Class primitiveClass, Class boxClass, int family, Object defaultValue, Object min, Object maxNegative, Object minPositive, Object max, int size) { this.primitiveClass = primitiveClass; this.family = family; this.primitiveName = primitiveClass != null ? primitiveClass.getSimpleName() : null; this.boxClass = boxClass; this.boxName = boxClass != null ? boxClass.getSimpleName() : null; this.defaultValue = defaultValue; this.min = min; this.maxNegative = maxNegative; this.minPositive = minPositive; this.max = max; this.size = size; } /** * Returns the Primitive object for a given primitive class. * *

For example, of(long.class) returns {@link #LONG}. * Returns {@code null} when applied to a boxing or other class; for example * of(Long.class) and of(String.class) return * {@code null}. */ public static Primitive of(Type type) { //noinspection SuspiciousMethodCalls return PRIMITIVE_MAP.get(type); } /** * Returns the Primitive object for a given boxing class. * *

For example, ofBox(java.util.Long.class) * returns {@link #LONG}. */ public static Primitive ofBox(Type type) { //noinspection SuspiciousMethodCalls return BOX_MAP.get(type); } /** * Returns the Primitive object for a given primitive or boxing class. * *

For example, ofBoxOr(Long.class) and * ofBoxOr(long.class) both return {@link #LONG}. */ public static Primitive ofBoxOr(Type type) { Primitive primitive = of(type); if (primitive == null) { primitive = ofBox(type); } return primitive; } /** * Returns whether a given type is primitive. */ public static boolean is(Type type) { //noinspection SuspiciousMethodCalls return PRIMITIVE_MAP.containsKey(type); } /** * Returns whether a given type is a box type (e.g. {@link Integer}). */ public static boolean isBox(Type type) { //noinspection SuspiciousMethodCalls return BOX_MAP.containsKey(type); } /** Returns whether this type is a primitive, box or other type. Useful for * switch statements. */ public static Flavor flavor(Type type) { if (is(type)) { return Flavor.PRIMITIVE; } else if (isBox(type)) { return Flavor.BOX; } else { return Flavor.OBJECT; } } /** Returns whether this Primitive is a numeric type. */ public boolean isNumeric() { // Per Java: Boolean and Character do not extend Number switch (this) { case BYTE: case SHORT: case INT: case LONG: case FLOAT: case DOUBLE: return true; default: return false; } } /** Returns whether this Primitive is a fixed-point numeric type. */ public boolean isFixedNumeric() { switch (this) { case BYTE: case SHORT: case INT: case LONG: return true; default: return false; } } /** * Converts a primitive type to a boxed type; returns other types * unchanged. */ public static Type box(Type type) { Primitive primitive = of(type); return primitive == null ? type : primitive.boxClass; } /** * Converts a primitive class to a boxed class; returns other classes * unchanged. */ public static Class box(Class type) { Primitive primitive = of(type); return primitive == null ? type : primitive.boxClass; } /** * Converts a boxed type to a primitive type; returns other types * unchanged. */ public static Type unbox(Type type) { Primitive primitive = ofBox(type); return primitive == null ? type : primitive.primitiveClass; } /** * Converts a boxed class to a primitive class; returns other types * unchanged. */ public static Class unbox(Class type) { Primitive primitive = ofBox(type); return primitive == null ? type : primitive.primitiveClass; } /** * Adapts a primitive array into a {@link List}. For example, * {@code asList(new double[2])} returns a {@code List<Double>}. */ public static List asList(final Object array) { // REVIEW: A per-type list might be more efficient. (Or might not.) return new AbstractList() { public Object get(int index) { return Array.get(array, index); } public int size() { return Array.getLength(array); } }; } /** * Adapts an array of {@code boolean} into a {@link List} of * {@link Boolean}. */ public static List asList(boolean[] elements) { //noinspection unchecked return (List) asList((Object) elements); } /** * Adapts an array of {@code byte} into a {@link List} of * {@link Byte}. */ public static List asList(byte[] elements) { //noinspection unchecked return (List) asList((Object) elements); } /** * Adapts an array of {@code char} into a {@link List} of * {@link Character}. */ public static List asList(char[] elements) { //noinspection unchecked return (List) asList((Object) elements); } /** * Adapts an array of {@code short} into a {@link List} of * {@link Short}. */ public static List asList(short[] elements) { //noinspection unchecked return (List) asList((Object) elements); } /** * Adapts an array of {@code int} into a {@link List} of * {@link Integer}. */ public static List asList(int[] elements) { //noinspection unchecked return (List) asList((Object) elements); } /** * Adapts an array of {@code long} into a {@link List} of * {@link Long}. */ public static List asList(long[] elements) { //noinspection unchecked return (List) asList((Object) elements); } /** * Adapts an array of {@code float} into a {@link List} of * {@link Float}. */ public static List asList(float[] elements) { //noinspection unchecked return (List) asList((Object) elements); } /** * Adapts an array of {@code double} into a {@link List} of * {@link Double}. */ public static List asList(double[] elements) { //noinspection unchecked return (List) asList((Object) elements); } /** * Converts a collection of boxed primitives into an array of primitives. * * @param collection Collection of boxed primitives * * @return array of primitives * @throws ClassCastException if any element is not of the box type * @throws NullPointerException if any element is null */ @SuppressWarnings("unchecked") public Object toArray(Collection collection) { int i = 0; switch (this) { case DOUBLE: double[] doubles = new double[collection.size()]; for (double v : (Collection) collection) { doubles[i++] = v; } return doubles; case FLOAT: float[] floats = new float[collection.size()]; for (float v : (Collection) collection) { floats[i++] = v; } return floats; case INT: int[] ints = new int[collection.size()]; for (int v : (Collection) collection) { ints[i++] = v; } return ints; case LONG: long[] longs = new long[collection.size()]; for (long v : (Collection) collection) { longs[i++] = v; } return longs; case SHORT: short[] shorts = new short[collection.size()]; for (short v : (Collection) collection) { shorts[i++] = v; } return shorts; case BOOLEAN: boolean[] booleans = new boolean[collection.size()]; for (boolean v : (Collection) collection) { booleans[i++] = v; } return booleans; case BYTE: byte[] bytes = new byte[collection.size()]; for (byte v : (Collection) collection) { bytes[i++] = v; } return bytes; case CHAR: char[] chars = new char[collection.size()]; for (char v : (Collection) collection) { chars[i++] = v; } return chars; default: throw new RuntimeException("unexpected: " + this); } } /** * Converts a collection of {@link Number} to a primitive array. */ public Object toArray2(Collection collection) { int i = 0; switch (this) { case DOUBLE: double[] doubles = new double[collection.size()]; for (Number number : collection) { doubles[i++] = number.doubleValue(); } return doubles; case FLOAT: float[] floats = new float[collection.size()]; for (Number number : collection) { floats[i++] = number.floatValue(); } return floats; case INT: int[] ints = new int[collection.size()]; for (Number number : collection) { ints[i++] = number.intValue(); } return ints; case LONG: long[] longs = new long[collection.size()]; for (Number number : collection) { longs[i++] = number.longValue(); } return longs; case SHORT: short[] shorts = new short[collection.size()]; for (Number number : collection) { shorts[i++] = number.shortValue(); } return shorts; case BOOLEAN: boolean[] booleans = new boolean[collection.size()]; for (Number number : collection) { booleans[i++] = number.byteValue() != 0; } return booleans; case BYTE: byte[] bytes = new byte[collection.size()]; for (Number number : collection) { bytes[i++] = number.byteValue(); } return bytes; case CHAR: char[] chars = new char[collection.size()]; for (Number number : collection) { chars[i++] = (char) number.shortValue(); } return chars; default: throw new RuntimeException("unexpected: " + this); } } /** Permutes an array. */ public Object permute(Object array, int[] sources) { int i; switch (this) { case DOUBLE: double[] doubles0 = (double[]) array; double[] doubles = new double[doubles0.length]; for (i = 0; i < doubles.length; i++) { doubles[i] = doubles0[sources[i]]; } return doubles; case FLOAT: float[] floats0 = (float[]) array; float[] floats = new float[floats0.length]; for (i = 0; i < floats.length; i++) { floats[i] = floats0[sources[i]]; } return floats; case INT: int[] ints0 = (int[]) array; int[] ints = new int[ints0.length]; for (i = 0; i < ints.length; i++) { ints[i] = ints0[sources[i]]; } return ints; case LONG: long[] longs0 = (long[]) array; long[] longs = new long[longs0.length]; for (i = 0; i < longs.length; i++) { longs[i] = longs0[sources[i]]; } return longs; case SHORT: short[] shorts0 = (short[]) array; short[] shorts = new short[shorts0.length]; for (i = 0; i < shorts.length; i++) { shorts[i] = shorts0[sources[i]]; } return shorts; case BOOLEAN: boolean[] booleans0 = (boolean[]) array; boolean[] booleans = new boolean[booleans0.length]; for (i = 0; i < booleans.length; i++) { booleans[i] = booleans0[sources[i]]; } return booleans; case BYTE: byte[] bytes0 = (byte[]) array; byte[] bytes = new byte[bytes0.length]; for (i = 0; i < bytes.length; i++) { bytes[i] = bytes0[sources[i]]; } return bytes; case CHAR: char[] chars0 = (char[]) array; char[] chars = new char[chars0.length]; for (i = 0; i < chars.length; i++) { chars[i] = chars0[sources[i]]; } return chars; default: throw new RuntimeException("unexpected: " + this); } } /** * Converts an array to a string. * * @param array Array of this primitive type * * @return String representation of array */ public String arrayToString(Object array) { switch (this) { case BOOLEAN: return Arrays.toString((boolean[]) array); case BYTE: return Arrays.toString((byte[]) array); case CHAR: return Arrays.toString((char[]) array); case DOUBLE: return Arrays.toString((double[]) array); case FLOAT: return Arrays.toString((float[]) array); case INT: return Arrays.toString((int[]) array); case LONG: return Arrays.toString((long[]) array); case SHORT: return Arrays.toString((short[]) array); case OTHER: case VOID: return Arrays.toString((Object[]) array); default: throw new AssertionError("unexpected " + this); } } /** * Sorts an array of this primitive type. * * @param array Array of this primitive type */ public void sortArray(Object array) { switch (this) { case BOOLEAN: // there is no Arrays.sort(boolean[]) final boolean[] booleans = (boolean[]) array; sortBooleanArray(booleans, 0, booleans.length); return; case BYTE: Arrays.sort((byte[]) array); return; case CHAR: Arrays.sort((char[]) array); return; case DOUBLE: Arrays.sort((double[]) array); return; case FLOAT: Arrays.sort((float[]) array); return; case INT: Arrays.sort((int[]) array); return; case LONG: Arrays.sort((long[]) array); return; case SHORT: Arrays.sort((short[]) array); return; case OTHER: case VOID: Arrays.sort((Object[]) array); return; default: throw new AssertionError("unexpected " + this); } } /** * Sorts a specified range of an array of this primitive type. * * @param array Array of this primitive type * @param fromIndex the index of the first element, inclusive, to be sorted * @param toIndex the index of the last element, exclusive, to be sorted */ public void sortArray(Object array, int fromIndex, int toIndex) { switch (this) { case BOOLEAN: // there is no Arrays.sort(boolean[], int, int) sortBooleanArray((boolean[]) array, fromIndex, toIndex); return; case BYTE: Arrays.sort((byte[]) array, fromIndex, toIndex); return; case CHAR: Arrays.sort((char[]) array, fromIndex, toIndex); return; case DOUBLE: Arrays.sort((double[]) array, fromIndex, toIndex); return; case FLOAT: Arrays.sort((float[]) array, fromIndex, toIndex); return; case INT: Arrays.sort((int[]) array, fromIndex, toIndex); return; case LONG: Arrays.sort((long[]) array, fromIndex, toIndex); return; case SHORT: Arrays.sort((short[]) array, fromIndex, toIndex); return; case OTHER: case VOID: Arrays.sort((Object[]) array, fromIndex, toIndex); return; default: throw new AssertionError("unexpected " + this); } } private static void sortBooleanArray(boolean[] booleans, int fromIndex, int toIndex) { // The sorted array will be like [false, false, ..., false, true, ... true]. // Every time we see a "false", the transition point moves up one. int midIndex = fromIndex; for (int i = fromIndex; i < toIndex; i++) { if (!booleans[i]) { ++midIndex; } } Arrays.fill(booleans, fromIndex, midIndex, false); Arrays.fill(booleans, midIndex, toIndex, true); } /** * Sends a field value to a sink. */ public void send(Field field, Object o, Sink sink) throws IllegalAccessException { switch (this) { case BOOLEAN: sink.set(field.getBoolean(o)); break; case BYTE: sink.set(field.getByte(o)); break; case CHAR: sink.set(field.getChar(o)); break; case SHORT: sink.set(field.getShort(o)); break; case INT: sink.set(field.getInt(o)); break; case LONG: sink.set(field.getLong(o)); break; case FLOAT: sink.set(field.getFloat(o)); break; case DOUBLE: sink.set(field.getDouble(o)); break; default: sink.set(field.get(o)); break; } } /** * Gets an item from an array. */ public Object arrayItem(Object dataSet, int ordinal) { // Plain old Array.get doesn't cut it when you have an array of // Integer values but you want to read Short values. Array.getShort // does the right thing. switch (this) { case DOUBLE: return Array.getDouble(dataSet, ordinal); case FLOAT: return Array.getFloat(dataSet, ordinal); case BOOLEAN: return Array.getBoolean(dataSet, ordinal); case BYTE: return Array.getByte(dataSet, ordinal); case CHAR: return Array.getChar(dataSet, ordinal); case SHORT: return Array.getShort(dataSet, ordinal); case INT: return Array.getInt(dataSet, ordinal); case LONG: return Array.getLong(dataSet, ordinal); case OTHER: return Array.get(dataSet, ordinal); default: throw new AssertionError("unexpected " + this); } } /** * Reads value from a source into an array. */ public void arrayItem(Source source, Object dataSet, int ordinal) { switch (this) { case DOUBLE: Array.setDouble(dataSet, ordinal, source.getDouble()); return; case FLOAT: Array.setFloat(dataSet, ordinal, source.getFloat()); return; case BOOLEAN: Array.setBoolean(dataSet, ordinal, source.getBoolean()); return; case BYTE: Array.setByte(dataSet, ordinal, source.getByte()); return; case CHAR: Array.setChar(dataSet, ordinal, source.getChar()); return; case SHORT: Array.setShort(dataSet, ordinal, source.getShort()); return; case INT: Array.setInt(dataSet, ordinal, source.getInt()); return; case LONG: Array.setLong(dataSet, ordinal, source.getLong()); return; case OTHER: Array.set(dataSet, ordinal, source.getObject()); return; default: throw new AssertionError("unexpected " + this); } } /** * Sends to a sink an from an array. */ public void arrayItem(Object dataSet, int ordinal, Sink sink) { switch (this) { case DOUBLE: sink.set(Array.getDouble(dataSet, ordinal)); return; case FLOAT: sink.set(Array.getFloat(dataSet, ordinal)); return; case BOOLEAN: sink.set(Array.getBoolean(dataSet, ordinal)); return; case BYTE: sink.set(Array.getByte(dataSet, ordinal)); return; case CHAR: sink.set(Array.getChar(dataSet, ordinal)); return; case SHORT: sink.set(Array.getShort(dataSet, ordinal)); return; case INT: sink.set(Array.getInt(dataSet, ordinal)); return; case LONG: sink.set(Array.getLong(dataSet, ordinal)); return; case OTHER: sink.set(Array.get(dataSet, ordinal)); return; default: throw new AssertionError("unexpected " + this); } } /** * Gets a value from a given column in a JDBC result set. * * @param resultSet Result set * @param i Ordinal of column (1-based, per JDBC) */ public Object jdbcGet(ResultSet resultSet, int i) throws SQLException { switch (this) { case BOOLEAN: return resultSet.getBoolean(i); case BYTE: return resultSet.getByte(i); case CHAR: return (char) resultSet.getShort(i); case DOUBLE: return resultSet.getDouble(i); case FLOAT: return resultSet.getFloat(i); case INT: return resultSet.getInt(i); case LONG: return resultSet.getLong(i); case SHORT: return resultSet.getShort(i); default: return resultSet.getObject(i); } } /** * Sends to a sink a value from a given column in a JDBC result set. * * @param resultSet Result set * @param i Ordinal of column (1-based, per JDBC) * @param sink Sink */ public void jdbc(ResultSet resultSet, int i, Sink sink) throws SQLException { switch (this) { case BOOLEAN: sink.set(resultSet.getBoolean(i)); break; case BYTE: sink.set(resultSet.getByte(i)); break; case CHAR: sink.set((char) resultSet.getShort(i)); break; case DOUBLE: sink.set(resultSet.getDouble(i)); break; case FLOAT: sink.set(resultSet.getFloat(i)); break; case INT: sink.set(resultSet.getInt(i)); break; case LONG: sink.set(resultSet.getLong(i)); break; case SHORT: sink.set(resultSet.getShort(i)); break; default: sink.set(resultSet.getObject(i)); break; } } /** * Sends a value from a source to a sink. */ public void send(Source source, Sink sink) { switch (this) { case BOOLEAN: sink.set(source.getBoolean()); break; case BYTE: sink.set(source.getByte()); break; case CHAR: sink.set(source.getChar()); break; case DOUBLE: sink.set(source.getDouble()); break; case FLOAT: sink.set(source.getFloat()); break; case INT: sink.set(source.getInt()); break; case LONG: sink.set(source.getLong()); break; case SHORT: sink.set(source.getShort()); break; default: sink.set(source.getObject()); break; } } /** * Calls the appropriate {@link Integer#valueOf(String) valueOf(String)} * method. */ public Object parse(String stringValue) { switch (this) { case BOOLEAN: return Boolean.valueOf(stringValue); case BYTE: return Byte.valueOf(stringValue); case CHAR: return Character.valueOf(stringValue.charAt(0)); case DOUBLE: return Double.valueOf(stringValue); case FLOAT: return Float.valueOf(stringValue); case INT: return Integer.valueOf(stringValue); case LONG: return Long.valueOf(stringValue); case SHORT: return Short.valueOf(stringValue); default: throw new AssertionError(stringValue); } } public boolean assignableFrom(Primitive primitive) { return family == primitive.family && ordinal() >= primitive.ordinal() && !(this == SHORT && primitive == CHAR) && !(this == CHAR && primitive == BYTE); } /** Creates a number value of this primitive's box type. For example, * {@code SHORT.number(Integer(0))} will return {@code Short(0)}. */ public Number number(Number value) { switch (this) { case BYTE: return Byte.valueOf(value.byteValue()); case DOUBLE: return Double.valueOf(value.doubleValue()); case FLOAT: return Float.valueOf(value.floatValue()); case INT: return Integer.valueOf(value.intValue()); case LONG: return Long.valueOf(value.longValue()); case SHORT: return Short.valueOf(value.shortValue()); default: throw new AssertionError(this + ": " + value); } } /** * A place to send a value. */ public interface Sink { void set(boolean v); void set(byte v); void set(char v); void set(short v); void set(int v); void set(long v); void set(float v); void set(double v); void set(Object v); } /** * A place from which to read a value. */ public interface Source { boolean getBoolean(); byte getByte(); char getChar(); short getShort(); int getInt(); long getLong(); float getFloat(); double getDouble(); Object getObject(); } /** What kind of type? */ public enum Flavor { /** A primitive type, e.g. {@code int}. */ PRIMITIVE, /** A type that boxes a primitive, e.g. {@link Integer}. */ BOX, /** Neither a primitive nor a boxing type. */ OBJECT } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy