Optimize comparison and hash #20
This commit is contained in:
parent
58bc4398c0
commit
3f56210b53
|
@ -21,8 +21,8 @@ import com.github.f4b6a3.ulid.UlidCreator;
|
||||||
@Fork(1)
|
@Fork(1)
|
||||||
@Threads(1)
|
@Threads(1)
|
||||||
@State(Scope.Benchmark)
|
@State(Scope.Benchmark)
|
||||||
@Warmup(iterations = 3)
|
@Warmup(iterations = 5, time = 1)
|
||||||
@Measurement(iterations = 5)
|
@Measurement(iterations = 5, time = 3)
|
||||||
@BenchmarkMode(Mode.Throughput)
|
@BenchmarkMode(Mode.Throughput)
|
||||||
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
||||||
public class Throughput {
|
public class Throughput {
|
||||||
|
|
|
@ -622,45 +622,45 @@ public final class Ulid implements Serializable, Comparable<Ulid> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
final int prime = 31;
|
final long bits = msb ^ lsb;
|
||||||
int result = 1;
|
return (int) (bits ^ (bits >>> 32));
|
||||||
result = prime * result + (int) (lsb ^ (lsb >>> 32));
|
|
||||||
result = prime * result + (int) (msb ^ (msb >>> 32));
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (this == obj)
|
|
||||||
return true;
|
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
return false;
|
return false;
|
||||||
if (getClass() != obj.getClass())
|
if (obj.getClass() != Ulid.class)
|
||||||
return false;
|
return false;
|
||||||
Ulid other = (Ulid) obj;
|
Ulid that = (Ulid) obj;
|
||||||
if (lsb != other.lsb)
|
if (lsb != that.lsb)
|
||||||
return false;
|
return false;
|
||||||
if (msb != other.msb)
|
if (msb != that.msb)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(Ulid other) {
|
public int compareTo(Ulid that) {
|
||||||
|
|
||||||
final long mask = 0xffffffffL;
|
// used to compare as UNSIGNED longs
|
||||||
|
final long min = 0x8000000000000000L;
|
||||||
|
|
||||||
final long[] a = { this.msb >>> 32, this.msb & mask, this.lsb >>> 32, this.lsb & mask };
|
final long a = this.msb + min;
|
||||||
final long[] b = { other.msb >>> 32, other.msb & mask, other.lsb >>> 32, other.lsb & mask };
|
final long b = that.msb + min;
|
||||||
|
|
||||||
// compare as fields unsigned integers
|
if (a > b)
|
||||||
for (int i = 0; i < a.length; i++) {
|
return 1;
|
||||||
if (a[i] > b[i]) {
|
else if (a < b)
|
||||||
return 1;
|
return -1;
|
||||||
} else if (a[i] < b[i]) {
|
|
||||||
return -1;
|
final long c = this.lsb + min;
|
||||||
}
|
final long d = that.lsb + min;
|
||||||
}
|
|
||||||
|
if (c > d)
|
||||||
|
return 1;
|
||||||
|
else if (c < d)
|
||||||
|
return -1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -337,6 +337,28 @@ public class UlidTest {
|
||||||
assertEquals(new BigInteger(random2).add(increment), new BigInteger(ulid2.getRandom()));
|
assertEquals(new BigInteger(random2).add(increment), new BigInteger(ulid2.getRandom()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHashCode() {
|
||||||
|
|
||||||
|
Random random = new Random();
|
||||||
|
byte[] bytes = new byte[Ulid.ULID_BYTES];
|
||||||
|
|
||||||
|
// invoked on the same object
|
||||||
|
for (int i = 0; i < DEFAULT_LOOP_MAX; i++) {
|
||||||
|
random.nextBytes(bytes);
|
||||||
|
Ulid ulid1 = Ulid.from(bytes);
|
||||||
|
assertEquals(ulid1.hashCode(), ulid1.hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
// invoked on two equal objects
|
||||||
|
for (int i = 0; i < DEFAULT_LOOP_MAX; i++) {
|
||||||
|
random.nextBytes(bytes);
|
||||||
|
Ulid ulid1 = Ulid.from(bytes);
|
||||||
|
Ulid ulid2 = Ulid.from(bytes);
|
||||||
|
assertEquals(ulid1.hashCode(), ulid2.hashCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEquals() {
|
public void testEquals() {
|
||||||
|
|
||||||
|
@ -366,15 +388,63 @@ public class UlidTest {
|
||||||
@Test
|
@Test
|
||||||
public void testCompareTo() {
|
public void testCompareTo() {
|
||||||
|
|
||||||
|
final long zero = 0L;
|
||||||
Random random = new Random();
|
Random random = new Random();
|
||||||
byte[] bytes = new byte[Ulid.ULID_BYTES];
|
byte[] bytes = new byte[Ulid.ULID_BYTES];
|
||||||
|
|
||||||
for (int i = 0; i < DEFAULT_LOOP_MAX; i++) {
|
for (int i = 0; i < DEFAULT_LOOP_MAX; i++) {
|
||||||
random.nextBytes(bytes);
|
|
||||||
|
bytes = ByteBuffer.allocate(16).putLong(random.nextLong()).putLong(random.nextLong()).array();
|
||||||
Ulid ulid1 = Ulid.from(bytes);
|
Ulid ulid1 = Ulid.from(bytes);
|
||||||
BigInteger number1 = new BigInteger(1, bytes);
|
BigInteger number1 = new BigInteger(1, bytes);
|
||||||
|
|
||||||
random.nextBytes(bytes);
|
bytes = ByteBuffer.allocate(16).putLong(random.nextLong()).putLong(random.nextLong()).array();
|
||||||
|
Ulid ulid2 = Ulid.from(bytes);
|
||||||
|
Ulid ulid3 = Ulid.from(bytes);
|
||||||
|
BigInteger number2 = new BigInteger(1, bytes);
|
||||||
|
BigInteger number3 = new BigInteger(1, bytes);
|
||||||
|
|
||||||
|
// compare numerically
|
||||||
|
assertEquals(number1.compareTo(number2) > 0, ulid1.compareTo(ulid2) > 0);
|
||||||
|
assertEquals(number1.compareTo(number2) < 0, ulid1.compareTo(ulid2) < 0);
|
||||||
|
assertEquals(number2.compareTo(number3) == 0, ulid2.compareTo(ulid3) == 0);
|
||||||
|
|
||||||
|
// compare lexicographically
|
||||||
|
assertEquals(number1.compareTo(number2) > 0, ulid1.toString().compareTo(ulid2.toString()) > 0);
|
||||||
|
assertEquals(number1.compareTo(number2) < 0, ulid1.toString().compareTo(ulid2.toString()) < 0);
|
||||||
|
assertEquals(number2.compareTo(number3) == 0, ulid2.toString().compareTo(ulid3.toString()) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < DEFAULT_LOOP_MAX; i++) {
|
||||||
|
|
||||||
|
bytes = ByteBuffer.allocate(16).putLong(zero).putLong(random.nextLong()).array();
|
||||||
|
Ulid ulid1 = Ulid.from(bytes);
|
||||||
|
BigInteger number1 = new BigInteger(1, bytes);
|
||||||
|
|
||||||
|
bytes = ByteBuffer.allocate(16).putLong(zero).putLong(random.nextLong()).array();
|
||||||
|
Ulid ulid2 = Ulid.from(bytes);
|
||||||
|
Ulid ulid3 = Ulid.from(bytes);
|
||||||
|
BigInteger number2 = new BigInteger(1, bytes);
|
||||||
|
BigInteger number3 = new BigInteger(1, bytes);
|
||||||
|
|
||||||
|
// compare numerically
|
||||||
|
assertEquals(number1.compareTo(number2) > 0, ulid1.compareTo(ulid2) > 0);
|
||||||
|
assertEquals(number1.compareTo(number2) < 0, ulid1.compareTo(ulid2) < 0);
|
||||||
|
assertEquals(number2.compareTo(number3) == 0, ulid2.compareTo(ulid3) == 0);
|
||||||
|
|
||||||
|
// compare lexicographically
|
||||||
|
assertEquals(number1.compareTo(number2) > 0, ulid1.toString().compareTo(ulid2.toString()) > 0);
|
||||||
|
assertEquals(number1.compareTo(number2) < 0, ulid1.toString().compareTo(ulid2.toString()) < 0);
|
||||||
|
assertEquals(number2.compareTo(number3) == 0, ulid2.toString().compareTo(ulid3.toString()) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < DEFAULT_LOOP_MAX; i++) {
|
||||||
|
|
||||||
|
bytes = ByteBuffer.allocate(16).putLong(random.nextLong()).putLong(zero).array();
|
||||||
|
Ulid ulid1 = Ulid.from(bytes);
|
||||||
|
BigInteger number1 = new BigInteger(1, bytes);
|
||||||
|
|
||||||
|
bytes = ByteBuffer.allocate(16).putLong(random.nextLong()).putLong(zero).array();
|
||||||
Ulid ulid2 = Ulid.from(bytes);
|
Ulid ulid2 = Ulid.from(bytes);
|
||||||
Ulid ulid3 = Ulid.from(bytes);
|
Ulid ulid3 = Ulid.from(bytes);
|
||||||
BigInteger number2 = new BigInteger(1, bytes);
|
BigInteger number2 = new BigInteger(1, bytes);
|
||||||
|
|
Loading…
Reference in New Issue