    001/*-
    002 * Copyright (c) 2019 Diamond Light Source Ltd.
    003 *
    004 * All rights reserved. This program and the accompanying materials
    005 * are made available under the terms of the Eclipse Public License v1.0
    006 * which accompanies this distribution, and is available at
    007 * http://www.eclipse.org/legal/epl-v10.html
    008 */
    009
    010package org.eclipse.january.dataset;
    011
    012import java.lang.reflect.Array;
    013import java.util.Date;
    014import java.util.HashMap;
    015import java.util.LinkedHashMap;
    016import java.util.List;
    017import java.util.Map;
    018import java.util.Map.Entry;
    019import java.util.Set;
    020
    021import org.apache.commons.math3.complex.Complex;
    022
    023/**
    024 * @since 2.3
    025 */
    026public class InterfaceUtils {
    027        private static final Map<Class<?>, Class<? extends Dataset>> class2Interface;
    028
    029        private static final Map<Class<? extends Dataset>, Class<?>> interface2Class;
    030
    031        private static final Map<Class<?>, Integer> elementBytes;
    032
    033        private static final Map<Class<?>, Class<?>> bestFloatElement;
    034
    035        private static final Map<Class<? extends Dataset>, Class<? extends CompoundDataset>> interface2Compound;
    036
    037        private static final Map<Class<? extends CompoundDataset>, Class<? extends Dataset>> compound2Interface;
    038
    039        private static Set<Class<? extends Dataset>> interfaces;
    040
    041        static {
    042                class2Interface = createClassInterfaceMap();
    043
    044                interface2Class = createInterfaceClassMap();
    045                interfaces = interface2Class.keySet();
    046
    047                elementBytes = createElementBytesMap();
    048
    049                bestFloatElement = createBestFloatElementMap();
    050
    051                interface2Compound = createInterfaceCompoundMap();
    052                compound2Interface = new HashMap<Class<? extends CompoundDataset>, Class<? extends Dataset>>();
    053                for (Entry<Class<? extends Dataset>, Class<? extends CompoundDataset>> e : interface2Compound.entrySet()) {
    054                        compound2Interface.put(e.getValue(), e.getKey());
    055                }
    056                compound2Interface.put(RGBByteDataset.class, ByteDataset.class);
    057                compound2Interface.put(RGBDataset.class, ShortDataset.class);
    058                compound2Interface.put(ComplexFloatDataset.class, FloatDataset.class);
    059                compound2Interface.put(ComplexDoubleDataset.class, DoubleDataset.class);
    060        }
    061
    062        private static Map<Class<?>, Class<? extends Dataset>> createClassInterfaceMap() {
    063                Map<Class<?>, Class<? extends Dataset>> result = new HashMap<>();
    064                result.put(Boolean.class, BooleanDataset.class);
    065                result.put(Byte.class, ByteDataset.class);
    066                result.put(Short.class, ShortDataset.class);
    067                result.put(Integer.class, IntegerDataset.class);
    068                result.put(Long.class, LongDataset.class);
    069                result.put(Float.class, FloatDataset.class);
    070                result.put(Double.class, DoubleDataset.class);
    071                result.put(boolean.class, BooleanDataset.class);
    072                result.put(byte.class, ByteDataset.class);
    073                result.put(short.class, ShortDataset.class);
    074                result.put(int.class, IntegerDataset.class);
    075                result.put(long.class, LongDataset.class);
    076                result.put(float.class, FloatDataset.class);
    077                result.put(double.class, DoubleDataset.class);
    078                result.put(Complex.class, ComplexDoubleDataset.class);
    079                result.put(String.class, StringDataset.class);
    080                result.put(Date.class, DateDataset.class);
    081                return result;
    082        }
    083
    084        private static Map<Class<? extends Dataset>, Class<?>> createInterfaceClassMap() {
    085                Map<Class<? extends Dataset>, Class<?>> result = new LinkedHashMap<>();
    086                // ordering is likelihood of occurrence as it is used in an iterative check
    087                // XXX for current implementation
    088                result.put(DoubleDataset.class, Double.class);
    089                result.put(DateDataset.class, Date.class); // XXX must be before string (and integer for unit test)
    090                result.put(IntegerDataset.class, Integer.class);
    091                result.put(BooleanDataset.class, Boolean.class);
    092                result.put(StringDataset.class, String.class);
    093                result.put(ComplexDoubleDataset.class, Double.class); // XXX must be before compound double
    094                result.put(RGBByteDataset.class, Byte.class); // XXX must be before compound byte
    095                result.put(RGBDataset.class, Short.class); // XXX must be before compound short
    096                result.put(ByteDataset.class, Byte.class);
    097                result.put(ShortDataset.class, Short.class);
    098                result.put(LongDataset.class, Long.class);
    099                result.put(FloatDataset.class, Float.class);
    100                result.put(ComplexFloatDataset.class, Float.class); // XXX must be before compound float
    101                result.put(CompoundShortDataset.class, Short.class);
    102                result.put(CompoundByteDataset.class, Byte.class);
    103                result.put(CompoundIntegerDataset.class, Integer.class);
    104                result.put(CompoundLongDataset.class, Long.class);
    105                result.put(CompoundFloatDataset.class, Float.class);
    106                result.put(CompoundDoubleDataset.class, Double.class);
    107                result.put(ObjectDataset.class, Object.class);
    108                return result;
    109        }
    110
    111        private static Map<Class<?>, Integer> createElementBytesMap() {
    112                Map<Class<?>, Integer> result = new LinkedHashMap<>();
    113                result.put(Boolean.class, 1);
    114                result.put(Byte.class, Byte.SIZE / 8);
    115                result.put(Short.class, Short.SIZE / 8);
    116                result.put(Integer.class, Integer.SIZE / 8);
    117                result.put(Long.class, Long.SIZE / 8);
    118                result.put(Float.class, Float.SIZE / 8);
    119                result.put(Double.class, Double.SIZE / 8);
    120                result.put(String.class, 1);
    121                result.put(Object.class, 1);
    122                result.put(Date.class, 1);
    123                return result;
    124        }
    125
    126        private static Map<Class<?>, Class<?>> createBestFloatElementMap() {
    127                Map<Class<?>, Class<?>> result = new HashMap<>();
    128                result.put(Boolean.class, Float.class);
    129                result.put(Byte.class, Float.class);
    130                result.put(Short.class, Float.class);
    131                result.put(Integer.class, Double.class);
    132                result.put(Long.class, Double.class);
    133                result.put(Float.class, Float.class);
    134                result.put(Double.class, Double.class);
    135                return result;
    136        }
    137
    138        private static Map<Class<? extends Dataset>, Class<? extends CompoundDataset>> createInterfaceCompoundMap() {
    139                Map<Class<? extends Dataset>, Class<? extends CompoundDataset>> result = new HashMap<>();
    140                result.put(ByteDataset.class, CompoundByteDataset.class);
    141                result.put(ShortDataset.class, CompoundShortDataset.class);
    142                result.put(IntegerDataset.class, CompoundIntegerDataset.class);
    143                result.put(LongDataset.class, CompoundLongDataset.class);
    144                result.put(FloatDataset.class, CompoundFloatDataset.class);
    145                result.put(DoubleDataset.class, CompoundDoubleDataset.class);
    146                return result;
    147        }
    148
    149        /**
    150         * @param object input
    151         * @param dInterface dataset interface
    152         * @return true if object is an instance of dataset interface
    153         */
    154        public static boolean isInstance(Object object, final Class<? extends Dataset> dInterface) {
    155                return dInterface.isInstance(object);
    156        }
    157
    158        /**
    159         * @param clazz dataset class
    160         * @param dInterface dataset interface
    161         * @return true if given class implements interface
    162         */
    163        public static boolean hasInterface(final Class<? extends Dataset> clazz, final Class<? extends Dataset> dInterface) {
    164                return dInterface.isAssignableFrom(clazz);
    165        }
    166
    167        /**
    168         * @param clazz dataset class
    169         * @param dInterfaces dataset interface
    170         * @return true if given class implements any of the interfaces
    171         */
    172        @SuppressWarnings("unchecked")
    173        public static boolean hasInterface(final Class<? extends Dataset> clazz, final Class<? extends Dataset>... dInterfaces) {
    174                for (Class<? extends Dataset> d : dInterfaces) {
    175                        if (d != null && d.isAssignableFrom(clazz)) {
    176                                return true;
    177                        }
    178                }
    179                return false;
    180        }
    181
    182        /**
    183         * @param clazz element class
    184         * @return true if supported as an element class (note, Object is not supported)
    185         */
    186        public static boolean isElementSupported(Class<? extends Object> clazz) {
    187                return class2Interface.containsKey(clazz);
    188        }
    189
    190        /**
    191         * @param clazz dataset class
    192         * @return (boxed) class of constituent element
    193         */
    194        public static Class<?> getElementClass(final Class<? extends Dataset> clazz) {
    195                return interface2Class.get(clazz);
    196        }
    197
    198        /**
    199         * Get dataset interface from an object. The following are supported: Java Number objects, Apache common math Complex
    200         * objects, Java arrays and lists, Dataset objects and ILazyDataset object
    201         *
    202         * @param obj input
    203         * @return dataset interface
    204         */
    205        public static Class <? extends Dataset> getInterface(Object obj) {
    206                Class<? extends Dataset> dc = null;
    207
    208                if (obj == null) {
    209                        return ObjectDataset.class;
    210                }
    211
    212                if (obj instanceof List<?>) {
    213                        List<?> jl = (List<?>) obj;
    214                        int l = jl.size();
    215                        for (int i = 0; i < l; i++) {
    216                                dc = getBestInterface(dc, getInterface(jl.get(i)));
    217                        }
    218                } else if (obj.getClass().isArray()) {
    219                        Class<?> ca = obj.getClass().getComponentType();
    220                        if (isElementSupported(ca)) {
    221                                return class2Interface.get(ca);
    222                        }
    223                        int l = Array.getLength(obj);
    224                        for (int i = 0; i < l; i++) {
    225                                Object lo = Array.get(obj, i);
    226                                dc = getBestInterface(dc, getInterface(lo));
    227                        }
    228                } else if (obj instanceof Dataset) {
    229                        dc = findSubInterface(((Dataset) obj).getClass());
    230                } else if (obj instanceof ILazyDataset) {
    231                        dc = getInterfaceFromClass(((ILazyDataset) obj).getElementsPerItem(), ((ILazyDataset) obj).getElementClass());
    232                } else {
    233                        Class<?> ca = obj.getClass();
    234                        if (isElementSupported(ca)) {
    235                                return class2Interface.get(ca);
    236                        }
    237                }
    238                return dc;
    239        }
    240
    241        /**
    242         * Find sub-interface of Dataset
    243         * @param clazz dataset class
    244         * @return sub-interface or null if given class is Dataset.class
    245         * @since 2.3
    246         */
    247        public static Class<? extends Dataset> findSubInterface(Class<? extends Dataset> clazz) {
    248                if (Dataset.class.equals(clazz)) {
    249                        throw new IllegalArgumentException("Class must be a sub-interface of Dataset");
    250                }
    251                for (Class<? extends Dataset> i : interfaces) {
    252                        if (i.isAssignableFrom(clazz)) {
    253                                return i;
    254                        }
    255                }
    256                // XXX special cases for current implementation
    257                if (BooleanDatasetBase.class.equals(clazz)) {
    258                        return BooleanDataset.class;
    259                }
    260                if (StringDatasetBase.class.equals(clazz)) {
    261                        return StringDataset.class;
    262                }
    263                if (ObjectDatasetBase.class.equals(clazz)) {
    264                        return ObjectDataset.class;
    265                }
    266                throw new IllegalArgumentException("Unknown sub-interface of Dataset");
    267        }
    268
    269        /**
    270         * @param elementsPerItem item size
    271         * @param elementClass element class
    272         * @return dataset interface
    273         */
    274        public static Class<? extends Dataset> getInterfaceFromClass(int elementsPerItem, Class<?> elementClass) {
    275                Class<? extends Dataset> clazz = class2Interface.get(elementClass);
    276                if (clazz == null) {
    277                        throw new IllegalArgumentException("Class of object not supported");
    278                }
    279                if (elementsPerItem > 1 && interface2Compound.containsKey(clazz)) {
    280                        clazz = interface2Compound.get(clazz);
    281                }
    282                return clazz;
    283        }
    284
    285        /**
    286         * @param clazz dataset interface
    287         * @return elemental dataset interface available for given dataset interface
    288         */
    289        public static Class<? extends Dataset> getElementalInterface(final Class<? extends Dataset> clazz) {
    290                Class<? extends Dataset> c = findSubInterface(clazz);
    291                return isElemental(c) ? c : compound2Interface.get(c);
    292        }
    293
    294        /**
    295         * @param clazz dataset interface
    296         * @return compound dataset interface available for given dataset interface
    297         */
    298        @SuppressWarnings("unchecked")
    299        public static Class<? extends CompoundDataset> getCompoundInterface(final Class<? extends Dataset> clazz) {
    300                Class<? extends CompoundDataset> c = null;
    301                Class<? extends Dataset> d = findSubInterface(clazz);
    302                if (isElemental(d)) {
    303                        c = interface2Compound.get(d);
    304                } else {
    305                        c = (Class<? extends CompoundDataset>) d;
    306                }
    307                if (c == null) {
    308                        throw new IllegalArgumentException("Interface cannot be compound");
    309                }
    310                return c;
    311        }
    312
    313        /**
    314         * @param a dataset
    315         * @return true if dataset is not compound or complex
    316         */
    317        public static boolean isElemental(ILazyDataset a) {
    318                return isElemental(getInterface(a));
    319        }
    320
    321        /**
    322         * @param clazz dataset class
    323         * @return true if dataset interface is not compound or complex
    324         */
    325        public static boolean isElemental(Class<? extends Dataset> clazz) {
    326                return !CompoundDataset.class.isAssignableFrom(clazz);
    327        }
    328
    329        /**
    330         * @param clazz dataset class
    331         * @return true if dataset interface is compound (not complex)
    332         */
    333        public static boolean isCompound(Class<? extends Dataset> clazz) {
    334                Class<? extends Dataset> c = findSubInterface(clazz);
    335                return compound2Interface.containsKey(c);
    336        }
    337
    338        /**
    339         * @param a dataset
    340         * @return true if dataset has integer elements
    341         */
    342        public static boolean isInteger(ILazyDataset a) {
    343                return a instanceof Dataset ? isInteger(((Dataset) a).getClass()) : isElementClassInteger(a.getElementClass());
    344        }
    345
    346        /**
    347         * @param a dataset
    348         * @return true if dataset has floating point elements
    349         */
    350        public static boolean isFloating(ILazyDataset a) {
    351                return a instanceof Dataset ? isFloating(((Dataset) a).getClass()) : isElementClassFloating(a.getElementClass());
    352        }
    353
    354        /**
    355         * @param clazz dataset class
    356         * @return true if dataset interface has integer elements
    357         */
    358        public static boolean isInteger(Class<? extends Dataset> clazz) {
    359                Class<?> c = interface2Class.get(clazz);
    360                return isElementClassInteger(c);
    361        }
    362
    363        /**
    364         * @param clazz dataset class
    365         * @return true if dataset interface has floating point elements
    366         */
    367        public static boolean isFloating(Class<? extends Dataset> clazz) {
    368                Class<?> c = interface2Class.get(clazz);
    369                return isElementClassFloating(c);
    370        }
    371
    372        private static boolean isElementClassInteger(Class<?> c) {
    373                return Byte.class == c || Short.class == c || Integer.class == c || Long.class == c;
    374        }
    375
    376        private static boolean isElementClassFloating(Class<?> c) {
    377                return Double.class == c || Float.class == c;
    378        }
    379
    380        /**
    381         * @param clazz dataset class
    382         * @return true if dataset interface has complex items
    383         */
    384        public static boolean isComplex(Class<? extends Dataset> clazz) {
    385                return ComplexDoubleDataset.class.isAssignableFrom(clazz) || ComplexFloatDataset.class.isAssignableFrom(clazz);
    386        }
    387
    388        /**
    389         * @param clazz dataset class
    390         * @return true if dataset interface has numerical elements
    391         */
    392        public static boolean isNumerical(Class<? extends Dataset> clazz) {
    393                Class<?> c = interface2Class.get(clazz);
    394                return Boolean.class == c || isElementClassInteger(c) || isElementClassFloating(c);
    395        }
    396
    397        /**
    398         * @param clazz dataset class
    399         * @return number of elements per item
    400         */
    401        public static int getElementsPerItem(Class<? extends Dataset> clazz) {
    402                if (isComplex(clazz)) {
    403                        return 2;
    404                } else if (RGBByteDataset.class.isAssignableFrom(clazz) || RGBDataset.class.isAssignableFrom(clazz)) {
    405                        return 3;
    406                }
    407                if (CompoundDataset.class.isAssignableFrom(clazz)) {
    408                        throw new UnsupportedOperationException("Multi-element type unsupported");
    409                }
    410                return 1;
    411        }
    412
    413        /**
    414         * Find dataset interface that best fits given classes. The best class takes into account complex and array datasets
    415         *
    416         * @param a
    417         *            first dataset class
    418         * @param b
    419         *            second dataset class
    420         * @return best dataset interface
    421         */
    422        public static Class<? extends Dataset> getBestInterface(Class<? extends Dataset> a, Class<? extends Dataset> b) {
    423                if (a == null) {
    424                        return b;
    425                }
    426                if (b == null) {
    427                        return a;
    428                }
    429
    430                boolean isElemental = true;
    431                final boolean az = isComplex(a);
    432                if (!az && !isElemental(a)) {
    433                        isElemental = false;
    434                        a = compound2Interface.get(a);
    435                }
    436                final boolean bz = isComplex(b);
    437                if (!bz && !isElemental(b)) {
    438                        isElemental = false;
    439                        b = compound2Interface.get(b);
    440                }
    441
    442                if (isFloating(a)) {
    443                        if (!isFloating(b)) {
    444                                b = getBestFloatInterface(b); // note doesn't change if not numerical!!!
    445                        }
    446                        if (az) {
    447                                b = DoubleDataset.class.isAssignableFrom(b) ? ComplexDoubleDataset.class : ComplexFloatDataset.class;
    448                        }
    449                } else if (isFloating(b)) {
    450                        a = getBestFloatInterface(a);
    451                        if (bz) {
    452                                a = DoubleDataset.class.isAssignableFrom(a) ? ComplexDoubleDataset.class : ComplexFloatDataset.class;
    453                        }
    454                }
    455
    456                Class<? extends Dataset> c = isBetter(interface2Class.get(a), interface2Class.get(b)) ? a : b;
    457                if ((az || bz) && !isComplex(c)) {
    458                        c = DoubleDataset.class.isAssignableFrom(c) ? ComplexDoubleDataset.class : ComplexFloatDataset.class;
    459                }
    460
    461                if (!isElemental && interface2Compound.containsKey(c)) {
    462                        c = interface2Compound.get(c);
    463                }
    464                return c;
    465        }
    466
    467        private static boolean isBetter(Class<?> a, Class<?> b) {
    468                for (Class<?> k : elementBytes.keySet()) { // elements order in increasing width (for numerical primitives)
    469                        if (k.equals(b)) {
    470                                return true;
    471                        }
    472                        if (k.equals(a)) {
    473                                return false;
    474                        }
    475                }
    476                return true;
    477        }
    478
    479        /**
    480         * The largest dataset type suitable for a summation of around a few thousand items without changing from the "kind"
    481         * of dataset
    482         *
    483         * @param a dataset
    484         * @return largest dataset type available for given dataset type
    485         */
    486        public static Class<? extends Dataset> getLargestInterface(Dataset a) {
    487                if (a instanceof BooleanDataset || a instanceof ByteDataset || a instanceof ShortDataset) {
    488                        return IntegerDataset.class;
    489                } else if (a instanceof IntegerDataset) {
    490                        return LongDataset.class;
    491                } else if (a instanceof FloatDataset) {
    492                        return DoubleDataset.class;
    493                } else if (a instanceof ComplexFloatDataset) {
    494                        return ComplexDoubleDataset.class;
    495                } else if (a instanceof CompoundByteDataset || a instanceof CompoundShortDataset) {
    496                        return CompoundIntegerDataset.class;
    497                } else if (a instanceof CompoundIntegerDataset) {
    498                        return CompoundLongDataset.class;
    499                } else if (a instanceof CompoundFloatDataset) {
    500                        return CompoundDoubleDataset.class;
    501                }
    502                return a.getClass();
    503        }
    504
    505        /**
    506         * Find floating point dataset interface that best fits given types. The best type takes into account complex and array
    507         * datasets
    508         *
    509         * @param clazz dataset class
    510         * @return best dataset interface
    511         */
    512        public static Class<? extends Dataset> getBestFloatInterface(Class<? extends Dataset> clazz) {
    513                Class<?> e = interface2Class.get(clazz);
    514                if (bestFloatElement.containsKey(e)) {
    515                        e = bestFloatElement.get(e);
    516                        return class2Interface.get(e);
    517                }
    518                return clazz;
    519        }
    520
    521        /**
    522         * @param isize
    523         *            number of elements in an item
    524         * @param clazz dataset interface
    525         * @return length of single item in bytes
    526         */
    527        public static int getItemBytes(final int isize, Class<? extends Dataset> clazz) {
    528                int bytes = elementBytes.get(interface2Class.get(clazz));
    529
    530                return isize * bytes;
    531        }
    532
    533        /**
    534         * Convert double array to primitive array
    535         * @param clazz dataset interface
    536         * @param x values
    537         * @return biggest native primitive array if integer. Return null if not interface is not numerical
    538         */
    539        public static Object fromDoublesToBiggestPrimitives(Class<? extends Dataset> clazz, double[] x) {
    540                if (BooleanDataset.class.isAssignableFrom(clazz) || ByteDataset.class.isAssignableFrom(clazz)
    541                                || ShortDataset.class.isAssignableFrom(clazz) || IntegerDataset.class.isAssignableFrom(clazz)) {
    542                        int[] i32 = new int[x.length];
    543                        for (int i = 0; i < x.length; i++) {
    544                                i32[i] = (int) (long) x[i];
    545                        }
    546                        return i32;
    547                } else if (LongDataset.class.isAssignableFrom(clazz)) {
    548                        long[] i64 = new long[x.length];
    549                        for (int i = 0; i < x.length; i++) {
    550                                i64[i] = (long) x[i];
    551                        }
    552                        return i64;
    553                } else if (FloatDataset.class.isAssignableFrom(clazz)) {
    554                        float[] f32 = new float[x.length];
    555                        for (int i = 0; i < x.length; i++) {
    556                                f32[i] = (float) x[i];
    557                        }
    558                        return f32;
    559                } else if (DoubleDataset.class.isAssignableFrom(clazz)) {
    560                        return x;
    561                }
    562                return null;
    563        }
    564
    565        /**
    566         * Convert double to number
    567         * @param clazz dataset interface
    568         * @param x value
    569         * @return number if integer. Return null if not interface is not numerical
    570         * @since 2.3
    571         */
    572        public static Number fromDoubleToNumber(Class<? extends Dataset> clazz, double x) {
    573                if (BooleanDataset.class.isAssignableFrom(clazz) || ByteDataset.class.isAssignableFrom(clazz)) {
    574                        return Byte.valueOf((byte) (long) x);
    575                } else if (ShortDataset.class.isAssignableFrom(clazz)) {
    576                        return Short.valueOf((short) (long) x);
    577                } else if (IntegerDataset.class.isAssignableFrom(clazz)) {
    578                        return Integer.valueOf((int) (long) x);
    579                } else if (LongDataset.class.isAssignableFrom(clazz)) {
    580                        return Long.valueOf((long) x);
    581                } else if (FloatDataset.class.isAssignableFrom(clazz)) {
    582                        return Float.valueOf((float) x);
    583                } else if (DoubleDataset.class.isAssignableFrom(clazz)) {
    584                        return Double.valueOf(x);
    585                }
    586                return null;
    587        }
    588
    589        /**
    590         * Convert double to number
    591         * @param clazz dataset interface
    592         * @param x value
    593         * @return biggest number if integer. Return null if not interface is not numerical
    594         */
    595        public static Number fromDoubleToBiggestNumber(Class<? extends Dataset> clazz, double x) {
    596                if (BooleanDataset.class.isAssignableFrom(clazz) || ByteDataset.class.isAssignableFrom(clazz)
    597                                || ShortDataset.class.isAssignableFrom(clazz) || IntegerDataset.class.isAssignableFrom(clazz)) {
    598                        return Integer.valueOf((int) (long) x);
    599                } else if (LongDataset.class.isAssignableFrom(clazz)) {
    600                        return Long.valueOf((long) x);
    601                } else if (FloatDataset.class.isAssignableFrom(clazz)) {
    602                        return Float.valueOf((float) x);
    603                } else if (DoubleDataset.class.isAssignableFrom(clazz)) {
    604                        return Double.valueOf(x);
    605                }
    606                return null;
    607        }
    608
    609        /**
    610         * @param clazz dataset interface
    611         * @param x value
    612         * @return biggest native primitive if integer
    613         * @since 2.3
    614         */
    615        public static Number toBiggestNumber(Class<? extends Dataset> clazz, Number x) {
    616                if (BooleanDataset.class.isAssignableFrom(clazz) || ByteDataset.class.isAssignableFrom(clazz)
    617                                || ShortDataset.class.isAssignableFrom(clazz) || IntegerDataset.class.isAssignableFrom(clazz)) {
    618                        return x instanceof Integer ? x : Integer.valueOf(x.intValue());
    619                } else if (LongDataset.class.isAssignableFrom(clazz)) {
    620                        return x instanceof Long ? x : Long.valueOf(x.longValue());
    621                } else if (FloatDataset.class.isAssignableFrom(clazz)) {
    622                        return x instanceof Float ? x : Float.valueOf(x.floatValue());
    623                } else if (DoubleDataset.class.isAssignableFrom(clazz)) {
    624                        return x instanceof Double ? x : Double.valueOf(x.doubleValue());
    625                }
    626                return null;
    627        }
    628}