com.blm.orc.DynamicByteArray.java Source code

Java tutorial

Introduction

Here is the source code for com.blm.orc.DynamicByteArray.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.blm.orc;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;

import org.apache.hadoop.io.Text;

/**
 * A class that is a growable array of bytes. Growth is managed in terms of
 * chunks that are allocated when needed.
 */
final class DynamicByteArray {
    static final int DEFAULT_CHUNKSIZE = 32 * 1024;
    static final int DEFAULT_NUM_CHUNKS = 128;

    private final int chunkSize; // our allocation sizes
    private byte[][] data; // the real data
    private int length; // max set element index +1
    private int initializedChunks = 0; // the number of chunks created

    public DynamicByteArray() {
        this(DEFAULT_NUM_CHUNKS, DEFAULT_CHUNKSIZE);
    }

    public DynamicByteArray(int numChunks, int chunkSize) {
        if (chunkSize == 0) {
            throw new IllegalArgumentException("bad chunksize");
        }
        this.chunkSize = chunkSize;
        data = new byte[numChunks][];
    }

    /**
     * Ensure that the given index is valid.
     */
    private void grow(int chunkIndex) {
        if (chunkIndex >= initializedChunks) {
            if (chunkIndex >= data.length) {
                int newSize = Math.max(chunkIndex + 1, 2 * data.length);
                byte[][] newChunk = new byte[newSize][];
                System.arraycopy(data, 0, newChunk, 0, data.length);
                data = newChunk;
            }
            for (int i = initializedChunks; i <= chunkIndex; ++i) {
                data[i] = new byte[chunkSize];
            }
            initializedChunks = chunkIndex + 1;
        }
    }

    public byte get(int index) {
        if (index >= length) {
            throw new IndexOutOfBoundsException("Index " + index + " is outside of 0.." + (length - 1));
        }
        int i = index / chunkSize;
        int j = index % chunkSize;
        return data[i][j];
    }

    public void set(int index, byte value) {
        int i = index / chunkSize;
        int j = index % chunkSize;
        grow(i);
        if (index >= length) {
            length = index + 1;
        }
        data[i][j] = value;
    }

    public int add(byte value) {
        int i = length / chunkSize;
        int j = length % chunkSize;
        grow(i);
        data[i][j] = value;
        int result = length;
        length += 1;
        return result;
    }

    /**
     * Copy a slice of a byte array into our buffer.
     * @param value the array to copy from
     * @param valueOffset the first location to copy from value
     * @param valueLength the number of bytes to copy from value
     * @return the offset of the start of the value
     */
    public int add(byte[] value, int valueOffset, int valueLength) {
        int i = length / chunkSize;
        int j = length % chunkSize;
        grow((length + valueLength) / chunkSize);
        int remaining = valueLength;
        while (remaining > 0) {
            int size = Math.min(remaining, chunkSize - j);
            System.arraycopy(value, valueOffset, data[i], j, size);
            remaining -= size;
            valueOffset += size;
            i += 1;
            j = 0;
        }
        int result = length;
        length += valueLength;
        return result;
    }

    /**
     * Read the entire stream into this array.
     * @param in the stream to read from
     * @throws IOException
     */
    public void readAll(InputStream in) throws IOException {
        int currentChunk = length / chunkSize;
        int currentOffset = length % chunkSize;
        grow(currentChunk);
        int currentLength = in.read(data[currentChunk], currentOffset, chunkSize - currentOffset);
        while (currentLength > 0) {
            length += currentLength;
            currentOffset = length % chunkSize;
            if (currentOffset == 0) {
                currentChunk = length / chunkSize;
                grow(currentChunk);
            }
            currentLength = in.read(data[currentChunk], currentOffset, chunkSize - currentOffset);
        }
    }

