org.apache.tajo.util.NumberUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.tajo.util.NumberUtil.java

Source

/**
 * 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.tajo.util;

import io.netty.buffer.ByteBuf;
import io.netty.util.internal.PlatformDependent;

import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.nio.charset.Charset;

// this is an implementation copied from LazyPrimitives in hive
public class NumberUtil {

    public static final double[] powersOf10 = { /* Table giving binary powers of 10.  Entry */
            10., /* is 10^2^i.  Used to convert decimal */
            100., /* exponents into floating-point numbers. */
            1.0e4, 1.0e8, 1.0e16, 1.0e32, 1.0e64, 1.0e128, 1.0e256 };
    private static final int maxExponent = 511; /* Largest possible base 10 exponent.  Any
                                                * exponent larger than this will already
                                                * produce underflow or overflow, so there's
                                                * no need to worry about additional digits.
                                                */

    public static long unsigned32(int n) {
        return n & 0xFFFFFFFFL;
    }

    public static int unsigned16(short n) {
        return n & 0xFFFF;
    }

    public static byte[] toAsciiBytes(Number i) {
        return BytesUtils.toASCIIBytes(String.valueOf(i).toCharArray());
    }

    public static byte[] toAsciiBytes(short i) {
        return BytesUtils.toASCIIBytes(String.valueOf(i).toCharArray());
    }

    public static byte[] toAsciiBytes(int i) {
        return BytesUtils.toASCIIBytes(String.valueOf(i).toCharArray());
    }

    public static byte[] toAsciiBytes(long i) {
        return BytesUtils.toASCIIBytes(String.valueOf(i).toCharArray());
    }

    public static byte[] toAsciiBytes(float i) {
        return BytesUtils.toASCIIBytes(String.valueOf(i).toCharArray());
    }

    public static byte[] toAsciiBytes(double i) {
        return BytesUtils.toASCIIBytes(String.valueOf(i).toCharArray());
    }

    /**
     * Returns the digit represented by character b.
     *
     * @param b     The ascii code of the character
     * @param radix The radix
     * @return -1 if it's invalid
     */
    static int digit(int b, int radix) {
        int r = -1;
        if (b >= '0' && b <= '9') {
            r = b - '0';
        } else if (b >= 'A' && b <= 'Z') {
            r = b - 'A' + 10;
        } else if (b >= 'a' && b <= 'z') {
            r = b - 'a' + 10;
        }
        if (r >= radix) {
            r = -1;
        }
        return r;
    }

    /**
     * Returns the digit represented by character b, radix is 10
     *
     * @param b The ascii code of the character
     * @return -1 if it's invalid
     */
    private static boolean isDigit(int b) {
        return (b >= '0' && b <= '9');
    }

    /**
     * Parses the byte array argument as if it was a double value and returns the
     * result. Throws NumberFormatException if the byte array does not represent a
     * double value.
     *
     * @return double, the value represented by the argument
     * @throws NumberFormatException if the argument could not be parsed as a double
     */
    public static double parseDouble(byte[] bytes, int start, int length) {
        if (bytes == null) {
            throw new NumberFormatException("String is null");
        }
        if (length == 0) {
            throw new NumberFormatException("Empty byte array!");
        }

        /*
         * Strip off leading blanks
         */
        int offset = start;
        int end = start + length;

        while (offset < end && bytes[offset] == ' ') {
            offset++;
        }
        if (offset == end) {
            throw new NumberFormatException("blank byte array!");
        }

        /*
         * check for a sign.
         */
        boolean sign = false;
        if (bytes[offset] == '-') {
            sign = true;
            offset++;
        } else if (bytes[offset] == '+') {
            offset++;
        }
        if (offset == end) {
            throw new NumberFormatException("the byte array only has a sign!");
        }

        /*
         * Count the number of digits in the mantissa (including the decimal
         * point), and also locate the decimal point.
         */
        int mantSize = 0; /* Number of digits in mantissa. */
        int decicalOffset = -1; /* Number of mantissa digits BEFORE decimal point. */
        for (; offset < end; offset++) {
            if (!isDigit(bytes[offset])) {
                if ((bytes[offset] != '.') || (decicalOffset >= 0)) {
                    break;
                }
                decicalOffset = mantSize;
            }
            mantSize++;
        }

        int exponentOffset = offset; /* Temporarily holds location of exponent in bytes. */

        /*
         * Now suck up the digits in the mantissa.  Use two integers to
         * collect 9 digits each (this is faster than using floating-point).
         * If the mantissa has more than 18 digits, ignore the extras, since
         * they can't affect the value anyway.
         */
        offset -= mantSize;
        if (decicalOffset < 0) {
            decicalOffset = mantSize;
        } else {
            mantSize -= 1; /* One of the digits was the decimal point. */
        }
        int fracExponent; /* Exponent that derives from the fractional
                           * part.  Under normal circumstatnces, it is
                               * the negative of the number of digits in F.
                               * However, if I is very long, the last digits
                               * of I get dropped (otherwise a long I with a
                               * large negative exponent could cause an
                               * unnecessary overflow on I alone).  In this
                               * case, fracExp is incremented one for each
                               * dropped digit. */
        if (mantSize > 18) {
            fracExponent = decicalOffset - 18;
            mantSize = 18;
        } else {
            fracExponent = decicalOffset - mantSize;
        }

        if (mantSize == 0) {
            return 0.0;
        }

        int frac1 = 0;
        for (; mantSize > 9; mantSize--) {
            int b = bytes[offset];
            offset++;
            if (b == '.') {
                b = bytes[offset];
                offset++;
            }
            frac1 = 10 * frac1 + (b - '0');
        }
        int frac2 = 0;
        for (; mantSize > 0; mantSize--) {
            int b = bytes[offset];
            offset++;
            if (b == '.') {
                b = bytes[offset];
                offset++;
            }
            frac2 = 10 * frac2 + (b - '0');
        }
        double fraction = (1.0e9 * frac1) + frac2;

        /*
         * Skim off the exponent.
         */
        int exponent = 0; /* Exponent read from "EX" field. */
        offset = exponentOffset;
        boolean expSign = false;

        if (offset < end) {
            if ((bytes[offset] != 'E') && (bytes[offset] != 'e')) {
                throw new NumberFormatException(new String(bytes, start, length));
            }

            // (bytes[offset] == 'E') || (bytes[offset] == 'e')
            offset++;

            if (bytes[offset] == '-') {
                expSign = true;
                offset++;
            } else if (bytes[offset] == '+') {
                offset++;
            }

            for (; offset < end; offset++) {
                if (isDigit(bytes[offset])) {
                    exponent = exponent * 10 + (bytes[offset] - '0');
                } else {
                    throw new NumberFormatException(new String(bytes, start, length));
                }
            }
        }

        exponent = expSign ? (fracExponent - exponent) : (fracExponent + exponent);

        /*
         * Generate a floating-point number that represents the exponent.
         * Do this by processing the exponent one bit at a time to combine
         * many powers of 2 of 10. Then combine the exponent with the
         * fraction.
         */
        if (exponent < 0) {
            expSign = true;
            exponent = -exponent;
        } else {
            expSign = false;
        }
        if (exponent > maxExponent) {
            throw new NumberFormatException(new String(bytes, start, length));
        }

        double dblExp = 1.0;
        for (int i = 0; exponent != 0; exponent >>= 1, i++) {
            if ((exponent & 01) == 01) {
                dblExp *= powersOf10[i];
            }
        }

        fraction = (expSign) ? (fraction / dblExp) : (fraction * dblExp);

        return sign ? (-fraction) : fraction;
    }

    /**
     * Parses the byte array argument as if it was an int value and returns the
     * result. Throws NumberFormatException if the byte array does not represent an
     * int quantity.
     *
     * @return int the value represented by the argument
     * @throws NumberFormatException if the argument could not be parsed as an int quantity.
     */
    public static int parseInt(byte[] bytes, int start, int length) {
        return parseInt(bytes, start, length, 10);
    }

    /**
     * Parses the byte array argument as if it was an int value and returns the
     * result. Throws NumberFormatException if the byte array does not represent an
     * int quantity. The second argument specifies the radix to use when parsing
     * the value.
     *
     * @param radix the base to use for conversion.
     * @return the value represented by the argument
     * @throws NumberFormatException if the argument could not be parsed as an int quantity.
     */
    public static int parseInt(byte[] bytes, int start, int length, int radix) {
        if (bytes == null) {
            throw new NumberFormatException("String is null");
        }
        if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) {
            throw new NumberFormatException("Invalid radix: " + radix);
        }
        if (length == 0) {
            throw new NumberFormatException("Empty byte array!");
        }
        int offset = start;
        boolean negative = bytes[start] == '-';
        if (negative || bytes[start] == '+') {
            offset++;
            if (length == 1) {
                throw new NumberFormatException(new String(bytes, start, length));
            }
        }

        return parseIntInternal(bytes, start, length, offset, radix, negative);
    }

    /**
     * @param bytes
     * @param start
     * @param length
     * @param radix    the base to use for conversion.
     * @param offset   the starting position after the sign (if exists)
     * @param radix    the base to use for conversion.
     * @param negative whether the number is negative.
     * @return the value represented by the argument
     * @throws NumberFormatException if the argument could not be parsed as an int quantity.
     */
    private static int parseIntInternal(byte[] bytes, int start, int length, int offset, int radix,
            boolean negative) {
        byte separator = '.';
        int max = Integer.MIN_VALUE / radix;
        int result = 0, end = start + length;
        while (offset < end) {
            int digit = digit(bytes[offset++], radix);
            if (digit == -1) {
                if (bytes[offset - 1] == separator) {
                    // We allow decimals and will return a truncated integer in that case.
                    // Therefore we won't throw an exception here (checking the fractional
                    // part happens below.)
                    break;
                }
                throw new NumberFormatException(new String(bytes, start, length));
            }
            if (max > result) {
                throw new NumberFormatException(new String(bytes, start, length));
            }
            int next = result * radix - digit;
            if (next > result) {
                throw new NumberFormatException(new String(bytes, start, length));
            }
            result = next;
        }

        // This is the case when we've encountered a decimal separator. The fractional
        // part will not change the number, but we will verify that the fractional part
        // is well formed.
        while (offset < end) {
            int digit = digit(bytes[offset++], radix);
            if (digit == -1) {
                throw new NumberFormatException(new String(bytes, start, length));
            }
        }

        if (!negative) {
            result = -result;
            if (result < 0) {
                throw new NumberFormatException(new String(bytes, start, length));
            }
        }
        return result;
    }

    /**
     * Parses the string argument as if it was a long value and returns the
     * result. Throws NumberFormatException if the string does not represent a
     * long quantity.
     *
     * @param bytes
     * @param start
     * @param length a UTF-8 encoded string representation of a long quantity.
     * @return long the value represented by the argument
     * @throws NumberFormatException if the argument could not be parsed as a long quantity.
     */
    public static long parseLong(byte[] bytes, int start, int length) {
        return parseLong(bytes, start, length, 10);
    }

    /**
     * Parses the string argument as if it was an long value and returns the
     * result. Throws NumberFormatException if the string does not represent an
     * long quantity. The second argument specifies the radix to use when parsing
     * the value.
     *
     * @param bytes
     * @param start
     * @param length a UTF-8 encoded string representation of a long quantity.
     * @param radix  the base to use for conversion.
     * @return the value represented by the argument
     * @throws NumberFormatException if the argument could not be parsed as an long quantity.
     */
    public static long parseLong(byte[] bytes, int start, int length, int radix) {
        if (bytes == null) {
            throw new NumberFormatException("String is null");
        }
        if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) {
            throw new NumberFormatException("Invalid radix: " + radix);
        }
        if (length == 0) {
            throw new NumberFormatException("Empty string!");
        }
        int offset = start;
        boolean negative = bytes[start] == '-';
        if (negative || bytes[start] == '+') {
            offset++;
            if (length == 1) {
                throw new NumberFormatException(new String(bytes, start, length));
            }
        }

        return parseLongInternal(bytes, start, length, offset, radix, negative);
    }

    /**
     * /** Parses the string argument as if it was an long value and returns the
     * result. Throws NumberFormatException if the string does not represent an
     * long quantity. The second argument specifies the radix to use when parsing
     * the value.
     *
     * @param bytes
     * @param start
     * @param length   a UTF-8 encoded string representation of a long quantity.
     * @param offset   the starting position after the sign (if exists)
     * @param radix    the base to use for conversion.
     * @param negative whether the number is negative.
     * @return the value represented by the argument
     * @throws NumberFormatException if the argument could not be parsed as an long quantity.
     */
    private static long parseLongInternal(byte[] bytes, int start, int length, int offset, int radix,
            boolean negative) {
        byte separator = '.';
        long max = Long.MIN_VALUE / radix;
        long result = 0, end = start + length;
        while (offset < end) {
            int digit = digit(bytes[offset++], radix);
            if (digit == -1 || max > result) {
                if (bytes[offset - 1] == separator) {
                    // We allow decimals and will return a truncated integer in that case.
                    // Therefore we won't throw an exception here (checking the fractional
                    // part happens below.)
                    break;
                }
                throw new NumberFormatException(new String(bytes, start, length));
            }
            long next = result * radix - digit;
            if (next > result) {
                throw new NumberFormatException(new String(bytes, start, length));
            }
            result = next;
        }

        // This is the case when we've encountered a decimal separator. The fractional
        // part will not change the number, but we will verify that the fractional part
        // is well formed.
        while (offset < end) {
            int digit = digit(bytes[offset++], radix);
            if (digit == -1) {
                throw new NumberFormatException(new String(bytes, start, length));
            }
        }

        if (!negative) {
            result = -result;
            if (result < 0) {
                throw new NumberFormatException(new String(bytes, start, length));
            }
        }
        return result;
    }

    /**
     * Writes out the text representation of an integer using base 10 to an
     * OutputStream in UTF-8 encoding.
     * <p/>
     * Note: division by a constant (like 10) is much faster than division by a
     * variable. That's one of the reasons that we don't make radix a parameter
     * here.
     *
     * @param out the outputstream to write to
     * @param i   an int to write out
     * @throws IOException
     */
    public static void writeUTF8(OutputStream out, int i) throws IOException {
        if (i == 0) {
            out.write('0');
            return;
        }

        boolean negative = i < 0;
        if (negative) {
            out.write('-');
        } else {
            // negative range is bigger than positive range, so there is no risk
            // of overflow here.
            i = -i;
        }

        int start = 1000000000;
        while (i / start == 0) {
            start /= 10;
        }

        while (start > 0) {
            out.write('0' - (i / start % 10));
            start /= 10;
        }
    }

    /**
     * Writes out the text representation of an integer using base 10 to an
     * OutputStream in UTF-8 encoding.
     * <p/>
     * Note: division by a constant (like 10) is much faster than division by a
     * variable. That's one of the reasons that we don't make radix a parameter
     * here.
     *
     * @param out the outputstream to write to
     * @param i   an int to write out
     * @throws java.io.IOException
     */
    public static void writeUTF8(OutputStream out, long i) throws IOException {
        if (i == 0) {
            out.write('0');
            return;
        }

        boolean negative = i < 0;
        if (negative) {
            out.write('-');
        } else {
            // negative range is bigger than positive range, so there is no risk
            // of overflow here.
            i = -i;
        }

        long start = 1000000000000000000L;
        while (i / start == 0) {
            start /= 10;
        }

        while (start > 0) {
            out.write('0' - (int) ((i / start) % 10));
            start /= 10;
        }
    }

    /**
     * Parses the byte array argument as if it was a double value and returns the
     * result. Throws NumberFormatException if the byte buffer does not represent a
     * double value.
     *
     * @return double, the value represented by the argument
     * @throws NumberFormatException if the argument could not be parsed as a double
     */
    public static double parseDouble(ByteBuf bytes) {
        return parseDouble(bytes, bytes.readerIndex(), bytes.readableBytes());
    }

    /**
     * Parses the byte array argument as if it was a double value and returns the
     * result. Throws NumberFormatException if the byte buffer does not represent a
     * double value.
     *
     * @return double, the value represented by the argument
     * @throws NumberFormatException if the argument could not be parsed as a double
     */
    public static double parseDouble(ByteBuf bytes, int start, int length) {
        if (!PlatformDependent.hasUnsafe()) {
            return parseDouble(bytes.array(), start, length);
        }

        if (bytes == null) {
            throw new NumberFormatException("String is null");
        }

        if (length == 0 || bytes.writerIndex() < start + length) {
            throw new NumberFormatException("Empty string or Invalid buffer!");
        }

        long memoryAddress = bytes.memoryAddress();
        /*
         * Strip off leading blanks
         */
        int offset = start;
        int end = start + length;

        while (offset < end && PlatformDependent.getByte(memoryAddress + offset) == ' ') {
            offset++;
        }
        if (offset == end) {
            throw new NumberFormatException("blank byte array!");
        }

        /*
         * check for a sign.
         */
        boolean sign = false;
        if (PlatformDependent.getByte(memoryAddress + offset) == '-') {
            sign = true;
            offset++;
        } else if (PlatformDependent.getByte(memoryAddress + offset) == '+') {
            offset++;
        }
        if (offset == end) {
            throw new NumberFormatException("the byte array only has a sign!");
        }

        /*
         * Count the number of digits in the mantissa (including the decimal
         * point), and also locate the decimal point.
         */
        int mantSize = 0; /* Number of digits in mantissa. */
        int decicalOffset = -1; /* Number of mantissa digits BEFORE decimal point. */
        for (; offset < end; offset++) {
            if (!isDigit(PlatformDependent.getByte(memoryAddress + offset))) {
                if ((PlatformDependent.getByte(memoryAddress + offset) != '.') || (decicalOffset >= 0)) {
                    break;
                }
                decicalOffset = mantSize;
            }
            mantSize++;
        }

        int exponentOffset = offset; /* Temporarily holds location of exponent in bytes. */

        /*
         * Now suck up the digits in the mantissa.  Use two integers to
         * collect 9 digits each (this is faster than using floating-point).
         * If the mantissa has more than 18 digits, ignore the extras, since
         * they can't affect the value anyway.
         */
        offset -= mantSize;
        if (decicalOffset < 0) {
            decicalOffset = mantSize;
        } else {
            mantSize -= 1; /* One of the digits was the decimal point. */
        }
        int fracExponent; /* Exponent that derives from the fractional
                           * part.  Under normal circumstatnces, it is
                               * the negative of the number of digits in F.
                               * However, if I is very long, the last digits
                               * of I get dropped (otherwise a long I with a
                               * large negative exponent could cause an
                               * unnecessary overflow on I alone).  In this
                               * case, fracExp is incremented one for each
                               * dropped digit. */
        if (mantSize > 18) {
            fracExponent = decicalOffset - 18;
            mantSize = 18;
        } else {
            fracExponent = decicalOffset - mantSize;
        }

        if (mantSize == 0) {
            return 0.0;
        }

        int frac1 = 0;
        for (; mantSize > 9; mantSize--) {
            int b = PlatformDependent.getByte(memoryAddress + offset);
            offset++;
            if (b == '.') {
                b = PlatformDependent.getByte(memoryAddress + offset);
                offset++;
            }
            frac1 = 10 * frac1 + (b - '0');
        }
        int frac2 = 0;
        for (; mantSize > 0; mantSize--) {
            int b = PlatformDependent.getByte(memoryAddress + offset);
            offset++;
            if (b == '.') {
                b = PlatformDependent.getByte(memoryAddress + offset);
                offset++;
            }
            frac2 = 10 * frac2 + (b - '0');
        }
        double fraction = (1.0e9 * frac1) + frac2;

        /*
         * Skim off the exponent.
         */
        int exponent = 0; /* Exponent read from "EX" field. */
        offset = exponentOffset;
        boolean expSign = false;

        if (offset < end) {
            if ((PlatformDependent.getByte(memoryAddress + offset) != 'E')
                    && (PlatformDependent.getByte(memoryAddress + offset) != 'e')) {
                throw new NumberFormatException(bytes.toString(start, length, Charset.defaultCharset()));
            }

            // (bytes[offset] == 'E') || (bytes[offset] == 'e')
            offset++;

            if (PlatformDependent.getByte(memoryAddress + offset) == '-') {
                expSign = true;
                offset++;
            } else if (PlatformDependent.getByte(memoryAddress + offset) == '+') {
                offset++;
            }

            for (; offset < end; offset++) {
                if (isDigit(PlatformDependent.getByte(memoryAddress + offset))) {
                    exponent = exponent * 10 + (PlatformDependent.getByte(memoryAddress + offset) - '0');
                } else {
                    throw new NumberFormatException(bytes.toString(start, length, Charset.defaultCharset()));
                }
            }
        }

        exponent = expSign ? (fracExponent - exponent) : (fracExponent + exponent);

        /*
         * Generate a floating-point number that represents the exponent.
         * Do this by processing the exponent one bit at a time to combine
         * many powers of 2 of 10. Then combine the exponent with the
         * fraction.
         */
        if (exponent < 0) {
            expSign = true;
            exponent = -exponent;
        } else {
            expSign = false;
        }
        if (exponent > maxExponent) {
            throw new NumberFormatException(bytes.toString(start, length, Charset.defaultCharset()));
        }

        double dblExp = 1.0;
        for (int i = 0; exponent != 0; exponent >>= 1, i++) {
            if ((exponent & 01) == 01) {
                dblExp *= powersOf10[i];
            }
        }

        fraction = (expSign) ? (fraction / dblExp) : (fraction * dblExp);

        return sign ? (-fraction) : fraction;
    }

    /**
     * Parses the byte buffer argument as if it was an int value and returns the
     * result. Throws NumberFormatException if the byte array does not represent an
     * int quantity.
     *
     * @return int the value represented by the argument
     * @throws NumberFormatException if the argument could not be parsed as an int quantity.
     */
    public static int parseInt(ByteBuf bytes) {
        return parseInt(bytes, bytes.readerIndex(), bytes.readableBytes());
    }

    /**
     * Parses the byte buffer argument as if it was an int value and returns the
     * result. Throws NumberFormatException if the byte array does not represent an
     * int quantity.
     *
     * @return int the value represented by the argument
     * @throws NumberFormatException if the argument could not be parsed as an int quantity.
     */
    public static int parseInt(ByteBuf bytes, int start, int length) {
        return parseInt(bytes, start, length, 10);
    }

    /**
     * Parses the byte buffer argument as if it was an int value and returns the
     * result. Throws NumberFormatException if the byte array does not represent an
     * int quantity. The second argument specifies the radix to use when parsing
     * the value.
     *
     * @param radix the base to use for conversion.
     * @return the value represented by the argument
     * @throws NumberFormatException if the argument could not be parsed as an int quantity.
     */
    public static int parseInt(ByteBuf bytes, int start, int length, int radix) {
        if (!PlatformDependent.hasUnsafe()) {
            return parseInt(bytes.array(), start, length);
        }

        if (bytes == null) {
            throw new NumberFormatException("String is null");
        }
        if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) {
            throw new NumberFormatException("Invalid radix: " + radix);
        }
        if (length == 0 || bytes.writerIndex() < start + length) {
            throw new NumberFormatException("Empty string or Invalid buffer!");
        }

        long memoryAddress = bytes.memoryAddress();

        int offset = start;
        boolean negative = PlatformDependent.getByte(memoryAddress + start) == '-';
        if (negative || PlatformDependent.getByte(memoryAddress + start) == '+') {
            offset++;
            if (length == 1) {
                throw new NumberFormatException(bytes.toString(start, length, Charset.defaultCharset()));
            }
        }

        return parseIntInternal(bytes, memoryAddress, start, length, offset, radix, negative);
    }

    /**
     * @param bytes         the string byte buffer
     * @param memoryAddress the offheap memory address
     * @param start
     * @param length
     * @param radix         the base to use for conversion.
     * @param offset        the starting position after the sign (if exists)
     * @param radix         the base to use for conversion.
     * @param negative      whether the number is negative.
     * @return the value represented by the argument
     * @throws NumberFormatException if the argument could not be parsed as an int quantity.
     */
    private static int parseIntInternal(ByteBuf bytes, long memoryAddress, int start, int length, int offset,
            int radix, boolean negative) {
        byte separator = '.';
        int max = Integer.MIN_VALUE / radix;
        int result = 0, end = start + length;
        while (offset < end) {
            int digit = digit(PlatformDependent.getByte(memoryAddress + offset++), radix);
            if (digit == -1) {
                if (PlatformDependent.getByte(memoryAddress + offset - 1) == separator) {
                    // We allow decimals and will return a truncated integer in that case.
                    // Therefore we won't throw an exception here (checking the fractional
                    // part happens below.)
                    break;
                }
                throw new NumberFormatException(bytes.toString(start, length, Charset.defaultCharset()));
            }
            if (max > result) {
                throw new NumberFormatException(bytes.toString(start, length, Charset.defaultCharset()));
            }
            int next = result * radix - digit;
            if (next > result) {
                throw new NumberFormatException(bytes.toString(start, length, Charset.defaultCharset()));
            }
            result = next;
        }

        // This is the case when we've encountered a decimal separator. The fractional
        // part will not change the number, but we will verify that the fractional part
        // is well formed.
        while (offset < end) {
            int digit = digit(PlatformDependent.getByte(memoryAddress + offset++), radix);
            if (digit == -1) {
                throw new NumberFormatException(bytes.toString(start, length, Charset.defaultCharset()));
            }
        }

        if (!negative) {
            result = -result;
            if (result < 0) {
                throw new NumberFormatException(bytes.toString(start, length, Charset.defaultCharset()));
            }
        }
        return result;
    }

    /**
     * Parses the byte buffer argument as if it was a long value and returns the
     * result. Throws NumberFormatException if the string does not represent a
     * long quantity.
     *
     * @param bytes the string byte buffer
     * @return long the value represented by the argument
     * @throws NumberFormatException if the argument could not be parsed as a long quantity.
     */
    public static long parseLong(ByteBuf bytes) {
        return parseLong(bytes, bytes.readerIndex(), bytes.readableBytes());
    }

    /**
     * Parses the byte buffer argument as if it was a long value and returns the
     * result. Throws NumberFormatException if the string does not represent a
     * long quantity.
     *
     * @param bytes  the string byte buffer
     * @param start
     * @param length a UTF-8 encoded string representation of a long quantity.
     * @return long the value represented by the argument
     * @throws NumberFormatException if the argument could not be parsed as a long quantity.
     */
    public static long parseLong(ByteBuf bytes, int start, int length) {
        return parseLong(bytes, start, length, 10);
    }

    /**
     * Parses the byte buffer argument as if it was an long value and returns the
     * result. Throws NumberFormatException if the string does not represent an
     * long quantity. The second argument specifies the radix to use when parsing
     * the value.
     *
     * @param bytes  the string byte buffer
     * @param start
     * @param length a UTF-8 encoded string representation of a long quantity.
     * @param radix  the base to use for conversion.
     * @return the value represented by the argument
     * @throws NumberFormatException if the argument could not be parsed as an long quantity.
     */
    public static long parseLong(ByteBuf bytes, int start, int length, int radix) {
        if (!PlatformDependent.hasUnsafe()) {
            return parseInt(bytes.array(), start, length);
        }

        if (bytes == null) {
            throw new NumberFormatException("String is null");
        }
        if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) {
            throw new NumberFormatException("Invalid radix: " + radix);
        }
        if (length == 0 || bytes.writerIndex() < start + length) {
            throw new NumberFormatException("Empty string or Invalid buffer!");
        }

        long memoryAddress = bytes.memoryAddress();

        int offset = start;
        boolean negative = PlatformDependent.getByte(memoryAddress + start) == '-';
        if (negative || PlatformDependent.getByte(memoryAddress + start) == '+') {
            offset++;
            if (length == 1) {
                throw new NumberFormatException(bytes.toString(start, length, Charset.defaultCharset()));
            }
        }

        return parseLongInternal(bytes, memoryAddress, start, length, offset, radix, negative);
    }

    /**
     * /** Parses the byte buffer argument as if it was an long value and returns the
     * result. Throws NumberFormatException if the string does not represent an
     * long quantity. The second argument specifies the radix to use when parsing
     * the value.
     *
     * @param bytes         the string byte buffer
     * @param memoryAddress the offheap memory address
     * @param start
     * @param length        a UTF-8 encoded string representation of a long quantity.
     * @param offset        the starting position after the sign (if exists)
     * @param radix         the base to use for conversion.
     * @param negative      whether the number is negative.
     * @return the value represented by the argument
     * @throws NumberFormatException if the argument could not be parsed as an long quantity.
     */
    private static long parseLongInternal(ByteBuf bytes, long memoryAddress, int start, int length, int offset,
            int radix, boolean negative) {
        byte separator = '.';
        long max = Long.MIN_VALUE / radix;
        long result = 0, end = start + length;
        while (offset < end) {
            int digit = digit(PlatformDependent.getByte(memoryAddress + offset++), radix);
            if (digit == -1 || max > result) {
                if (PlatformDependent.getByte(memoryAddress + offset - 1) == separator) {
                    // We allow decimals and will return a truncated integer in that case.
                    // Therefore we won't throw an exception here (checking the fractional
                    // part happens below.)
                    break;
                }
                throw new NumberFormatException(bytes.toString(start, length, Charset.defaultCharset()));
            }
            long next = result * radix - digit;
            if (next > result) {
                throw new NumberFormatException(bytes.toString(start, length, Charset.defaultCharset()));
            }
            result = next;
        }

        // This is the case when we've encountered a decimal separator. The fractional
        // part will not change the number, but we will verify that the fractional part
        // is well formed.
        while (offset < end) {
            int digit = digit(PlatformDependent.getByte(memoryAddress + offset++), radix);
            if (digit == -1) {
                throw new NumberFormatException(bytes.toString(start, length, Charset.defaultCharset()));
            }
        }

        if (!negative) {
            result = -result;
            if (result < 0) {
                throw new NumberFormatException(bytes.toString(start, length, Charset.defaultCharset()));
            }
        }
        return result;
    }

    public static Number numberValue(Class<?> numberClazz, String value) {
        Number returnNumber = null;

        if (numberClazz == null && value == null) {
            return returnNumber;
        }

        if (Number.class.isAssignableFrom(numberClazz)) {
            try {
                Constructor<?> constructor = numberClazz.getConstructor(String.class);
                returnNumber = (Number) constructor.newInstance(value);
            } catch (RuntimeException e) {
                throw e;
            } catch (Exception ignored) {
            }

        }

        return returnNumber;
    }
}