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();
|
||||
```
|
||||
|
||||
Create a fast ULID:
|
||||
|
||||
```java
|
||||
String ulid = UlidCreator.getFastUlid();
|
||||
```
|
||||
|
||||
Create a ULID as GUID object:
|
||||
|
||||
```java
|
||||
UUID ulid = UlidCreator.getGuid();
|
||||
```
|
||||
|
||||
Create a fast ULID as GUID object:
|
||||
|
||||
```java
|
||||
UUID ulid = UlidCreator.getFastGuid();
|
||||
```
|
||||
|
||||
Create a ULID as byte sequence:
|
||||
|
||||
```java
|
||||
byte[] ulid = UlidCreator.getBytes();
|
||||
```
|
||||
|
||||
Create a fast ULID as byte sequence:
|
||||
|
||||
```java
|
||||
byte[] ulid = UlidCreator.getFastBytes();
|
||||
```
|
||||
|
||||
### Maven dependency
|
||||
|
||||
Add these lines to your `pom.xml`.
|
||||
|
@ -51,7 +33,7 @@ Add these lines to your `pom.xml`.
|
|||
<dependency>
|
||||
<groupId>com.github.f4b6a3</groupId>
|
||||
<artifactId>ulid-creator</artifactId>
|
||||
<version>1.0.1</version>
|
||||
<version>1.0.2</version>
|
||||
</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).
|
||||
|
@ -139,17 +121,19 @@ These are some examples of using the `GuidCreator` to create ULIDs:
|
|||
|
||||
```java
|
||||
|
||||
// with the default random generator (java.security.SecureRandom)
|
||||
String ulid = UlidCreator.getGuidCreator().createUlid();
|
||||
|
||||
// with java random generator (java.util.Random)
|
||||
// with fixed timestamp strategy (for test cases)
|
||||
String ulid = UlidCreator.getGuidCreator()
|
||||
.withRandomGenerator(new Random())
|
||||
.createUlid();
|
||||
.withTimestampStrategy(new FixedTimestampStretegy())
|
||||
.createUlid();
|
||||
|
||||
// with fast random generator (Xorshift128Plus)
|
||||
// with your custom timestamp strategy
|
||||
String ulid = UlidCreator.getGuidCreator()
|
||||
.withFastRandomGenerator()
|
||||
.withTimestampStrategy(new MyCustomTimestampStrategy())
|
||||
.createUlid();
|
||||
|
||||
// with your custom random number generator
|
||||
String ulid = UlidCreator.getGuidCreator()
|
||||
.withRandomGenerator(new MyCustomRandom())
|
||||
.createUlid();
|
||||
|
||||
// with fast random generator (Xorshift128Plus with salt)
|
||||
|
@ -158,5 +142,11 @@ Random random = new Xorshift128PlusRandom(salt);
|
|||
String ulid = UlidCreator.getGuidCreator()
|
||||
.withRandomGenerator(random)
|
||||
.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
|
||||
*/
|
||||
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
|
||||
* @return a UUID if valid
|
||||
*/
|
||||
public static UUID fromUlidToUuid(String ulid) {
|
||||
byte[] bytes = fromUlidToBytes(ulid);
|
||||
return fromBytesToUuid(bytes);
|
||||
public static UUID fromUlidToUuid(final String ulid) {
|
||||
|
||||
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
|
||||
* @return an array of bytes
|
||||
*/
|
||||
public static byte[] fromUuidToBytes(UUID uuid) {
|
||||
long msb = uuid.getMostSignificantBits();
|
||||
long lsb = uuid.getLeastSignificantBits();
|
||||
byte[] msbBytes = ByteUtil.toBytes(msb);
|
||||
byte[] lsbBytes = ByteUtil.toBytes(lsb);
|
||||
public static byte[] fromUuidToBytes(final UUID uuid) {
|
||||
final long msb = uuid.getMostSignificantBits();
|
||||
final long lsb = uuid.getLeastSignificantBits();
|
||||
final byte[] msbBytes = ByteUtil.toBytes(msb);
|
||||
final byte[] lsbBytes = ByteUtil.toBytes(lsb);
|
||||
return ByteUtil.concat(msbBytes, lsbBytes);
|
||||
}
|
||||
|
||||
|
@ -87,10 +117,12 @@ public class UlidUtil {
|
|||
* @return a UUID
|
||||
*/
|
||||
public static UUID fromBytesToUuid(byte[] bytes) {
|
||||
byte[] msbBytes = ByteUtil.copy(bytes, 0, 8);
|
||||
byte[] lsbBytes = ByteUtil.copy(bytes, 8, 16);
|
||||
long msb = ByteUtil.toNumber(msbBytes);
|
||||
long lsb = ByteUtil.toNumber(lsbBytes);
|
||||
byte[] msbBytes = new byte[8];
|
||||
System.arraycopy(bytes, 0, msbBytes, 0, 8);
|
||||
byte[] lsbBytes = new byte[8];
|
||||
System.arraycopy(bytes, 8, lsbBytes, 0, 8);
|
||||
final long msb = ByteUtil.toNumber(msbBytes);
|
||||
final long lsb = ByteUtil.toNumber(lsbBytes);
|
||||
return new UUID(msb, lsb);
|
||||
}
|
||||
|
||||
|
@ -105,12 +137,12 @@ public class UlidUtil {
|
|||
|
||||
byte[] timeBytes = new byte[6];
|
||||
System.arraycopy(bytes, 0, timeBytes, 0, 6);
|
||||
long timeNumber = ByteUtil.toNumber(timeBytes);
|
||||
String timestampComponent = leftPad(Base32Util.toBase32Crockford(timeNumber));
|
||||
final long timeNumber = ByteUtil.toNumber(timeBytes);
|
||||
final String timestampComponent = leftPad(Base32Util.toBase32Crockford(timeNumber));
|
||||
|
||||
byte[] randBytes = new byte[10];
|
||||
System.arraycopy(bytes, 6, randBytes, 0, 10);
|
||||
String randomnessComponent = Base32Util.toBase32Crockford(randBytes);
|
||||
final String randomnessComponent = Base32Util.toBase32Crockford(randBytes);
|
||||
|
||||
return timestampComponent + randomnessComponent;
|
||||
}
|
||||
|
@ -122,16 +154,16 @@ public class UlidUtil {
|
|||
* a ULID string
|
||||
* @return an array of bytes
|
||||
*/
|
||||
public static byte[] fromUlidToBytes(String ulid) {
|
||||
public static byte[] fromUlidToBytes(final String ulid) {
|
||||
UlidUtil.validate(ulid);
|
||||
byte[] bytes = new byte[16];
|
||||
|
||||
String timestampComponent = ulid.substring(0, 10);
|
||||
long timeNumber = Base32Util.fromBase32CrockfordAsLong(timestampComponent);
|
||||
final String timestampComponent = ulid.substring(0, 10);
|
||||
final long timeNumber = Base32Util.fromBase32CrockfordAsLong(timestampComponent);
|
||||
byte[] timeBytes = ByteUtil.toBytes(timeNumber);
|
||||
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);
|
||||
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 = "----------------------------------------";
|
||||
|
||||
public static void printList() {
|
||||
int max = 1_000;
|
||||
int max = 100;
|
||||
|
||||
System.out.println(HORIZONTAL_LINE);
|
||||
System.out.println("### ULID");
|
||||
|
|
|
@ -182,8 +182,8 @@ public class UlidUtilTest {
|
|||
|
||||
for (int i = 0; i < DEFAULT_LOOP_MAX; i++) {
|
||||
|
||||
UUID uuid = UlidCreator.getFastGuid();
|
||||
String ulid = UlidUtil.fromUuidToUlid(uuid);
|
||||
UUID uuid1 = UlidCreator.getGuid();
|
||||
String ulid = UlidUtil.fromUuidToUlid(uuid1);
|
||||
|
||||
assertTrue("ULID is null", ulid != null);
|
||||
assertTrue("ULID is empty", !ulid.isEmpty());
|
||||
|
@ -191,12 +191,57 @@ public class UlidUtilTest {
|
|||
assertTrue("ULID is not valid", UlidUtil.isValid(ulid, /* strict */
|
||||
true));
|
||||
|
||||
UUID result = UlidUtil.fromUlidToUuid(ulid);
|
||||
assertEquals("Result ULID is different from original ULID", uuid, result);
|
||||
UUID uuid2 = UlidUtil.fromUlidToUuid(ulid);
|
||||
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) {
|
||||
return "0000000000".substring(unpadded.length()) + unpadded;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue