/*
* Copyright 2007-2012 Amazon Technologies, Inc. or its affiliates.
* Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
* of Amazon Technologies, Inc. or its affiliates. All rights reserved.
*
* 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.amazon.carbonado.util;
import java.util.Comparator;
import org.cojen.classfile.TypeDesc;
/**
* Collection of utility comparators.
*
* @author Brian S O'Neill
*/
public class Comparators {
/**
* Returns a comparator which can sort single or multi-dimensional arrays
* of primitves or Comparables.
*
* @param unsigned applicable only to arrays of bytes, shorts, ints, or longs
* @return null if unsupported
*/
public static <T> Comparator<T> arrayComparator(Class<T> arrayType, boolean unsigned) {
if (!arrayType.isArray()) {
throw new IllegalArgumentException();
}
Comparator c;
TypeDesc componentType = TypeDesc.forClass(arrayType.getComponentType());
switch (componentType.getTypeCode()) {
case TypeDesc.BYTE_CODE:
c = unsigned ? UnsignedByteArray : SignedByteArray;
break;
case TypeDesc.SHORT_CODE:
c = unsigned ? UnsignedShortArray : SignedShortArray;
break;
case TypeDesc.INT_CODE:
c = unsigned ? UnsignedIntArray : SignedIntArray;
break;
case TypeDesc.LONG_CODE:
c = unsigned ? UnsignedLongArray : SignedLongArray;
break;
case TypeDesc.BOOLEAN_CODE:
c = BooleanArray;
break;
case TypeDesc.CHAR_CODE:
c = CharArray;
break;
case TypeDesc.FLOAT_CODE:
c = FloatArray;
break;
case TypeDesc.DOUBLE_CODE:
c = DoubleArray;
break;
case TypeDesc.OBJECT_CODE: default:
if (componentType.isArray()) {
c = new ComparatorArray(arrayComparator(componentType.toClass(), unsigned));
} else if (Comparable.class.isAssignableFrom(componentType.toClass())) {
c = ComparableArray;
} else {
c = null;
}
break;
}
return (Comparator<T>) c;
}
private static final Comparator<byte[]> SignedByteArray = new Comparator<byte[]>() {
public int compare(byte[] a, byte[] b) {
int len = Math.min(a.length, b.length);
for (int i=0; i<len; i++) {
byte ai = a[i];
byte bi = b[i];
if (ai != bi) {
return ai - bi;
}
}
return a.length - b.length;
}
};
private static final Comparator<byte[]> UnsignedByteArray = new Comparator<byte[]>() {
public int compare(byte[] a, byte[] b) {
int len = Math.min(a.length, b.length);
for (int i=0; i<len; i++) {
byte ai = a[i];
byte bi = b[i];
if (ai != bi) {
return (ai & 0xff) - (bi & 0xff);
}
}
return a.length - b.length;
}
};
private static final Comparator<short[]> SignedShortArray = new Comparator<short[]>() {
public int compare(short[] a, short[] b) {
int len = Math.min(a.length, b.length);
for (int i=0; i<len; i++) {
short ai = a[i];
short bi = b[i];
if (ai != bi) {
return ai - bi;
}
}
return a.length - b.length;
}
};
private static final Comparator<short[]> UnsignedShortArray = new Comparator<short[]>() {
public int compare(short[] a, short[] b) {
int len = Math.min(a.length, b.length);
for (int i=0; i<len; i++) {
short ai = a[i];
short bi = b[i];
if (ai != bi) {
return (ai & 0xffff) - (bi & 0xffff);
}
}
return a.length - b.length;
}
};
private static final Comparator<int[]> SignedIntArray = new Comparator<int[]>() {
public int compare(int[] a, int[] b) {
int len = Math.min(a.length, b.length);
for (int i=0; i<len; i++) {
int ai = a[i];
int bi = b[i];
if (ai != bi) {
return ai < bi ? -1 : 1;
}
}
return a.length - b.length;
}
};
private static final Comparator<int[]> UnsignedIntArray = new Comparator<int[]>() {
public int compare(int[] a, int[] b) {
int len = Math.min(a.length, b.length);
for (int i=0; i<len; i++) {
int ai = a[i];
int bi = b[i];
if (ai != bi) {
return (ai & 0xffffffffL) < (bi & 0xffffffffL) ? -1 : 1;
}
}
return a.length - b.length;
}
};
private static final Comparator<long[]> SignedLongArray = new Comparator<long[]>() {
public int compare(long[] a, long[] b) {
int len = Math.min(a.length, b.length);
for (int i=0; i<len; i++) {
long ai = a[i];
long bi = b[i];
if (ai != bi) {
return ai < bi ? -1 : 1;
}
}
return a.length - b.length;
}
};
private static final Comparator<long[]> UnsignedLongArray = new Comparator<long[]>() {
public int compare(long[] a, long[] b) {
int len = Math.min(a.length, b.length);
for (int i=0; i<len; i++) {
long ai = a[i];
long bi = b[i];
if (ai != bi) {
long sai = ai >>> 1;
long sbi = bi >>> 1;
if (sai < sbi) {
return -1;
}
if (sai > sbi) {
return 1;
}
return (ai & 1) == 0 ? -1 : 1;
}
}
return a.length - b.length;
}
};
private static final Comparator<boolean[]> BooleanArray = new Comparator<boolean[]>() {
public int compare(boolean[] a, boolean[] b) {
int len = Math.min(a.length, b.length);
for (int i=0; i<len; i++) {
boolean ai = a[i];
boolean bi = b[i];
if (ai != bi) {
return ai ? 1 : -1;
}
}
return a.length - b.length;
}
};
private static final Comparator<char[]> CharArray = new Comparator<char[]>() {
public int compare(char[] a, char[] b) {
int len = Math.min(a.length, b.length);
for (int i=0; i<len; i++) {
char ai = a[i];
char bi = b[i];
if (ai != bi) {
return ai - bi;
}
}
return a.length - b.length;
}
};
private static final Comparator<float[]> FloatArray = new Comparator<float[]>() {
public int compare(float[] a, float[] b) {
int len = Math.min(a.length, b.length);
for (int i=0; i<len; i++) {
float ai = a[i];
float bi = b[i];
if (ai != bi) {
return Float.compare(ai, bi);
}
}
return a.length - b.length;
}
};
private static final Comparator<double[]> DoubleArray = new Comparator<double[]>() {
public int compare(double[] a, double[] b) {
int len = Math.min(a.length, b.length);
for (int i=0; i<len; i++) {
double ai = a[i];
double bi = b[i];
if (ai != bi) {
return Double.compare(ai, bi);
}
}
return a.length - b.length;
}
};
private static final Comparator<Comparable[]> ComparableArray = new Comparator<Comparable[]>()
{
public int compare(Comparable[] a, Comparable[] b) {
int len = Math.min(a.length, b.length);
for (int i=0; i<len; i++) {
Comparable ai = a[i];
Comparable bi = b[i];
if (ai == bi) {
continue;
}
if (ai == null) {
return 1;
}
if (bi == null) {
return -1;
}
int compare = ai.compareTo(bi);
if (compare != 0) {
return compare;
}
}
return a.length - b.length;
}
};
private static class ComparatorArray implements Comparator<Object[]> {
private final Comparator<Object> mComparator;
ComparatorArray(Comparator<Object> comparator) {
mComparator = comparator;
}
public int compare(Object[] a, Object[] b) {
int len = Math.min(a.length, b.length);
for (int i=0; i<len; i++) {
Object ai = a[i];
Object bi = b[i];
if (ai == bi) {
continue;
}
if (ai == null) {
return 1;
}
if (bi == null) {
return -1;
}
int compare = mComparator.compare(ai, bi);
if (compare != 0) {
return compare;
}
}
return a.length - b.length;
}
}
}