blob: d4356239dd98d7be2b5ad148052ab25f89963fee [file] [log] [blame]
/*
* 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.pig.data;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import org.apache.hadoop.io.WritableComparator;
import org.apache.pig.classification.InterfaceAudience;
import org.apache.pig.classification.InterfaceStability;
/**
* An implementation of byte array. This is done as an object because we
* need to be able to implement compareTo, toString, hashCode, and some
* other methods.
*/
@InterfaceAudience.Public
@InterfaceStability.Stable
public class DataByteArray implements Comparable, Serializable {
private static final long serialVersionUID = 1L;
byte[] mData = null;
/**
* Default constructor. The data array will not be allocated when this
* constructor is called.
*/
public DataByteArray() {
}
/**
* Construct a byte array using the provided bytes as the content.
* @param b byte array to use as content. A reference to the bytes
* will be taken, the underlying bytes will not be copied.
*/
public DataByteArray(byte[] b) {
mData = b;
}
/**
* Construct a byte array concatenating the two provided
* byte arrays as the content.
* @param b the first byte array to use as content.
* @param c the other byte array to use as content.
*
*/
public DataByteArray(DataByteArray b, DataByteArray c) {
byte[] ba = (b == null) ? null : b.get();
byte[] ca = (c == null) ? null : c.get();
int baLength = (ba == null) ? 0 : ba.length;
int caLength = (ca == null) ? 0 : ca.length;
int totalSize = baLength + caLength;
if(totalSize == 0) {
return;
}
System.arraycopy(ba, 0, mData = new byte[totalSize], 0, baLength);
System.arraycopy(ca, 0, mData,baLength, caLength);
}
/**
* Construct a byte array using a portion of the provided bytes as content.
* @param b byte array to read from. A copy of the underlying bytes will be
* made.
* @param start starting point to copy from
* @param end ending point to copy to, exclusive.
*/
public DataByteArray(byte[] b, int start, int end) {
System.arraycopy(b, start, mData = new byte[end - start], 0, end-start);
}
/**
* Construct a byte array from a String. The contents of the string
* are copied.
* @param s String to make a byte array out of.
*/
public DataByteArray(String s) {
try {
mData = s.getBytes("UTF8");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* Find the size of the byte array.
* @return number of bytes in the array.
*/
public int size() {
return mData.length;
}
/**
* Get the underlying byte array. This is the real thing, not a copy,
* so don't mess with it!
* @return underlying byte[]
*/
public byte[] get() {
return mData;
}
/**
* Set the internal byte array. This should not be called unless the
* default constructor was used.
* @param b byte array to store. The contents of the byte array are
* not copied.
*/
public void set(byte[] b) {
mData = b;
}
/**
* Set the internal byte array. This should not be called unless the
* default constructor was used.
* @param s String to copy. The contents of the string are copied.
*/
public void set(String s) {
mData = s.getBytes();
}
/**
* Append given byte array to the internal byte array.
* @param b byte array who's contents to append. The contents of the byte array are
* copied.
*/
public DataByteArray append(DataByteArray b) {
byte[] ba = (b == null) ? null : b.get();
return append(ba, 0, ba == null ? 0 : ba.length);
}
public DataByteArray append(byte [] ba){
return append(ba, 0, ba.length);
}
public DataByteArray append(byte [] ba, int start, int baLength){
int mDataLength = (mData == null) ? 0 : mData.length;
int totalSize = mDataLength + baLength;
if(totalSize == 0) {
return this;
}
byte[] oldData = mData == null ? new byte[0] : mData.clone();
System.arraycopy(oldData, 0, mData = new byte[totalSize], 0, mDataLength);
System.arraycopy(ba, start, mData, mDataLength, baLength);
return this;
}
public DataByteArray append(String str){
try {
return append(str.getBytes("UTF8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
//TODO: better error here
throw new RuntimeException("Unable to append str: " + str);
}
/**
* Convert the byte array to a string. UTF8 encoding will be assumed.
*/
@Override
public String toString() {
String r="";
try {
r = new String(mData, "UTF8");
} catch (Exception e) {
// TODO: handle exception
}
return r;
}
/**
* Compare two byte arrays. Comparison is done first using byte values then
* length. So "g" will be greater than "abcdefg", but "hello worlds" is
* greater than "hello world". If the other object is not a DataByteArray,
* {@link DataType#compare} will be called.
*
* @param other Other object to compare to.
* @return -1 if less than, 1 if greater than, 0 if equal.
*/
public int compareTo(Object other) {
if (other instanceof DataByteArray) {
DataByteArray dba = (DataByteArray) other;
return compare(mData, dba.mData);
} else {
return DataType.compare(this, other);
}
}
public static int compare(byte[] b1, byte[] b2) {
return WritableComparator.compareBytes(b1, 0, b1.length,
b2, 0, b2.length);
}
@Override
public boolean equals(Object other) {
return (compareTo(other) == 0);
}
@Override
public int hashCode() {
return hashCode(mData);
}
public static int hashCode(byte[] buf) {
return Arrays.hashCode(buf);
}
}