com.github.haixing_hu.io.OutputUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.github.haixing_hu.io.OutputUtils.java

Source

/*
 * Copyright (c) 2014  Haixing Hu
 *
 * Licensed 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.github.haixing_hu.io;

import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Collection;
import java.util.Date;
import java.util.Map;

import javax.annotation.Nullable;

import com.github.haixing_hu.collection.primitive.BooleanCollection;
import com.github.haixing_hu.collection.primitive.BooleanIterator;
import com.github.haixing_hu.collection.primitive.ByteCollection;
import com.github.haixing_hu.collection.primitive.ByteIterator;
import com.github.haixing_hu.collection.primitive.CharCollection;
import com.github.haixing_hu.collection.primitive.CharIterator;
import com.github.haixing_hu.collection.primitive.DoubleCollection;
import com.github.haixing_hu.collection.primitive.DoubleIterator;
import com.github.haixing_hu.collection.primitive.FloatCollection;
import com.github.haixing_hu.collection.primitive.FloatIterator;
import com.github.haixing_hu.collection.primitive.IntCollection;
import com.github.haixing_hu.collection.primitive.IntIterator;
import com.github.haixing_hu.collection.primitive.LongCollection;
import com.github.haixing_hu.collection.primitive.LongIterator;
import com.github.haixing_hu.collection.primitive.ShortCollection;
import com.github.haixing_hu.collection.primitive.ShortIterator;
import com.github.haixing_hu.io.serialize.BinarySerialization;
import com.github.haixing_hu.io.serialize.BinarySerializer;
import com.github.haixing_hu.io.serialize.NoBinarySerializerRegisteredException;
import com.github.haixing_hu.util.buffer.ByteBuffer;
import com.google.common.collect.Multimap;

/**
 * Provides functions to write data to the {@link Output} object.
 *
 * @author Haixing Hu
 */
public final class OutputUtils {

    private static final String UNSUPPORTED_VAR_NUMBER = "The variable length integer format does not support negative value.";

    public static boolean writeNullMark(final OutputStream out, final Object object) throws IOException {
        if (object == null) {
            out.write(1);
            return true;
        } else {
            out.write(0);
            return false;
        }
    }

    public static void writeBoolean(final OutputStream out, final boolean value) throws IOException {
        if (value) {
            out.write(1);
        } else {
            out.write(0);
        }
    }

    public static void writeBooleanObject(final OutputStream out, @Nullable final Boolean value)
            throws IOException {
        if (!writeNullMark(out, value)) {
            writeBoolean(out, value);
        }
    }

    public static void writeChar(final OutputStream out, final char value) throws IOException {
        writeVarShort(out, (short) value);
    }

    public static void writeCharObject(final OutputStream out, @Nullable final Character value) throws IOException {
        if (!writeNullMark(out, value)) {
            writeChar(out, value);
        }
    }

    public static void writeByte(final OutputStream out, final byte value) throws IOException {
        out.write(value);
    }

    public static void writeByteObject(final OutputStream out, @Nullable final Byte value) throws IOException {
        if (!writeNullMark(out, value)) {
            writeByte(out, value);
        }
    }

    public static void writeShort(final OutputStream out, final short value) throws IOException {
        out.write(value >>> 8);
        out.write(value);
    }

    public static void writeShortObject(final OutputStream out, @Nullable final Short value) throws IOException {
        if (!writeNullMark(out, value)) {
            writeShort(out, value);
        }
    }

    public static void writeVarShort(final OutputStream out, final short value) throws IOException {
        writeVarInt(out, value);
    }

    public static void writeVarShortObject(final OutputStream out, @Nullable final Short value) throws IOException {
        if ((value != null) && (value < 0)) {
            throw new IllegalArgumentException(UNSUPPORTED_VAR_NUMBER);
        }
        if (!writeNullMark(out, value)) {
            writeVarInt(out, value);
        }
    }

    public static void writeInt(final OutputStream out, final int value) throws IOException {
        out.write(value >>> 24);
        out.write(value >>> 16);
        out.write(value >>> 8);
        out.write(value);
    }