    /**
     * Byte compare a set of bytes against the bytes in this dynamic array.
     * @param other source of the other bytes
     * @param otherOffset start offset in the other array
     * @param otherLength number of bytes in the other array
     * @param ourOffset the offset in our array
     * @param ourLength the number of bytes in our array
     * @return negative for less, 0 for equal, positive for greater
     */
    public int compare(byte[] other, int otherOffset, int otherLength, int ourOffset, int ourLength) {
        int currentChunk = ourOffset / chunkSize;
        int currentOffset = ourOffset % chunkSize;
        int maxLength = Math.min(otherLength, ourLength);
        while (maxLength > 0 && other[otherOffset] == data[currentChunk][currentOffset]) {
            otherOffset += 1;
            currentOffset += 1;
            if (currentOffset == chunkSize) {
                currentChunk += 1;
                currentOffset = 0;
            }
            maxLength -= 1;
        }
        if (maxLength == 0) {
            return otherLength - ourLength;
        }
        int otherByte = 0xff & other[otherOffset];
        int ourByte = 0xff & data[currentChunk][currentOffset];
        return otherByte > ourByte ? 1 : -1;
    }

    /**
     * Get the size of the array.
     * @return the number of bytes in the array
     */
    public int size() {
        return length;
    }

    /**
     * Clear the array to its original pristine state.
     */
    public void clear() {
        length = 0;
        for (int i = 0; i < data.length; ++i) {
            data[i] = null;
        }
        initializedChunks = 0;
    }

    /**
     * Set a text value from the bytes in this dynamic array.
     * @param result the value to set
     * @param offset the start of the bytes to copy
     * @param length the number of bytes to copy
     */
    public void setText(Text result, int offset, int length) {
        result.clear();
        int currentChunk = offset / chunkSize;
        int currentOffset = offset % chunkSize;
        int currentLength = Math.min(length, chunkSize - currentOffset);
        while (length > 0) {
            result.append(data[currentChunk], currentOffset, currentLength);
            length -= currentLength;
            currentChunk += 1;
            currentOffset = 0;
            currentLength = Math.min(length, chunkSize - currentOffset);
        }
    }

    /**
     * Write out a range of this dynamic array to an output stream.
     * @param out the stream to write to
     * @param offset the first offset to write
     * @param length the number of bytes to write
     * @throws IOException
     */
    public void write(OutputStream out, int offset, int length) throws IOException {
        int currentChunk = offset / chunkSize;
        int currentOffset = offset % chunkSize;
        while (length > 0) {
            int currentLength = Math.min(length, chunkSize - currentOffset);
            out.write(data[currentChunk], currentOffset, currentLength);
            length -= currentLength;
            currentChunk += 1;
            currentOffset = 0;
        }
    }

    @Override
    public String toString() {
        int i;
        StringBuilder sb = new StringBuilder(length * 3);

        sb.append('{');
        int l = length - 1;
        for (i = 0; i < l; i++) {
            sb.append(Integer.toHexString(get(i)));
            sb.append(',');
        }
        sb.append(get(i));
        sb.append('}');

        return sb.toString();
    }

    public void setByteBuffer(ByteBuffer result, int offset, int length) {
        result.clear();
        int currentChunk = offset / chunkSize;
        int currentOffset = offset % chunkSize;
        int currentLength = Math.min(length, chunkSize - currentOffset);
        while (length > 0) {
            result.put(data[currentChunk], currentOffset, currentLength);
            length -= currentLength;
            currentChunk += 1;
            currentOffset = 0;
            currentLength = Math.min(length, chunkSize - currentOffset);
        }
    }

    /**
     * Gets all the bytes of the array.
     *
     * @return Bytes of the array
     */
    public byte[] get() {
        byte[] result = null;
        if (length > 0) {
            int currentChunk = 0;
            int currentOffset = 0;
            int currentLength = Math.min(length, chunkSize);
            int destOffset = 0;
            result = new byte[length];
            int totalLength = length;
            while (totalLength > 0) {
                System.arraycopy(data[currentChunk], currentOffset, result, destOffset, currentLength);
                destOffset += currentLength;
                totalLength -= currentLength;
                currentChunk += 1;
                currentOffset = 0;
                currentLength = Math.min(totalLength, chunkSize - currentOffset);
            }
        }
        return result;
    }

    /**
     * Get the size of the buffers.
     */
    public long getSizeInBytes() {
        return initializedChunks * chunkSize;
    }
}