All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
javolution.util.stripped.FastComparator Maven / Gradle / Ivy
/*
* Javolution - Java(TM) Solution for Real-Time and Embedded Systems
* Copyright (C) 2006 - Javolution (http://javolution.org/)
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software is
* freely granted, provided that this notice is preserved.
*/
package javolution.util.stripped;
import java.io.ObjectStreamException;
import java.util.Comparator;
/**
* This class represents a comparator to be used for equality as well as
* for ordering; instances of this class provide a hashcode function
* consistent with equal (if two objects {@link #areEqual
* are equal}, they have the same {@link #hashCodeOf hashcode}),
* equality with null
values is supported.
*
* {@link FastComparator} can be employed with {@link FastMap} (e.g. custom
* key comparators for identity maps, value retrieval using keys of a
* different class that the map keys) or with {@link FastCollection}
* classes.
*
* @author Jean-Marie Dautelle
* @version 5.3, April 23, 2009
*/
public abstract class FastComparator implements Comparator {
public static boolean _Rehash = isPoorSystemHash();
private static boolean isPoorSystemHash() {
boolean[] dist = new boolean[64]; // Length power of 2.
for (int i = 0; i < dist.length; i++) {
dist[new Object().hashCode() & (dist.length - 1)] = true;
}
int occupied = 0;
for (int i = 0; i < dist.length;) {
occupied += dist[i++] ? 1 : 0; // Count occupied slots.
}
return occupied < (dist.length >> 2); // Less than 16 slots on 64.
}
/**
* Holds the default object comparator; rehash is performed if the
* system hash code (platform dependent) is not evenly distributed.
*
* @see
* Javolution Configuration
*/
public static final FastComparator DEFAULT = new Default ();
private static final class Default extends FastComparator {
public int hashCodeOf( T obj) {
return (obj == null) ? 0 : (_Rehash ? REHASH.hashCodeOf(obj) : obj.hashCode());
}
public boolean areEqual( T o1, T o2) {
return (o1 == null) ? (o2 == null) : (o1 == o2) || o1.equals(o2);
}
public int compare( T o1, T o2) {
return ((Comparable) o1).compareTo(o2);
}
public String toString() {
return "Default";
}
public Object readResolve() throws ObjectStreamException {
return DEFAULT;
}
};
/**
* Holds the direct object comparator; no rehash is performed.
* Two objects o1 and o2 are considered {@link #areEqual equal} if and
* only if o1.equals(o2)
. The {@link #compare} method
* throws {@link ClassCastException} if the specified objects are not
* {@link Comparable}.
*/
public static final FastComparator DIRECT = new Direct ();
private static final class Direct extends FastComparator {
public int hashCodeOf( T obj) {
return (obj == null) ? 0 : obj.hashCode();
}
public boolean areEqual( T o1, T o2) {
return (o1 == null) ? (o2 == null) : (o1 == o2) || o1.equals(o2);
}
public int compare( T o1, T o2) {
return ((Comparable) o1).compareTo(o2);
}
public String toString() {
return "Direct";
}
public Object readResolve() throws ObjectStreamException {
return DIRECT;
}
};
/**
* Holds the comparator for objects with uneven hash distribution; objects
* hashcodes are rehashed. Two objects o1 and o2 are considered
* {@link #areEqual equal} if and only if o1.equals(o2)
.
* The {@link #compare} method throws {@link ClassCastException} if the
* specified objects are not {@link Comparable}.
*/
public static final FastComparator REHASH = new Rehash ();
private static final class Rehash extends FastComparator {
public int hashCodeOf( T obj) {
if (obj == null)
return 0;
// Formula identical java.util.HashMap
to ensures
// similar behavior for ill-conditioned hashcode keys.
int h = obj.hashCode();
h += ~(h << 9);
h ^= (h >>> 14);
h += (h << 4);
return h ^ (h >>> 10);
}
public boolean areEqual( T o1, T o2) {
return (o1 == null) ? (o2 == null) : (o1 == o2) || o1.equals(o2);
}
public int compare( T o1, T o2) {
return ((Comparable) o1).compareTo(o2);
}
public String toString() {
return "Rehash";
}
public Object readResolve() throws ObjectStreamException {
return REHASH;
}
};
/**
* Holds a fast comparator for java.lang.String
. Hashcodes
* are calculated by taking a sample of few characters instead of
* the whole string.
*/
public static final FastComparator STRING = new StringComparator();
private static final class StringComparator extends FastComparator {
public int hashCodeOf(Object obj) {
if (obj == null)
return 0;
final String str = (String) obj;
final int length = str.length();
if (length == 0)
return 0;
return str.charAt(0) + str.charAt(length - 1) * 31 +
str.charAt(length >> 1) * 1009 +
str.charAt(length >> 2) * 27583 +
str.charAt(length - 1 - (length >> 2)) * 73408859;
}
public boolean areEqual(Object o1, Object o2) {
return (o1 == null) ? (o2 == null) : (o1 == o2) || o1.equals(o2);
}
public int compare(Object o1, Object o2) {
return ((String) o1).compareTo((String) o2);
}
public String toString() {
return "String";
}
public Object readResolve() throws ObjectStreamException {
return STRING;
}
};
/**
* Holds the identity comparator; poorly distributed system hashcodes are
* rehashed. Two objects o1 and o2 are considered {@link #areEqual equal}
* if and only if (o1 == o2)
. The {@link #compare} method
* throws {@link ClassCastException} if the specified objects are not
* {@link Comparable}.
*/
public static final FastComparator IDENTITY = new Identity();
private static final class Identity extends FastComparator {
public int hashCodeOf(Object obj) {
int h = System.identityHashCode(obj);
if (!_Rehash)
return h;
h += ~(h << 9);
h ^= (h >>> 14);
h += (h << 4);
return h ^ (h >>> 10);
}
public boolean areEqual(Object o1, Object o2) {
return o1 == o2;
}
public int compare(Object o1, Object o2) {
return ((Comparable) o1).compareTo(o2);
}
public String toString() {
return "Identity";
}
public Object readResolve() throws ObjectStreamException {
return IDENTITY;
}
};
/**
* Holds a lexicographic comparator for any {@link CharSequence} or
* {@link String} instances.
* Two objects are considered {@link #areEqual equal} if and only if they
* represents the same character sequence). The hashcode is calculated
* using the following formula (same as for java.lang.String
):
* s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
*/
public static final FastComparator LEXICAL = new Lexical();
private static final class Lexical extends FastComparator {
public int hashCodeOf(Object obj) {
if (obj == null)
return 0;
if ((obj instanceof String))
return obj.hashCode();
CharSequence chars = (CharSequence) obj;
int h = 0;
final int length = chars.length();
for (int i = 0; i < length;) {
h = 31 * h + chars.charAt(i++);
}
return h;
}
public boolean areEqual(Object o1, Object o2) {
if ((o1 instanceof String) && (o2 instanceof String))
return o1.equals(o2);
if ((o1 instanceof CharSequence) && (o2 instanceof String)) {
final CharSequence csq = (CharSequence) o1;
final String str = (String) o2;
final int length = str.length();
if (csq.length() != length)
return false;
for (int i = 0; i < length;) {
if (str.charAt(i) != csq.charAt(i++))
return false;
}
return true;
}
if ((o1 instanceof String) && (o2 instanceof CharSequence)) {
final CharSequence csq = (CharSequence) o2;
final String str = (String) o1;
final int length = str.length();
if (csq.length() != length)
return false;
for (int i = 0; i < length;) {
if (str.charAt(i) != csq.charAt(i++))
return false;
}
return true;
}
if ((o1 == null) || (o2 == null))
return o1 == o2;
final CharSequence csq1 = (CharSequence) o1;
final CharSequence csq2 = (CharSequence) o2;
final int length = csq1.length();
if (csq2.length() != length)
return false;
for (int i = 0; i < length;) {
if (csq1.charAt(i) != csq2.charAt(i++))
return false;
}
return true;
}
public int compare(Object left, Object right) {
if (left instanceof String) {
if (right instanceof String)
return ((String) left).compareTo((String) right);
// Right must be a CharSequence.
String seq1 = (String) left;
CharSequence seq2 = (CharSequence) right;
int i = 0;
int n = Math.min(seq1.length(), seq2.length());
while (n-- != 0) {
char c1 = seq1.charAt(i);
char c2 = seq2.charAt(i++);
if (c1 != c2)
return c1 - c2;
}
return seq1.length() - seq2.length();
}
if (right instanceof String)
return -compare(right, left);
// Both are CharSequence.
CharSequence seq1 = (CharSequence) left;
CharSequence seq2 = (CharSequence) right;
int i = 0;
int n = Math.min(seq1.length(), seq2.length());
while (n-- != 0) {
char c1 = seq1.charAt(i);
char c2 = seq2.charAt(i++);
if (c1 != c2)
return c1 - c2;
}
return seq1.length() - seq2.length();
}
public String toString() {
return "Lexical";
}
public Object readResolve() throws ObjectStreamException {
return LEXICAL;
}
};
/**
* Returns the hash code for the specified object (consistent with
* {@link #areEqual}). Two objects considered {@link #areEqual equal} have
* the same hash code.
*
* @param obj the object to return the hashcode for.
* @return the hashcode for the specified object.
*/
public abstract int hashCodeOf( T obj);
/**
* Indicates if the specified objects can be considered equal.
*
* @param o1 the first object (or null
).
* @param o2 the second object (or null
).
* @return true
if both objects are considered equal;
* false
otherwise.
*/
public abstract boolean areEqual( T o1, T o2);
/**
* Compares the specified objects for order. Returns a negative integer,
* zero, or a positive integer as the first argument is less than, equal to,
* or greater than the second.
*
* @param o1 the first object.
* @param o2 the second object.
* @return a negative integer, zero, or a positive integer as the first
* argument is less than, equal to, or greater than the second.
* @throws NullPointerException if any of the specified object is
* null
.
*/
public abstract int compare( T o1, T o2);
}