    public static void writeIntObject(final OutputStream out, @Nullable final Integer value) throws IOException {
        if (!writeNullMark(out, value)) {
            writeInt(out, value);
        }
    }

    public static void writeVarInt(final OutputStream out, int value) throws IOException {
        if (value < 0) {
            throw new IllegalArgumentException(UNSUPPORTED_VAR_NUMBER);
        }
        while (value > 0x7F) {
            out.write((value & 0x7F) | 0x80);
            value >>>= 7;
        }
        out.write(value);
    }

    public static void writeVarIntObject(final OutputStream out, @Nullable final Integer value) throws IOException {
        if ((value != null) && (value < 0)) {
            throw new IllegalArgumentException(UNSUPPORTED_VAR_NUMBER);
        }
        if (!writeNullMark(out, value)) {
            writeVarInt(out, value);
        }
    }

    public static void writeLong(final OutputStream out, final long value) throws IOException {
        final byte[] buffer = new byte[8];
        buffer[0] = (byte) (value >>> 56);
        buffer[1] = (byte) (value >>> 48);
        buffer[2] = (byte) (value >>> 40);
        buffer[3] = (byte) (value >>> 32);
        buffer[4] = (byte) (value >>> 24);
        buffer[5] = (byte) (value >>> 16);
        buffer[6] = (byte) (value >>> 8);
        buffer[7] = (byte) value;
        out.write(buffer, 0, 8);
    }

    public static void writeLongObject(final OutputStream out, @Nullable final Long value) throws IOException {
        if (!writeNullMark(out, value)) {
            writeLong(out, value);
        }
    }

    public static void writeVarLong(final OutputStream out, long value) throws IOException {
        if (value < 0) {
            throw new IllegalArgumentException(UNSUPPORTED_VAR_NUMBER);
        }
        while (value > 0x7FL) {
            out.write((int) (value & 0x7FL) | 0x80);
            value >>>= 7;
        }
        out.write((int) value);
    }

    public static void writeVarLongObject(final OutputStream out, @Nullable final Long value) throws IOException {
        if ((value != null) && (value < 0)) {
            throw new IllegalArgumentException(UNSUPPORTED_VAR_NUMBER);
        }
        if (!writeNullMark(out, value)) {
            writeVarLong(out, value);
        }
    }

    public static void writeFloat(final OutputStream out, final float value) throws IOException {
        final int intBits = Float.floatToIntBits(value);
        writeInt(out, intBits);
    }

    public static void writeFloatObject(final OutputStream out, @Nullable final Float value) throws IOException {
        if (!writeNullMark(out, value)) {
            writeFloat(out, value);
        }
    }

    public static void writeDouble(final OutputStream out, final double value) throws IOException {
        final long longBits = Double.doubleToLongBits(value);
        writeLong(out, longBits);
    }

    public static void writeDoubleObject(final OutputStream out, @Nullable final Double value) throws IOException {
        if (!writeNullMark(out, value)) {
            writeDouble(out, value);
        }
    }

    public static void writeString(final OutputStream out, @Nullable final String value) throws IOException {
        if (!writeNullMark(out, value)) {
            final int strlen = value.length();
            if (strlen == 0) {
                writeVarInt(out, 0); // special case for empty string
                return;
            }
            final ByteBuffer bytes = new ByteBuffer();
            // encode the characters
            for (int i = 0; i < strlen; ++i) {
                final int ch = value.charAt(i);
                if ((ch >= 0x0001) && (ch <= 0x007F)) {
                    bytes.append((byte) ch);
                } else if (ch > 0x07FF) {
                    bytes.append((byte) (0xE0 | ((ch >> 12) & 0x0F)));
                    bytes.append((byte) (0x80 | ((ch >> 6) & 0x3F)));
                    bytes.append((byte) (0x80 | (ch & 0x3F)));
                } else {
                    bytes.append((byte) (0xC0 | ((ch >> 6) & 0x1F)));
                    bytes.append((byte) (0x80 | (ch & 0x3F)));
                }
            }
            // write the length and bytes of the buffer
            writeVarInt(out, bytes.length());
            out.write(bytes.buffer(), 0, bytes.length());
        }
    }

