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 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()
 | 
			
		||||
    .withFastRandomGenerator()
 | 
			
		||||
    .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