com.phantom.hadoop.examples.terasort.Unsigned16.java Source code

Java tutorial

Introduction

Here is the source code for com.phantom.hadoop.examples.terasort.Unsigned16.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 com.phantom.hadoop.examples.terasort;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

import org.apache.hadoop.io.Writable;

/**
 * An unsigned 16 byte integer class that supports addition, multiplication, and
 * left shifts.
 */
class Unsigned16 implements Writable {
    private long hi8;
    private long lo8;

    public Unsigned16() {
        hi8 = 0;
        lo8 = 0;
    }

    public Unsigned16(long l) {
        hi8 = 0;
        lo8 = l;
    }

    public Unsigned16(Unsigned16 other) {
        hi8 = other.hi8;
        lo8 = other.lo8;
    }

    @Override
    public boolean equals(Object o) {
        if (o instanceof Unsigned16) {
            Unsigned16 other = (Unsigned16) o;
            return other.hi8 == hi8 && other.lo8 == lo8;
        }
        return false;
    }

    @Override
    public int hashCode() {
        return (int) lo8;
    }

    /**
     * Parse a hex string
     * 
     * @param s
     *            the hex string
     */
    public Unsigned16(String s) throws NumberFormatException {
        set(s);
    }

    /**
     * Set the number from a hex string
     * 
     * @param s
     *            the number in hexadecimal
     * @throws NumberFormatException
     *             if the number is invalid
     */
    public void set(String s) throws NumberFormatException {
        hi8 = 0;
        lo8 = 0;
        final long lastDigit = 0xfl << 60;
        for (int i = 0; i < s.length(); ++i) {
            int digit = getHexDigit(s.charAt(i));
            if ((lastDigit & hi8) != 0) {
                throw new NumberFormatException(s + " overflowed 16 bytes");
            }
            hi8 <<= 4;
            hi8 |= (lo8 & lastDigit) >>> 60;
            lo8 <<= 4;
            lo8 |= digit;
        }
    }

    /**
     * Set the number to a given long.
     * 
     * @param l
     *            the new value, which is treated as an unsigned number
     */
    public void set(long l) {
        lo8 = l;
        hi8 = 0;
    }

    /**
     * Map a hexadecimal character into a digit.
     * 
     * @param ch
     *            the character
     * @return the digit from 0 to 15
     * @throws NumberFormatException
     */
    private static int getHexDigit(char ch) throws NumberFormatException {
        if (ch >= '0' && ch <= '9') {
            return ch - '0';
        }
        if (ch >= 'a' && ch <= 'f') {
            return ch - 'a' + 10;
        }
        if (ch >= 'A' && ch <= 'F') {
            return ch - 'A' + 10;
        }
        throw new NumberFormatException(ch + " is not a valid hex digit");
    }

    private static final Unsigned16 TEN = new Unsigned16(10);