    public static void writeDate(final OutputStream out, @Nullable final Date value) throws IOException {
        if (!writeNullMark(out, value)) {
            final long time = value.getTime();
            writeLong(out, time);
        }
    }

    public static void writeBigInteger(final OutputStream out, @Nullable final BigInteger value)
            throws IOException {
        if (!writeNullMark(out, value)) {
            if (value.signum() == 0) { // value == 0
                writeVarInt(out, 0);
            } else {
                final byte[] bits = value.toByteArray();
                writeVarInt(out, bits.length);
                out.write(bits, 0, bits.length);
            }
        }
    }

    public static void writeBigDecimal(final OutputStream out, @Nullable final BigDecimal value)
            throws IOException {
        if (!writeNullMark(out, value)) {
            if (value.signum() == 0) { // value == 0
                writeVarInt(out, 0);
            } else {
                final BigInteger unscaledValue = value.unscaledValue();
                final byte[] bits = unscaledValue.toByteArray();
                writeVarInt(out, bits.length);
                out.write(bits, 0, bits.length);
                writeInt(out, value.scale());
            }
        }
    }

    public static void writeClass(final OutputStream out, @Nullable final Class<?> value) throws IOException {
        if (value == null) {
            writeString(out, null);
        } else {
            writeString(out, value.getName());
        }
    }

    public static void writeEnum(final OutputStream out, @Nullable final Enum<?> value) throws IOException {
        if (!writeNullMark(out, value)) {
            writeVarInt(out, value.ordinal());
        }
    }

    public static void writeBooleanArray(final OutputStream out, @Nullable final boolean[] array)
            throws IOException {
        if (!writeNullMark(out, array)) {
            writeVarInt(out, array.length);
            for (final boolean value : array) {
                writeBoolean(out, value);
            }
        }
    }

    public static void writeBooleanArray(final OutputStream out, final boolean[] array, final int off,
            final int len) throws IOException {
        if ((off < 0) || (len < 0) || (len > array.length - off)) {
            throw new IndexOutOfBoundsException();
        }
        writeVarInt(out, len);
        final int end = off + len;
        for (int i = off; i < end; ++i) {
            writeBoolean(out, array[i]);
        }
    }

    public static void writeBooleanCollection(final OutputStream out, @Nullable final BooleanCollection col)
            throws IOException {
        if (!writeNullMark(out, col)) {
            writeVarInt(out, col.size());
            final BooleanIterator iter = col.iterator();
            while (iter.hasNext()) {
                final boolean value = iter.next();
                writeBoolean(out, value);
            }
        }
    }

    public static void writeCharArray(final OutputStream out, @Nullable final char[] array) throws IOException {
        if (!writeNullMark(out, array)) {
            writeVarInt(out, array.length);
            for (final char value : array) {
                writeChar(out, value);
            }
        }
    }

    public static void writeCharArray(final OutputStream out, final char[] array, final int off, final int len)
            throws IOException {
        if ((off < 0) || (len < 0) || (len > array.length - off)) {
            throw new IndexOutOfBoundsException();
        }
        writeVarInt(out, len);
        final int end = off + len;
        for (int i = off; i < end; ++i) {
            writeChar(out, array[i]);
        }
    }

    public static void writeCharCollection(final OutputStream out, @Nullable final CharCollection col)
            throws IOException {
        if (!writeNullMark(out, col)) {
            writeVarInt(out, col.size());
            final CharIterator iter = col.iterator();
            while (iter.hasNext()) {
                final char value = iter.next();
                writeChar(out, value);
            }
        }
    }

    public static void writeByteArray(final OutputStream out, @Nullable final byte[] array) throws IOException {
        if (!writeNullMark(out, array)) {
            writeVarInt(out, array.length);
            // use the write() to optimize the writing of bytes
            out.write(array, 0, array.length);
        }
    }

    public static void writeByteArray(final OutputStream out, final byte[] array, final int off, final int len)
            throws IOException {
        if ((off < 0) || (len < 0) || (len > array.length - off)) {
            throw new IndexOutOfBoundsException();
        }
        writeVarInt(out, len);
        out.write(array, off, len);
    }

