Small optimizations
Optimized methods: - UlidUtil.fromUuidToUlid() - UlidUtil.fromUlidToUuid() Added tests cases: - UlidUtilTest.testFromUuidToBytes() - UlidUtilTest.testFromBytesToUuid() - UlidUtilTest.testToAndFromBytes() Created classes: - Benchmarks.java (need to uncomment)
This commit is contained in:
parent
1fc0952067
commit
c01a914319
44
README.md
44
README.md
|
@ -12,36 +12,18 @@ Create a ULID:
|
||||||
String ulid = UlidCreator.getUlid();
|
String ulid = UlidCreator.getUlid();
|
||||||
```
|
```
|
||||||
|
|
||||||
Create a fast ULID:
|
|
||||||
|
|
||||||
```java
|
|
||||||
String ulid = UlidCreator.getFastUlid();
|
|
||||||
```
|
|
||||||
|
|
||||||
Create a ULID as GUID object:
|
Create a ULID as GUID object:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
UUID ulid = UlidCreator.getGuid();
|
UUID ulid = UlidCreator.getGuid();
|
||||||
```
|
```
|
||||||
|
|
||||||
Create a fast ULID as GUID object:
|
|
||||||
|
|
||||||
```java
|
|
||||||
UUID ulid = UlidCreator.getFastGuid();
|
|
||||||
```
|
|
||||||
|
|
||||||
Create a ULID as byte sequence:
|
Create a ULID as byte sequence:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
byte[] ulid = UlidCreator.getBytes();
|
byte[] ulid = UlidCreator.getBytes();
|
||||||
```
|
```
|
||||||
|
|
||||||
Create a fast ULID as byte sequence:
|
|
||||||
|
|
||||||
```java
|
|
||||||
byte[] ulid = UlidCreator.getFastBytes();
|
|
||||||
```
|
|
||||||
|
|
||||||
### Maven dependency
|
### Maven dependency
|
||||||
|
|
||||||
Add these lines to your `pom.xml`.
|
Add these lines to your `pom.xml`.
|
||||||
|
@ -51,7 +33,7 @@ Add these lines to your `pom.xml`.
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.f4b6a3</groupId>
|
<groupId>com.github.f4b6a3</groupId>
|
||||||
<artifactId>ulid-creator</artifactId>
|
<artifactId>ulid-creator</artifactId>
|
||||||
<version>1.0.1</version>
|
<version>1.0.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
See more options in [maven.org](https://search.maven.org/artifact/com.github.f4b6a3/ulid-creator) and [mvnrepository.com](https://mvnrepository.com/artifact/com.github.f4b6a3/ulid-creator).
|
See more options in [maven.org](https://search.maven.org/artifact/com.github.f4b6a3/ulid-creator) and [mvnrepository.com](https://mvnrepository.com/artifact/com.github.f4b6a3/ulid-creator).
|
||||||
|
@ -139,17 +121,19 @@ These are some examples of using the `GuidCreator` to create ULIDs:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
|
|
||||||
// with the default random generator (java.security.SecureRandom)
|
// with fixed timestamp strategy (for test cases)
|
||||||
String ulid = UlidCreator.getGuidCreator().createUlid();
|
|
||||||
|
|
||||||
// with java random generator (java.util.Random)
|
|
||||||
String ulid = UlidCreator.getGuidCreator()
|
String ulid = UlidCreator.getGuidCreator()
|
||||||
.withRandomGenerator(new Random())
|
.withTimestampStrategy(new FixedTimestampStretegy())
|
||||||
.createUlid();
|
.createUlid();
|
||||||
|
|
||||||
|
// with your custom timestamp strategy
|
||||||
|
String ulid = UlidCreator.getGuidCreator()
|
||||||
|
.withTimestampStrategy(new MyCustomTimestampStrategy())
|
||||||
|
.createUlid();
|
||||||
|
|
||||||
// with fast random generator (Xorshift128Plus)
|
// with your custom random number generator
|
||||||
String ulid = UlidCreator.getGuidCreator()
|
String ulid = UlidCreator.getGuidCreator()
|
||||||
.withFastRandomGenerator()
|
.withRandomGenerator(new MyCustomRandom())
|
||||||
.createUlid();
|
.createUlid();
|
||||||
|
|
||||||
// with fast random generator (Xorshift128Plus with salt)
|
// with fast random generator (Xorshift128Plus with salt)
|
||||||
|
@ -158,5 +142,11 @@ Random random = new Xorshift128PlusRandom(salt);
|
||||||
String ulid = UlidCreator.getGuidCreator()
|
String ulid = UlidCreator.getGuidCreator()
|
||||||
.withRandomGenerator(random)
|
.withRandomGenerator(random)
|
||||||
.createUlid();
|
.createUlid();
|
||||||
|
|
||||||
|
// with fast random generator (the same as above)
|
||||||
|
String ulid = UlidCreator.getGuidCreator()
|
||||||
|
.withFastRandomGenerator()
|
||||||
|
.createUlid();
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -46,8 +46,23 @@ public class UlidUtil {
|
||||||
* @return a ULID
|
* @return a ULID
|
||||||
*/
|
*/
|
||||||
public static String fromUuidToUlid(UUID uuid) {
|
public static String fromUuidToUlid(UUID uuid) {
|
||||||
byte[] bytes = fromUuidToBytes(uuid);
|
|
||||||
return fromBytesToUlid(bytes);
|
final long msb = uuid.getMostSignificantBits();
|
||||||
|
final long lsb = uuid.getLeastSignificantBits();
|
||||||
|
|
||||||
|
// Extract timestamp component
|
||||||
|
final long timeNumber = (msb >>> 16);
|
||||||
|
String timestampComponent = leftPad(Base32Util.toBase32Crockford(timeNumber));
|
||||||
|
|
||||||
|
// Extract randomness component
|
||||||
|
byte[] randBytes = new byte[10];
|
||||||
|
randBytes[0] = (byte) (msb >>> 8);
|
||||||
|
randBytes[1] = (byte) (msb);
|
||||||
|
byte[] lsbBytes = ByteUtil.toBytes(lsb);
|
||||||
|
System.arraycopy(lsbBytes, 0, randBytes, 2, 8);
|
||||||
|
String randomnessComponent = Base32Util.toBase32Crockford(randBytes);
|
||||||
|
|
||||||
|
return timestampComponent + randomnessComponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -59,9 +74,24 @@ public class UlidUtil {
|
||||||
* a ULID
|
* a ULID
|
||||||
* @return a UUID if valid
|
* @return a UUID if valid
|
||||||
*/
|
*/
|
||||||
public static UUID fromUlidToUuid(String ulid) {
|
public static UUID fromUlidToUuid(final String ulid) {
|
||||||
byte[] bytes = fromUlidToBytes(ulid);
|
|
||||||
return fromBytesToUuid(bytes);
|
UlidUtil.validate(ulid);
|
||||||
|
|
||||||
|
// Extract timestamp component
|
||||||
|
final String timestampComponent = ulid.substring(0, 10);
|
||||||
|
final long timeNumber = Base32Util.fromBase32CrockfordAsLong(timestampComponent);
|
||||||
|
|
||||||
|
// Extract randomness component
|
||||||
|
final String randomnessComponent = ulid.substring(10, 26);
|
||||||
|
byte[] randBytes = Base32Util.fromBase32Crockford(randomnessComponent);
|
||||||
|
byte[] lsbBytes = new byte[8];
|
||||||
|
System.arraycopy(randBytes, 2, lsbBytes, 0, 8);
|
||||||
|
|
||||||
|
final long msb = (timeNumber << 16) | ((randBytes[0] << 8) & 0x0000ff00L) | ((randBytes[1]) & 0x000000ffL);
|
||||||
|
final long lsb = ByteUtil.toNumber(lsbBytes);
|
||||||
|
|
||||||
|
return new UUID(msb, lsb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -71,11 +101,11 @@ public class UlidUtil {
|
||||||
* a UUID
|
* a UUID
|
||||||
* @return an array of bytes
|
* @return an array of bytes
|
||||||
*/
|
*/
|
||||||
public static byte[] fromUuidToBytes(UUID uuid) {
|
public static byte[] fromUuidToBytes(final UUID uuid) {
|
||||||
long msb = uuid.getMostSignificantBits();
|
final long msb = uuid.getMostSignificantBits();
|
||||||
long lsb = uuid.getLeastSignificantBits();
|
final long lsb = uuid.getLeastSignificantBits();
|
||||||
byte[] msbBytes = ByteUtil.toBytes(msb);
|
final byte[] msbBytes = ByteUtil.toBytes(msb);
|
||||||
byte[] lsbBytes = ByteUtil.toBytes(lsb);
|
final byte[] lsbBytes = ByteUtil.toBytes(lsb);
|
||||||
return ByteUtil.concat(msbBytes, lsbBytes);
|
return ByteUtil.concat(msbBytes, lsbBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,10 +117,12 @@ public class UlidUtil {
|
||||||
* @return a UUID
|
* @return a UUID
|
||||||
*/
|
*/
|
||||||
public static UUID fromBytesToUuid(byte[] bytes) {
|
public static UUID fromBytesToUuid(byte[] bytes) {
|
||||||
byte[] msbBytes = ByteUtil.copy(bytes, 0, 8);
|
byte[] msbBytes = new byte[8];
|
||||||
byte[] lsbBytes = ByteUtil.copy(bytes, 8, 16);
|
System.arraycopy(bytes, 0, msbBytes, 0, 8);
|
||||||
long msb = ByteUtil.toNumber(msbBytes);
|
byte[] lsbBytes = new byte[8];
|
||||||
long lsb = ByteUtil.toNumber(lsbBytes);
|
System.arraycopy(bytes, 8, lsbBytes, 0, 8);
|
||||||
|
final long msb = ByteUtil.toNumber(msbBytes);
|
||||||
|
final long lsb = ByteUtil.toNumber(lsbBytes);
|
||||||
return new UUID(msb, lsb);
|
return new UUID(msb, lsb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,12 +137,12 @@ public class UlidUtil {
|
||||||
|
|
||||||
byte[] timeBytes = new byte[6];
|
byte[] timeBytes = new byte[6];
|
||||||
System.arraycopy(bytes, 0, timeBytes, 0, 6);
|
System.arraycopy(bytes, 0, timeBytes, 0, 6);
|
||||||
long timeNumber = ByteUtil.toNumber(timeBytes);
|
final long timeNumber = ByteUtil.toNumber(timeBytes);
|
||||||
String timestampComponent = leftPad(Base32Util.toBase32Crockford(timeNumber));
|
final String timestampComponent = leftPad(Base32Util.toBase32Crockford(timeNumber));
|
||||||
|
|
||||||
byte[] randBytes = new byte[10];
|
byte[] randBytes = new byte[10];
|
||||||
System.arraycopy(bytes, 6, randBytes, 0, 10);
|
System.arraycopy(bytes, 6, randBytes, 0, 10);
|
||||||
String randomnessComponent = Base32Util.toBase32Crockford(randBytes);
|
final String randomnessComponent = Base32Util.toBase32Crockford(randBytes);
|
||||||
|
|
||||||
return timestampComponent + randomnessComponent;
|
return timestampComponent + randomnessComponent;
|
||||||
}
|
}
|
||||||
|
@ -122,16 +154,16 @@ public class UlidUtil {
|
||||||
* a ULID string
|
* a ULID string
|
||||||
* @return an array of bytes
|
* @return an array of bytes
|
||||||
*/
|
*/
|
||||||
public static byte[] fromUlidToBytes(String ulid) {
|
public static byte[] fromUlidToBytes(final String ulid) {
|
||||||
UlidUtil.validate(ulid);
|
UlidUtil.validate(ulid);
|
||||||
byte[] bytes = new byte[16];
|
byte[] bytes = new byte[16];
|
||||||
|
|
||||||
String timestampComponent = ulid.substring(0, 10);
|
final String timestampComponent = ulid.substring(0, 10);
|
||||||
long timeNumber = Base32Util.fromBase32CrockfordAsLong(timestampComponent);
|
final long timeNumber = Base32Util.fromBase32CrockfordAsLong(timestampComponent);
|
||||||
byte[] timeBytes = ByteUtil.toBytes(timeNumber);
|
byte[] timeBytes = ByteUtil.toBytes(timeNumber);
|
||||||
System.arraycopy(timeBytes, 2, bytes, 0, 6);
|
System.arraycopy(timeBytes, 2, bytes, 0, 6);
|
||||||
|
|
||||||
String randomnessComponent = ulid.substring(10, 26);
|
final String randomnessComponent = ulid.substring(10, 26);
|
||||||
byte[] randBytes = Base32Util.fromBase32Crockford(randomnessComponent);
|
byte[] randBytes = Base32Util.fromBase32Crockford(randomnessComponent);
|
||||||
System.arraycopy(randBytes, 0, bytes, 6, 10);
|
System.arraycopy(randBytes, 0, bytes, 6, 10);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
package com.github.f4b6a3;
|
||||||
|
|
||||||
|
// Add theese dependencies to pom.xml:
|
||||||
|
//
|
||||||
|
// <dependency>
|
||||||
|
// <groupId>org.openjdk.jmh</groupId>
|
||||||
|
// <artifactId>jmh-core</artifactId>
|
||||||
|
// <version>1.23</version>
|
||||||
|
// </dependency>
|
||||||
|
// <dependency>
|
||||||
|
// <groupId>org.openjdk.jmh</groupId>
|
||||||
|
// <artifactId>jmh-generator-annprocess</artifactId>
|
||||||
|
// <version>1.23</version>
|
||||||
|
// </dependency>
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import org.openjdk.jmh.annotations.Benchmark;
|
||||||
|
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||||
|
import org.openjdk.jmh.annotations.Measurement;
|
||||||
|
import org.openjdk.jmh.annotations.Mode;
|
||||||
|
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||||
|
import org.openjdk.jmh.annotations.Scope;
|
||||||
|
import org.openjdk.jmh.annotations.State;
|
||||||
|
import org.openjdk.jmh.annotations.Threads;
|
||||||
|
import org.openjdk.jmh.annotations.Warmup;
|
||||||
|
import org.openjdk.jmh.runner.Runner;
|
||||||
|
import org.openjdk.jmh.runner.RunnerException;
|
||||||
|
import org.openjdk.jmh.runner.options.Options;
|
||||||
|
import org.openjdk.jmh.runner.options.OptionsBuilder;
|
||||||
|
|
||||||
|
import com.github.f4b6a3.ulid.UlidCreator;
|
||||||
|
|
||||||
|
@Threads(1)
|
||||||
|
@State(Scope.Thread)
|
||||||
|
@Warmup(iterations = 5)
|
||||||
|
@Measurement(iterations = 5)
|
||||||
|
public class Benchmarks {
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
@BenchmarkMode(Mode.Throughput)
|
||||||
|
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
||||||
|
public String getUlidThroughput() {
|
||||||
|
return UlidCreator.getUlid();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
@BenchmarkMode(Mode.AverageTime)
|
||||||
|
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||||
|
public String getUlidAverage() {
|
||||||
|
return UlidCreator.getUlid();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
@BenchmarkMode(Mode.Throughput)
|
||||||
|
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
||||||
|
public UUID getGuidThroughput() {
|
||||||
|
return UlidCreator.getGuid();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
@BenchmarkMode(Mode.AverageTime)
|
||||||
|
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||||
|
public UUID getGuidAverage() {
|
||||||
|
return UlidCreator.getGuid();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
@BenchmarkMode(Mode.Throughput)
|
||||||
|
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
||||||
|
public UUID getRandomUUIDThroughput() {
|
||||||
|
return UUID.randomUUID();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
@BenchmarkMode(Mode.AverageTime)
|
||||||
|
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||||
|
public UUID getRandomUUIDAverage() {
|
||||||
|
return UUID.randomUUID();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws RunnerException {
|
||||||
|
Options opt = new OptionsBuilder().include(MyBenchmark.class.getSimpleName()).forks(1).build();
|
||||||
|
new Runner(opt).run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
|
@ -7,7 +7,7 @@ public class DemoTest {
|
||||||
private static final String HORIZONTAL_LINE = "----------------------------------------";
|
private static final String HORIZONTAL_LINE = "----------------------------------------";
|
||||||
|
|
||||||
public static void printList() {
|
public static void printList() {
|
||||||
int max = 1_000;
|
int max = 100;
|
||||||
|
|
||||||
System.out.println(HORIZONTAL_LINE);
|
System.out.println(HORIZONTAL_LINE);
|
||||||
System.out.println("### ULID");
|
System.out.println("### ULID");
|
||||||
|
|
|
@ -182,8 +182,8 @@ public class UlidUtilTest {
|
||||||
|
|
||||||
for (int i = 0; i < DEFAULT_LOOP_MAX; i++) {
|
for (int i = 0; i < DEFAULT_LOOP_MAX; i++) {
|
||||||
|
|
||||||
UUID uuid = UlidCreator.getFastGuid();
|
UUID uuid1 = UlidCreator.getGuid();
|
||||||
String ulid = UlidUtil.fromUuidToUlid(uuid);
|
String ulid = UlidUtil.fromUuidToUlid(uuid1);
|
||||||
|
|
||||||
assertTrue("ULID is null", ulid != null);
|
assertTrue("ULID is null", ulid != null);
|
||||||
assertTrue("ULID is empty", !ulid.isEmpty());
|
assertTrue("ULID is empty", !ulid.isEmpty());
|
||||||
|
@ -191,12 +191,57 @@ public class UlidUtilTest {
|
||||||
assertTrue("ULID is not valid", UlidUtil.isValid(ulid, /* strict */
|
assertTrue("ULID is not valid", UlidUtil.isValid(ulid, /* strict */
|
||||||
true));
|
true));
|
||||||
|
|
||||||
UUID result = UlidUtil.fromUlidToUuid(ulid);
|
UUID uuid2 = UlidUtil.fromUlidToUuid(ulid);
|
||||||
assertEquals("Result ULID is different from original ULID", uuid, result);
|
assertEquals("Result ULID is different from original ULID", uuid1, uuid2);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testToAndFromBytes() {
|
||||||
|
for (int i = 0; i < DEFAULT_LOOP_MAX; i++) {
|
||||||
|
String ulid1 = UlidCreator.getUlid();
|
||||||
|
byte[] bytes = UlidUtil.fromUlidToBytes(ulid1);
|
||||||
|
String ulid2 = UlidUtil.fromBytesToUlid(bytes);
|
||||||
|
|
||||||
|
// Check ULID 1
|
||||||
|
assertTrue(ulid1 != null);
|
||||||
|
assertTrue(!ulid1.isEmpty());
|
||||||
|
assertTrue(ulid1.length() == ULID_LENGTH);
|
||||||
|
assertTrue(UlidUtil.isValid(ulid1, /* strict */ true));
|
||||||
|
|
||||||
|
// Check ULID 2
|
||||||
|
assertTrue(ulid2 != null);
|
||||||
|
assertTrue(!ulid2.isEmpty());
|
||||||
|
assertTrue(ulid2.length() == ULID_LENGTH);
|
||||||
|
assertTrue(UlidUtil.isValid(ulid2, /* strict */ true));
|
||||||
|
|
||||||
|
assertEquals(ulid1, ulid2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFromUuidToBytes() {
|
||||||
|
for (int i = 0; i < DEFAULT_LOOP_MAX; i++) {
|
||||||
|
UUID uuid1 = UlidCreator.getGuid();
|
||||||
|
byte[] bytes = UlidUtil.fromUuidToBytes(uuid1);
|
||||||
|
long msb = ByteUtil.toNumber(ByteUtil.copy(bytes, 0, 8));
|
||||||
|
long lsb = ByteUtil.toNumber(ByteUtil.copy(bytes, 8, 16));
|
||||||
|
UUID uuid2 = new UUID(msb, lsb);
|
||||||
|
assertEquals(uuid1, uuid2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFromBytesToUuid() {
|
||||||
|
for (int i = 0; i < DEFAULT_LOOP_MAX; i++) {
|
||||||
|
UUID uuid1 = UlidCreator.getGuid();
|
||||||
|
byte[] bytes = UlidUtil.fromUuidToBytes(uuid1);
|
||||||
|
UUID uuid2 = UlidUtil.fromBytesToUuid(bytes);
|
||||||
|
assertEquals(uuid1, uuid2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private String leftPad(String unpadded) {
|
private String leftPad(String unpadded) {
|
||||||
return "0000000000".substring(unpadded.length()) + unpadded;
|
return "0000000000".substring(unpadded.length()) + unpadded;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue