/*
* Copyright (C) 2012 Facebook, Inc.
*
* 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.facebook.collections;
import com.google.common.base.Preconditions;
import java.util.Arrays;
import java.util.Comparator;
/**
* helper class that wraps a byte[] in order to properly get
* Arrays.hashcode()/equals() for use in a HashSet; also implements Comparable
*/
public abstract class ByteArray implements Comparable<ByteArray> {
public static final ByteArrayComparator BYTE_ARRAY_COMPARATOR = new ByteArrayComparator();
abstract public byte[] getArray();
abstract public int getLength();
public abstract byte getAdjusted(int pos);
public static ByteArray wrap(byte[] array) {
return new PureByteArray(array);
}
public static ByteArray wrap(byte[] array, int offset) {
return new ByteArrayView(array, offset);
}
public static ByteArray wrap(byte[] array, int offset, int length) {
Preconditions.checkArgument(offset + length <= array.length);
return new ByteArrayView(array, offset, length);
}
public static boolean equals(ByteArray array1, ByteArray array2) {
if (array1 == null) {
if (array2 == null) {
return true;
} else {
return false;
}
}
if (array2 == null) {
return false;
}
if (array1.getArray() == null) {
if (array2.getArray() == null) {
return true;
} else {
return false;
}
}
if (array2.getArray() == null) {
return false;
}
return Arrays.equals(array1.getArray(), array2.getArray());
}
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof ByteArray)) {
return false;
}
final ByteArray that = (ByteArray) o;
return ByteArray.equals(this, that);
}
private static class PureByteArray extends ByteArray {
private final byte[] array;
private PureByteArray(byte[] array) {
this.array = array;
}
@Override
public byte[] getArray() {
return array;
}
@Override
public int getLength() {
return array.length;
}
@Override
public byte getAdjusted(int pos) {
return array[pos];
}
@Override
public int compareTo(ByteArray o) {
return BYTE_ARRAY_COMPARATOR.compare(this, o);
}
@Override
public int hashCode() {
return array != null ? Arrays.hashCode(array) : 0;
}
@Override
public String toString() {
return "PureByteArray{" +
"array=" + Arrays.toString(array) +
'}';
}
}
private static class ByteArrayView extends ByteArray {
private final byte[] array;
private final int offset;
private final int length;
private ByteArrayView(byte[] array, int offset, int length) {
this.array = array;
this.offset = offset;
this.length = length;
}
private ByteArrayView(byte[] array, int offset) {
this(array, offset, array.length - offset);
}
private ByteArrayView(byte[] array) {
this(array, 0, array.length);
}
@Override
public byte[] getArray() {
return array;
}
@Override
public int getLength() {
return length;
}
@Override
public byte getAdjusted(int pos) {
return array[offset + pos];
}
@Override
public int hashCode() {
int result = array != null ? Arrays.hashCode(array) : 0;
result = 31 * result + offset;
result = 31 * result + length;
return result;
}
@Override
public int compareTo(ByteArray o) {
return BYTE_ARRAY_COMPARATOR.compare(this, o);
}
@Override
public String toString() {
return "ByteArrayView{" +
"array=" + Arrays.toString(array) +
", start=" + offset +
", length=" + length +
"} " + toString();
}
}
private static class ByteArrayComparator implements Comparator<ByteArray> {
@Override
public int compare(ByteArray o1, ByteArray o2) {
if (o1 == null) {
if (o2 == null) {
return 0;
} else {
return -1;
}
}
if (o2 == null) {
return 1;
}
if (o1.getArray() == null) {
if (o2.getArray() == null) {
return 0;
} else {
return -1;
}
}
if (o2.getArray() == null) {
return 1;
}
int array1Length = o1.getLength();
int array2Length = o2.getLength();
int length = Math.min(array1Length, array2Length);
for (int i = 0; i < length; i++) {
if (o1.getAdjusted(i) < o2.getAdjusted(i)) {
return -1;
} else if (o1.getAdjusted(i) > o2.getAdjusted(i)) {
return 1;
}
}
if (array1Length < array2Length) {
return -1;
} else if (array1Length > array2Length) {
return 1;
} else {
return 0;
}
}
}
}