    public static void writeByteCollection(final OutputStream out, @Nullable final ByteCollection col)
            throws IOException {
        if (!writeNullMark(out, col)) {
            writeVarInt(out, col.size());
            final ByteIterator iter = col.iterator();
            while (iter.hasNext()) {
                final byte value = iter.next();
                writeByte(out, value);
            }
        }
    }

    public static void writeShortArray(final OutputStream out, @Nullable final short[] array) throws IOException {
        if (!writeNullMark(out, array)) {
            writeVarInt(out, array.length);
            for (final short value : array) {
                writeShort(out, value);
            }
        }
    }

    public static void writeShortArray(final OutputStream out, final short[] array, final int off, final int len)
            throws IOException {
        if ((off < 0) || (len < 0) || (len > array.length - off)) {
            throw new IndexOutOfBoundsException();
        }
        writeVarInt(out, len);
        final int end = off + len;
        for (int i = off; i < end; ++i) {
            writeShort(out, array[i]);
        }
    }

    public static void writeShortCollection(final OutputStream out, @Nullable final ShortCollection col)
            throws IOException {
        if (!writeNullMark(out, col)) {
            writeVarInt(out, col.size());
            final ShortIterator iter = col.iterator();
            while (iter.hasNext()) {
                final short value = iter.next();
                writeShort(out, value);
            }
        }
    }

    public static void writeVarShortArray(final OutputStream out, @Nullable final short[] array)
            throws IOException {
        if (!writeNullMark(out, array)) {
            writeVarInt(out, array.length);
            for (final short value : array) {
                writeVarShort(out, value);
            }
        }
    }

    public static void writeVarShortArray(final OutputStream out, final short[] array, final int off, final int len)
            throws IOException {
        if ((off < 0) || (len < 0) || (len > array.length - off)) {
            throw new IndexOutOfBoundsException();
        }
        writeVarInt(out, len);
        final int end = off + len;
        for (int i = off; i < end; ++i) {
            writeVarShort(out, array[i]);
        }
    }

    public static void writeVarShortCollection(final OutputStream out, @Nullable final ShortCollection col)
            throws IOException {
        if (!writeNullMark(out, col)) {
            writeVarInt(out, col.size());
            final ShortIterator iter = col.iterator();
            while (iter.hasNext()) {
                final short value = iter.next();
                writeVarShort(out, value);
            }
        }
    }

    public static void writeIntArray(final OutputStream out, @Nullable final int[] array) throws IOException {
        if (!writeNullMark(out, array)) {
            writeVarInt(out, array.length);
            for (final int value : array) {
                writeInt(out, value);
            }
        }
    }

    public static void writeIntArray(final OutputStream out, final int[] array, final int off, final int len)
            throws IOException {
        if ((off < 0) || (len < 0) || (len > array.length - off)) {
            throw new IndexOutOfBoundsException();
        }
        writeVarInt(out, len);
        final int end = off + len;
        for (int i = off; i < end; ++i) {
            writeInt(out, array[i]);
        }
    }

    public static void writeIntCollection(final OutputStream out, @Nullable final IntCollection col)
            throws IOException {
        if (!writeNullMark(out, col)) {
            writeVarInt(out, col.size());
            final IntIterator iter = col.iterator();
            while (iter.hasNext()) {
                final int value = iter.next();
                writeInt(out, value);
            }
        }
    }

    public static void writeVarIntArray(final OutputStream out, @Nullable final int[] array) throws IOException {
        if (!writeNullMark(out, array)) {
            writeVarInt(out, array.length);
            for (final int value : array) {
                writeVarInt(out, value);
            }
        }
    }

    public static void writeVarIntArray(final OutputStream out, final int[] array, final int off, final int len)
            throws IOException {
        if ((off < 0) || (len < 0) || (len > array.length - off)) {
            throw new IndexOutOfBoundsException();
        }
        writeVarInt(out, len);
        final int end = off + len;
        for (int i = off; i < end; ++i) {
            writeVarInt(out, array[i]);
        }
    }