    public static Unsigned16 fromDecimal(String s) throws NumberFormatException {
        Unsigned16 result = new Unsigned16();
        Unsigned16 tmp = new Unsigned16();
        for (int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i);
            if (ch < '0' || ch > '9') {
                throw new NumberFormatException(ch + " not a valid decimal digit");
            }
            int digit = ch - '0';
            result.multiply(TEN);
            tmp.set(digit);
            result.add(tmp);
        }
        return result;
    }

    /**
     * Return the number as a hex string.
     */
    public String toString() {
        if (hi8 == 0) {
            return Long.toHexString(lo8);
        } else {
            StringBuilder result = new StringBuilder();
            result.append(Long.toHexString(hi8));
            String loString = Long.toHexString(lo8);
            for (int i = loString.length(); i < 16; ++i) {
                result.append('0');
            }
            result.append(loString);
            return result.toString();
        }
    }

    /**
     * Get a given byte from the number.
     * 
     * @param b
     *            the byte to get with 0 meaning the most significant byte
     * @return the byte or 0 if b is outside of 0..15
     */
    public byte getByte(int b) {
        if (b >= 0 && b < 16) {
            if (b < 8) {
                return (byte) (hi8 >> (56 - 8 * b));
            } else {
                return (byte) (lo8 >> (120 - 8 * b));
            }
        }
        return 0;
    }

    /**
     * Get the hexadecimal digit at the given position.
     * 
     * @param p
     *            the digit position to get with 0 meaning the most significant
     * @return the character or '0' if p is outside of 0..31
     */
    public char getHexDigit(int p) {
        byte digit = getByte(p / 2);
        if (p % 2 == 0) {
            digit >>>= 4;
        }
        digit &= 0xf;
        if (digit < 10) {
            return (char) ('0' + digit);
        } else {
            return (char) ('A' + digit - 10);
        }
    }

    /**
     * Get the high 8 bytes as a long.
     */
    public long getHigh8() {
        return hi8;
    }

    /**
     * Get the low 8 bytes as a long.
     */
    public long getLow8() {
        return lo8;
    }

    /**
     * Multiple the current number by a 16 byte unsigned integer. Overflow is
     * not detected and the result is the low 16 bytes of the result. The
     * numbers are divided into 32 and 31 bit chunks so that the product of two
     * chucks fits in the unsigned 63 bits of a long.
     * 
     * @param b
     *            the other number
     */
    void multiply(Unsigned16 b) {
        // divide the left into 4 32 bit chunks
        long[] left = new long[4];
        left[0] = lo8 & 0xffffffffl;
        left[1] = lo8 >>> 32;
        left[2] = hi8 & 0xffffffffl;
        left[3] = hi8 >>> 32;
        // divide the right into 5 31 bit chunks
        long[] right = new long[5];
        right[0] = b.lo8 & 0x7fffffffl;
        right[1] = (b.lo8 >>> 31) & 0x7fffffffl;
        right[2] = (b.lo8 >>> 62) + ((b.hi8 & 0x1fffffffl) << 2);
        right[3] = (b.hi8 >>> 29) & 0x7fffffffl;
        right[4] = (b.hi8 >>> 60);
        // clear the cur value
        set(0);
        Unsigned16 tmp = new Unsigned16();
        for (int l = 0; l < 4; ++l) {
            for (int r = 0; r < 5; ++r) {
                long prod = left[l] * right[r];
                if (prod != 0) {
                    int off = l * 32 + r * 31;
                    tmp.set(prod);
                    tmp.shiftLeft(off);
                    add(tmp);
                }
            }
        }
    }

    /**
     * Add the given number into the current number.
     * 
     * @param b
     *            the other number
     */
    public void add(Unsigned16 b) {
        long sumHi;
        long sumLo;
        long reshibit, hibit0, hibit1;

        sumHi = hi8 + b.hi8;

        hibit0 = (lo8 & 0x8000000000000000L);
        hibit1 = (b.lo8 & 0x8000000000000000L);
        sumLo = lo8 + b.lo8;
        reshibit = (sumLo & 0x8000000000000000L);
        if ((hibit0 & hibit1) != 0 | ((hibit0 ^ hibit1) != 0 && reshibit == 0))
            sumHi++; /* add carry bit */
        hi8 = sumHi;
        lo8 = sumLo;
    }

    /**
     * Shift the number a given number of bit positions. The number is the low
     * order bits of the result.
     * 
     * @param bits
     *            the bit positions to shift by
     */
    public void shiftLeft(int bits) {
        if (bits != 0) {
            if (bits < 64) {
                hi8 <<= bits;
                hi8 |= (lo8 >>> (64 - bits));
                lo8 <<= bits;
            } else if (bits < 128) {
                hi8 = lo8 << (bits - 64);
                lo8 = 0;
            } else {
                hi8 = 0;
                lo8 = 0;
            }
        }
    }

    @Override
    public void readFields(DataInput in) throws IOException {
        hi8 = in.readLong();
        lo8 = in.readLong();
    }

    @Override
    public void write(DataOutput out) throws IOException {
        out.writeLong(hi8);
        out.writeLong(lo8);
    }

}