    public static void writeVarIntCollection(final OutputStream out, @Nullable final IntCollection col)
            throws IOException {
        if (!writeNullMark(out, col)) {
            writeVarInt(out, col.size());
            final IntIterator iter = col.iterator();
            while (iter.hasNext()) {
                final int value = iter.next();
                writeVarInt(out, value);
            }
        }
    }

    public static void writeLongArray(final OutputStream out, @Nullable final long[] array) throws IOException {
        if (!writeNullMark(out, array)) {
            writeVarInt(out, array.length);
            for (final long value : array) {
                writeLong(out, value);
            }
        }
    }

    public static void writeLongArray(final OutputStream out, final long[] array, final int off, final int len)
            throws IOException {
        if ((off < 0) || (len < 0) || (len > array.length - off)) {
            throw new IndexOutOfBoundsException();
        }
        writeVarInt(out, len);
        final int end = off + len;
        for (int i = off; i < end; ++i) {
            writeLong(out, array[i]);
        }
    }

    public static void writeLongCollection(final OutputStream out, @Nullable final LongCollection col)
            throws IOException {
        if (!writeNullMark(out, col)) {
            writeVarInt(out, col.size());
            final LongIterator iter = col.iterator();
            while (iter.hasNext()) {
                final long value = iter.next();
                writeLong(out, value);
            }
        }
    }

    public static void writeVarLongArray(final OutputStream out, @Nullable final long[] array) throws IOException {
        if (!writeNullMark(out, array)) {
            writeVarInt(out, array.length);
            for (final long value : array) {
                writeVarLong(out, value);
            }
        }
    }

    public static void writeVarLongArray(final OutputStream out, final long[] array, final int off, final int len)
            throws IOException {
        if ((off < 0) || (len < 0) || (len > array.length - off)) {
            throw new IndexOutOfBoundsException();
        }
        writeVarInt(out, len);
        final int end = off + len;
        for (int i = off; i < end; ++i) {
            writeVarLong(out, array[i]);
        }
    }

    public static void writeVarLongCollection(final OutputStream out, @Nullable final LongCollection col)
            throws IOException {
        if (!writeNullMark(out, col)) {
            writeVarInt(out, col.size());
            final LongIterator iter = col.iterator();
            while (iter.hasNext()) {
                final long value = iter.next();
                writeVarLong(out, value);
            }
        }
    }

    public static void writeFloatArray(final OutputStream out, @Nullable final float[] array) throws IOException {
        if (!writeNullMark(out, array)) {
            writeVarInt(out, array.length);
            for (final float value : array) {
                writeFloat(out, value);
            }
        }
    }

    public static void writeFloatArray(final OutputStream out, final float[] array, final int off, final int len)
            throws IOException {
        if ((off < 0) || (len < 0) || (len > array.length - off)) {
            throw new IndexOutOfBoundsException();
        }
        writeVarInt(out, len);
        final int end = off + len;
        for (int i = off; i < end; ++i) {
            writeFloat(out, array[i]);
        }
    }

    public static void writeFloatCollection(final OutputStream out, @Nullable final FloatCollection col)
            throws IOException {
        if (!writeNullMark(out, col)) {
            writeVarInt(out, col.size());
            final FloatIterator iter = col.iterator();
            while (iter.hasNext()) {
                final float value = iter.next();
                writeFloat(out, value);
            }
        }
    }

    public static void writeDoubleArray(final OutputStream out, @Nullable final double[] array) throws IOException {
        if (!writeNullMark(out, array)) {
            writeVarInt(out, array.length);
            for (final double value : array) {
                writeDouble(out, value);
            }
        }
    }

    public static void writeDoubleArray(final OutputStream out, final double[] array, final int off, final int len)
            throws IOException {
        if ((off < 0) || (len < 0) || (len > array.length - off)) {
            throw new IndexOutOfBoundsException();
        }
        writeVarInt(out, len);
        final int end = off + len;
        for (int i = off; i < end; ++i) {
            writeDouble(out, array[i]);
        }
    }

    public static void writeDoubleCollection(final OutputStream out, @Nullable final DoubleCollection col)
            throws IOException {
        if (!writeNullMark(out, col)) {
            writeVarInt(out, col.size());
            final DoubleIterator iter = col.iterator();
            while (iter.hasNext()) {
                final double value = iter.next();
                writeDouble(out, value);
            }
        }
    }

    /**
     * Writes an object to an binary output stream.
     *
     * @param <T>
     *          The type of the class.
     * @param valueClass
     *          The class object of the object to be serialized.
     * @param out
     *          A binary output stream.
     * @param value
     *          The object to be serialized. It could be null.
     * @throws IOException
     *           If any I/O error occurred.
     */
    public static <T> void writeObject(final Class<T> valueClass, final OutputStream out, @Nullable final T value)
            throws IOException {
        final BinarySerializer serializer = BinarySerialization.getSerializer(valueClass);
        if (serializer == null) {
            throw new NoBinarySerializerRegisteredException(valueClass);
        }
        serializer.serialize(out, value);
    }

    public static <T> void writeArray(final Class<T> valueClass, final OutputStream out, @Nullable final T[] array)
            throws IOException {
        final BinarySerializer serializer = BinarySerialization.getSerializer(valueClass);
        if (serializer == null) {
            throw new NoBinarySerializerRegisteredException(valueClass);
        }
        if (!writeNullMark(out, array)) {
            writeVarInt(out, array.length);
            for (final T value : array) {
                serializer.serialize(out, value);
            }
        }
    }

    public static <T> void writeArray(final Class<T> valueClass, final OutputStream out, final T[] array,
            final int off, final int len) throws IOException {
        if ((off < 0) || (len < 0) || (len > array.length - off)) {
            throw new IndexOutOfBoundsException();
        }
        final BinarySerializer serializer = BinarySerialization.getSerializer(valueClass);
        if (serializer == null) {
            throw new NoBinarySerializerRegisteredException(valueClass);
        }
        writeVarInt(out, len);
        final int end = off + len;
        for (int i = off; i < end; ++i) {
            serializer.serialize(out, array[i]);
        }
    }

    public static <T> void writeCollection(final Class<T> valueClass, final OutputStream out,
            @Nullable final Collection<T> col) throws IOException {
        final BinarySerializer serializer = BinarySerialization.getSerializer(valueClass);
        if (serializer == null) {
            throw new NoBinarySerializerRegisteredException(valueClass);
        }
        if (!writeNullMark(out, col)) {
            writeVarInt(out, col.size());
            for (final T value : col) {
                serializer.serialize(out, value);
            }
        }
    }

    public static <K, V> void writeMap(final Class<K> keyClass, final Class<V> valueClass, final OutputStream out,
            @Nullable final Map<K, V> map) throws IOException {
        final BinarySerializer keySerializer = BinarySerialization.getSerializer(keyClass);
        if (keySerializer == null) {
            throw new NoBinarySerializerRegisteredException(keyClass);
        }
        final BinarySerializer valueSerializer = BinarySerialization.getSerializer(valueClass);
        if (valueSerializer == null) {
            throw new NoBinarySerializerRegisteredException(valueClass);
        }
        if (!writeNullMark(out, map)) {
            writeVarInt(out, map.size());
            for (final Map.Entry<K, V> entry : map.entrySet()) {
                final K key = entry.getKey();
                final V value = entry.getValue();
                keySerializer.serialize(out, key);
                valueSerializer.serialize(out, value);
            }
        }
    }

    public static <K, V> void writeMultimap(final OutputStream out, @Nullable final Multimap<K, V> map,
            final Class<K> keyClass, final Class<V> valueClass) throws IOException {
        final BinarySerializer keySerializer = BinarySerialization.getSerializer(keyClass);
        if (keySerializer == null) {
            throw new NoBinarySerializerRegisteredException(keyClass);
        }
        final BinarySerializer valueSerializer = BinarySerialization.getSerializer(valueClass);
        if (valueSerializer == null) {
            throw new NoBinarySerializerRegisteredException(valueClass);
        }
        if (!writeNullMark(out, map)) {
            writeVarInt(out, map.size());
            for (final Map.Entry<K, V> entry : map.entries()) {
                final K key = entry.getKey();
                final V value = entry.getValue();
                keySerializer.serialize(out, key);
                valueSerializer.serialize(out, value);
            }
        }
    }
}