Development of version 3.0.0 #7
Continuing... List of changes: Improved Ulid Improved UlidCrator Improved UlidSpecCreator Improved DefaultUlidSpecCreator Improved MonotonicUlidSpecCreator Removed TimestampStrategy Removed DefaultTimestampStrategy Removed FixedTimestampStrategy Updated testa cases
This commit is contained in:
		
							parent
							
								
									2ffa7a95dd
								
							
						
					
					
						commit
						ef2842bfe8
					
				| 
						 | 
				
			
			@ -25,6 +25,7 @@
 | 
			
		|||
package com.github.f4b6a3.ulid;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
import com.github.f4b6a3.ulid.util.UlidValidator;
 | 
			
		||||
| 
						 | 
				
			
			@ -37,99 +38,134 @@ public final class Ulid implements Serializable, Comparable<Ulid> {
 | 
			
		|||
	private final long msb;
 | 
			
		||||
	private final long lsb;
 | 
			
		||||
 | 
			
		||||
	protected static final int STRING_LENGTH = 26;
 | 
			
		||||
	protected static final long TIME_MAX = 281474976710655L; // 2^48 - 1
 | 
			
		||||
 | 
			
		||||
	protected static final char[] BASE32_CHARS = //
 | 
			
		||||
	public static final int ULID_LENGTH = 26;
 | 
			
		||||
	public static final int TIME_LENGTH = 10;
 | 
			
		||||
	public static final int RANDOM_LENGTH = 16;
 | 
			
		||||
 | 
			
		||||
	public static final int ULID_BYTES_LENGTH = 16;
 | 
			
		||||
	public static final int TIME_BYTES_LENGTH = 6;
 | 
			
		||||
	public static final int RANDOM_BYTES_LENGTH = 10;
 | 
			
		||||
 | 
			
		||||
	protected static final char[] ENCODING_CHARS = //
 | 
			
		||||
			{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', //
 | 
			
		||||
					'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', //
 | 
			
		||||
					'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', 'X', 'Y', 'Z' };
 | 
			
		||||
 | 
			
		||||
	protected static final long[] BASE32_VALUES = new long[128];
 | 
			
		||||
	protected static final long[] ENCODING_VALUES = new long[128];
 | 
			
		||||
	static {
 | 
			
		||||
		for (int i = 0; i < BASE32_VALUES.length; i++) {
 | 
			
		||||
			BASE32_VALUES[i] = -1;
 | 
			
		||||
		for (int i = 0; i < ENCODING_VALUES.length; i++) {
 | 
			
		||||
			ENCODING_VALUES[i] = -1;
 | 
			
		||||
		}
 | 
			
		||||
		// Numbers
 | 
			
		||||
		BASE32_VALUES['0'] = 0x00;
 | 
			
		||||
		BASE32_VALUES['1'] = 0x01;
 | 
			
		||||
		BASE32_VALUES['2'] = 0x02;
 | 
			
		||||
		BASE32_VALUES['3'] = 0x03;
 | 
			
		||||
		BASE32_VALUES['4'] = 0x04;
 | 
			
		||||
		BASE32_VALUES['5'] = 0x05;
 | 
			
		||||
		BASE32_VALUES['6'] = 0x06;
 | 
			
		||||
		BASE32_VALUES['7'] = 0x07;
 | 
			
		||||
		BASE32_VALUES['8'] = 0x08;
 | 
			
		||||
		BASE32_VALUES['9'] = 0x09;
 | 
			
		||||
		ENCODING_VALUES['0'] = 0x00;
 | 
			
		||||
		ENCODING_VALUES['1'] = 0x01;
 | 
			
		||||
		ENCODING_VALUES['2'] = 0x02;
 | 
			
		||||
		ENCODING_VALUES['3'] = 0x03;
 | 
			
		||||
		ENCODING_VALUES['4'] = 0x04;
 | 
			
		||||
		ENCODING_VALUES['5'] = 0x05;
 | 
			
		||||
		ENCODING_VALUES['6'] = 0x06;
 | 
			
		||||
		ENCODING_VALUES['7'] = 0x07;
 | 
			
		||||
		ENCODING_VALUES['8'] = 0x08;
 | 
			
		||||
		ENCODING_VALUES['9'] = 0x09;
 | 
			
		||||
		// Lower case
 | 
			
		||||
		BASE32_VALUES['a'] = 0x0a;
 | 
			
		||||
		BASE32_VALUES['b'] = 0x0b;
 | 
			
		||||
		BASE32_VALUES['c'] = 0x0c;
 | 
			
		||||
		BASE32_VALUES['d'] = 0x0d;
 | 
			
		||||
		BASE32_VALUES['e'] = 0x0e;
 | 
			
		||||
		BASE32_VALUES['f'] = 0x0f;
 | 
			
		||||
		BASE32_VALUES['g'] = 0x10;
 | 
			
		||||
		BASE32_VALUES['h'] = 0x11;
 | 
			
		||||
		BASE32_VALUES['j'] = 0x12;
 | 
			
		||||
		BASE32_VALUES['k'] = 0x13;
 | 
			
		||||
		BASE32_VALUES['m'] = 0x14;
 | 
			
		||||
		BASE32_VALUES['n'] = 0x15;
 | 
			
		||||
		BASE32_VALUES['p'] = 0x16;
 | 
			
		||||
		BASE32_VALUES['q'] = 0x17;
 | 
			
		||||
		BASE32_VALUES['r'] = 0x18;
 | 
			
		||||
		BASE32_VALUES['s'] = 0x19;
 | 
			
		||||
		BASE32_VALUES['t'] = 0x1a;
 | 
			
		||||
		BASE32_VALUES['v'] = 0x1b;
 | 
			
		||||
		BASE32_VALUES['w'] = 0x1c;
 | 
			
		||||
		BASE32_VALUES['x'] = 0x1d;
 | 
			
		||||
		BASE32_VALUES['y'] = 0x1e;
 | 
			
		||||
		BASE32_VALUES['z'] = 0x1f;
 | 
			
		||||
		ENCODING_VALUES['a'] = 0x0a;
 | 
			
		||||
		ENCODING_VALUES['b'] = 0x0b;
 | 
			
		||||
		ENCODING_VALUES['c'] = 0x0c;
 | 
			
		||||
		ENCODING_VALUES['d'] = 0x0d;
 | 
			
		||||
		ENCODING_VALUES['e'] = 0x0e;
 | 
			
		||||
		ENCODING_VALUES['f'] = 0x0f;
 | 
			
		||||
		ENCODING_VALUES['g'] = 0x10;
 | 
			
		||||
		ENCODING_VALUES['h'] = 0x11;
 | 
			
		||||
		ENCODING_VALUES['j'] = 0x12;
 | 
			
		||||
		ENCODING_VALUES['k'] = 0x13;
 | 
			
		||||
		ENCODING_VALUES['m'] = 0x14;
 | 
			
		||||
		ENCODING_VALUES['n'] = 0x15;
 | 
			
		||||
		ENCODING_VALUES['p'] = 0x16;
 | 
			
		||||
		ENCODING_VALUES['q'] = 0x17;
 | 
			
		||||
		ENCODING_VALUES['r'] = 0x18;
 | 
			
		||||
		ENCODING_VALUES['s'] = 0x19;
 | 
			
		||||
		ENCODING_VALUES['t'] = 0x1a;
 | 
			
		||||
		ENCODING_VALUES['v'] = 0x1b;
 | 
			
		||||
		ENCODING_VALUES['w'] = 0x1c;
 | 
			
		||||
		ENCODING_VALUES['x'] = 0x1d;
 | 
			
		||||
		ENCODING_VALUES['y'] = 0x1e;
 | 
			
		||||
		ENCODING_VALUES['z'] = 0x1f;
 | 
			
		||||
		// Lower case OIL
 | 
			
		||||
		BASE32_VALUES['o'] = 0x00;
 | 
			
		||||
		BASE32_VALUES['i'] = 0x01;
 | 
			
		||||
		BASE32_VALUES['l'] = 0x01;
 | 
			
		||||
		ENCODING_VALUES['o'] = 0x00;
 | 
			
		||||
		ENCODING_VALUES['i'] = 0x01;
 | 
			
		||||
		ENCODING_VALUES['l'] = 0x01;
 | 
			
		||||
		// Upper case
 | 
			
		||||
		BASE32_VALUES['A'] = 0x0a;
 | 
			
		||||
		BASE32_VALUES['B'] = 0x0b;
 | 
			
		||||
		BASE32_VALUES['C'] = 0x0c;
 | 
			
		||||
		BASE32_VALUES['D'] = 0x0d;
 | 
			
		||||
		BASE32_VALUES['E'] = 0x0e;
 | 
			
		||||
		BASE32_VALUES['F'] = 0x0f;
 | 
			
		||||
		BASE32_VALUES['G'] = 0x10;
 | 
			
		||||
		BASE32_VALUES['H'] = 0x11;
 | 
			
		||||
		BASE32_VALUES['J'] = 0x12;
 | 
			
		||||
		BASE32_VALUES['K'] = 0x13;
 | 
			
		||||
		BASE32_VALUES['M'] = 0x14;
 | 
			
		||||
		BASE32_VALUES['N'] = 0x15;
 | 
			
		||||
		BASE32_VALUES['P'] = 0x16;
 | 
			
		||||
		BASE32_VALUES['Q'] = 0x17;
 | 
			
		||||
		BASE32_VALUES['R'] = 0x18;
 | 
			
		||||
		BASE32_VALUES['S'] = 0x19;
 | 
			
		||||
		BASE32_VALUES['T'] = 0x1a;
 | 
			
		||||
		BASE32_VALUES['V'] = 0x1b;
 | 
			
		||||
		BASE32_VALUES['W'] = 0x1c;
 | 
			
		||||
		BASE32_VALUES['X'] = 0x1d;
 | 
			
		||||
		BASE32_VALUES['Y'] = 0x1e;
 | 
			
		||||
		BASE32_VALUES['Z'] = 0x1f;
 | 
			
		||||
		ENCODING_VALUES['A'] = 0x0a;
 | 
			
		||||
		ENCODING_VALUES['B'] = 0x0b;
 | 
			
		||||
		ENCODING_VALUES['C'] = 0x0c;
 | 
			
		||||
		ENCODING_VALUES['D'] = 0x0d;
 | 
			
		||||
		ENCODING_VALUES['E'] = 0x0e;
 | 
			
		||||
		ENCODING_VALUES['F'] = 0x0f;
 | 
			
		||||
		ENCODING_VALUES['G'] = 0x10;
 | 
			
		||||
		ENCODING_VALUES['H'] = 0x11;
 | 
			
		||||
		ENCODING_VALUES['J'] = 0x12;
 | 
			
		||||
		ENCODING_VALUES['K'] = 0x13;
 | 
			
		||||
		ENCODING_VALUES['M'] = 0x14;
 | 
			
		||||
		ENCODING_VALUES['N'] = 0x15;
 | 
			
		||||
		ENCODING_VALUES['P'] = 0x16;
 | 
			
		||||
		ENCODING_VALUES['Q'] = 0x17;
 | 
			
		||||
		ENCODING_VALUES['R'] = 0x18;
 | 
			
		||||
		ENCODING_VALUES['S'] = 0x19;
 | 
			
		||||
		ENCODING_VALUES['T'] = 0x1a;
 | 
			
		||||
		ENCODING_VALUES['V'] = 0x1b;
 | 
			
		||||
		ENCODING_VALUES['W'] = 0x1c;
 | 
			
		||||
		ENCODING_VALUES['X'] = 0x1d;
 | 
			
		||||
		ENCODING_VALUES['Y'] = 0x1e;
 | 
			
		||||
		ENCODING_VALUES['Z'] = 0x1f;
 | 
			
		||||
		// Upper case OIL
 | 
			
		||||
		BASE32_VALUES['O'] = 0x00;
 | 
			
		||||
		BASE32_VALUES['I'] = 0x01;
 | 
			
		||||
		BASE32_VALUES['L'] = 0x01;
 | 
			
		||||
		ENCODING_VALUES['O'] = 0x00;
 | 
			
		||||
		ENCODING_VALUES['I'] = 0x01;
 | 
			
		||||
		ENCODING_VALUES['L'] = 0x01;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static final long serialVersionUID = 2625269413446854731L;
 | 
			
		||||
 | 
			
		||||
	private Ulid() {
 | 
			
		||||
		this.msb = 0;
 | 
			
		||||
		this.lsb = 0;
 | 
			
		||||
	public Ulid(long mostSignificantBits, long leastSignificantBits) {
 | 
			
		||||
		this.msb = mostSignificantBits;
 | 
			
		||||
		this.lsb = leastSignificantBits;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private Ulid(UUID ulid) {
 | 
			
		||||
		this.msb = ulid.getMostSignificantBits();
 | 
			
		||||
		this.lsb = ulid.getLeastSignificantBits();
 | 
			
		||||
	// TODO: test
 | 
			
		||||
	public static Ulid of(byte[] bytes) {
 | 
			
		||||
 | 
			
		||||
		if (bytes == null || bytes.length != ULID_BYTES_LENGTH) {
 | 
			
		||||
			throw new IllegalArgumentException("Invalid ULID bytes");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	private Ulid(String ulid) {
 | 
			
		||||
		long long0 = 0;
 | 
			
		||||
		long long1 = 0;
 | 
			
		||||
 | 
			
		||||
		long0 |= (bytes[0x0] & 0xffL) << 56;
 | 
			
		||||
		long0 |= (bytes[0x1] & 0xffL) << 48;
 | 
			
		||||
		long0 |= (bytes[0x2] & 0xffL) << 40;
 | 
			
		||||
		long0 |= (bytes[0x3] & 0xffL) << 32;
 | 
			
		||||
		long0 |= (bytes[0x4] & 0xffL) << 24;
 | 
			
		||||
		long0 |= (bytes[0x5] & 0xffL) << 16;
 | 
			
		||||
		long0 |= (bytes[0x6] & 0xffL) << 8;
 | 
			
		||||
		long0 |= (bytes[0x7] & 0xffL);
 | 
			
		||||
 | 
			
		||||
		long1 |= (bytes[0x8] & 0xffL) << 56;
 | 
			
		||||
		long1 |= (bytes[0x9] & 0xffL) << 48;
 | 
			
		||||
		long1 |= (bytes[0xa] & 0xffL) << 40;
 | 
			
		||||
		long1 |= (bytes[0xb] & 0xffL) << 32;
 | 
			
		||||
		long1 |= (bytes[0xc] & 0xffL) << 24;
 | 
			
		||||
		long1 |= (bytes[0xd] & 0xffL) << 16;
 | 
			
		||||
		long1 |= (bytes[0xe] & 0xffL) << 8;
 | 
			
		||||
		long1 |= (bytes[0xf] & 0xffL);
 | 
			
		||||
 | 
			
		||||
		return new Ulid(long0, long1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: optimize
 | 
			
		||||
	public static Ulid of(String ulid) {
 | 
			
		||||
 | 
			
		||||
		final char[] chars = ulid == null ? new char[0] : ulid.toCharArray();
 | 
			
		||||
		UlidValidator.validate(chars);
 | 
			
		||||
| 
						 | 
				
			
			@ -138,64 +174,109 @@ public final class Ulid implements Serializable, Comparable<Ulid> {
 | 
			
		|||
		long r1 = 0;
 | 
			
		||||
		long r2 = 0;
 | 
			
		||||
 | 
			
		||||
		tm |= BASE32_VALUES[chars[0x00]] << 45;
 | 
			
		||||
		tm |= BASE32_VALUES[chars[0x01]] << 40;
 | 
			
		||||
		tm |= BASE32_VALUES[chars[0x02]] << 35;
 | 
			
		||||
		tm |= BASE32_VALUES[chars[0x03]] << 30;
 | 
			
		||||
		tm |= BASE32_VALUES[chars[0x04]] << 25;
 | 
			
		||||
		tm |= BASE32_VALUES[chars[0x05]] << 20;
 | 
			
		||||
		tm |= BASE32_VALUES[chars[0x06]] << 15;
 | 
			
		||||
		tm |= BASE32_VALUES[chars[0x07]] << 10;
 | 
			
		||||
		tm |= BASE32_VALUES[chars[0x08]] << 5;
 | 
			
		||||
		tm |= BASE32_VALUES[chars[0x09]];
 | 
			
		||||
		tm |= ENCODING_VALUES[chars[0x00]] << 45;
 | 
			
		||||
		tm |= ENCODING_VALUES[chars[0x01]] << 40;
 | 
			
		||||
		tm |= ENCODING_VALUES[chars[0x02]] << 35;
 | 
			
		||||
		tm |= ENCODING_VALUES[chars[0x03]] << 30;
 | 
			
		||||
		tm |= ENCODING_VALUES[chars[0x04]] << 25;
 | 
			
		||||
		tm |= ENCODING_VALUES[chars[0x05]] << 20;
 | 
			
		||||
		tm |= ENCODING_VALUES[chars[0x06]] << 15;
 | 
			
		||||
		tm |= ENCODING_VALUES[chars[0x07]] << 10;
 | 
			
		||||
		tm |= ENCODING_VALUES[chars[0x08]] << 5;
 | 
			
		||||
		tm |= ENCODING_VALUES[chars[0x09]];
 | 
			
		||||
 | 
			
		||||
		r1 |= BASE32_VALUES[chars[0x0a]] << 35;
 | 
			
		||||
		r1 |= BASE32_VALUES[chars[0x0b]] << 30;
 | 
			
		||||
		r1 |= BASE32_VALUES[chars[0x0c]] << 25;
 | 
			
		||||
		r1 |= BASE32_VALUES[chars[0x0d]] << 20;
 | 
			
		||||
		r1 |= BASE32_VALUES[chars[0x0e]] << 15;
 | 
			
		||||
		r1 |= BASE32_VALUES[chars[0x0f]] << 10;
 | 
			
		||||
		r1 |= BASE32_VALUES[chars[0x10]] << 5;
 | 
			
		||||
		r1 |= BASE32_VALUES[chars[0x11]];
 | 
			
		||||
		r1 |= ENCODING_VALUES[chars[0x0a]] << 35;
 | 
			
		||||
		r1 |= ENCODING_VALUES[chars[0x0b]] << 30;
 | 
			
		||||
		r1 |= ENCODING_VALUES[chars[0x0c]] << 25;
 | 
			
		||||
		r1 |= ENCODING_VALUES[chars[0x0d]] << 20;
 | 
			
		||||
		r1 |= ENCODING_VALUES[chars[0x0e]] << 15;
 | 
			
		||||
		r1 |= ENCODING_VALUES[chars[0x0f]] << 10;
 | 
			
		||||
		r1 |= ENCODING_VALUES[chars[0x10]] << 5;
 | 
			
		||||
		r1 |= ENCODING_VALUES[chars[0x11]];
 | 
			
		||||
 | 
			
		||||
		r2 |= BASE32_VALUES[chars[0x12]] << 35;
 | 
			
		||||
		r2 |= BASE32_VALUES[chars[0x13]] << 30;
 | 
			
		||||
		r2 |= BASE32_VALUES[chars[0x14]] << 25;
 | 
			
		||||
		r2 |= BASE32_VALUES[chars[0x15]] << 20;
 | 
			
		||||
		r2 |= BASE32_VALUES[chars[0x16]] << 15;
 | 
			
		||||
		r2 |= BASE32_VALUES[chars[0x17]] << 10;
 | 
			
		||||
		r2 |= BASE32_VALUES[chars[0x18]] << 5;
 | 
			
		||||
		r2 |= BASE32_VALUES[chars[0x19]];
 | 
			
		||||
		r2 |= ENCODING_VALUES[chars[0x12]] << 35;
 | 
			
		||||
		r2 |= ENCODING_VALUES[chars[0x13]] << 30;
 | 
			
		||||
		r2 |= ENCODING_VALUES[chars[0x14]] << 25;
 | 
			
		||||
		r2 |= ENCODING_VALUES[chars[0x15]] << 20;
 | 
			
		||||
		r2 |= ENCODING_VALUES[chars[0x16]] << 15;
 | 
			
		||||
		r2 |= ENCODING_VALUES[chars[0x17]] << 10;
 | 
			
		||||
		r2 |= ENCODING_VALUES[chars[0x18]] << 5;
 | 
			
		||||
		r2 |= ENCODING_VALUES[chars[0x19]];
 | 
			
		||||
 | 
			
		||||
		this.msb = (tm << 16) | (r1 >>> 24);
 | 
			
		||||
		this.lsb = (r1 << 40) | (r2 & 0xffffffffffL);
 | 
			
		||||
	}
 | 
			
		||||
		final long msb = (tm << 16) | (r1 >>> 24);
 | 
			
		||||
		final long lsb = (r1 << 40) | (r2 & 0xffffffffffL);
 | 
			
		||||
 | 
			
		||||
	private Ulid(long msb, long lsb) {
 | 
			
		||||
		this.msb = msb;
 | 
			
		||||
		this.lsb = lsb;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static Ulid of(UUID ulid) {
 | 
			
		||||
		return new Ulid(ulid);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static Ulid of(String ulid) {
 | 
			
		||||
		return new Ulid(ulid);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static Ulid of(long msb, long lsb) {
 | 
			
		||||
		return new Ulid(msb, lsb);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public UUID toUuid() {
 | 
			
		||||
		return new UUID(this.msb, this.lsb);
 | 
			
		||||
	public static Ulid of(UUID uuid) {
 | 
			
		||||
		return new Ulid(uuid.getMostSignificantBits(), uuid.getLeastSignificantBits());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static Ulid of(long time, byte[] random) {
 | 
			
		||||
 | 
			
		||||
		if ((time & 0xffff000000000000L) != 0) {
 | 
			
		||||
			throw new IllegalArgumentException("Invalid time value");
 | 
			
		||||
		}
 | 
			
		||||
		if (random == null || random.length != RANDOM_BYTES_LENGTH) {
 | 
			
		||||
			throw new IllegalArgumentException("Invalid random bytes");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		long msb = 0;
 | 
			
		||||
		long lsb = 0;
 | 
			
		||||
 | 
			
		||||
		msb |= time << 16;
 | 
			
		||||
		msb |= (long) (random[0x0] & 0xff) << 8;
 | 
			
		||||
		msb |= (long) (random[0x1] & 0xff);
 | 
			
		||||
 | 
			
		||||
		lsb |= (long) (random[0x2] & 0xff) << 56;
 | 
			
		||||
		lsb |= (long) (random[0x3] & 0xff) << 48;
 | 
			
		||||
		lsb |= (long) (random[0x4] & 0xff) << 40;
 | 
			
		||||
		lsb |= (long) (random[0x5] & 0xff) << 32;
 | 
			
		||||
		lsb |= (long) (random[0x6] & 0xff) << 24;
 | 
			
		||||
		lsb |= (long) (random[0x7] & 0xff) << 16;
 | 
			
		||||
		lsb |= (long) (random[0x8] & 0xff) << 8;
 | 
			
		||||
		lsb |= (long) (random[0x9] & 0xff);
 | 
			
		||||
 | 
			
		||||
		return new Ulid(msb, lsb);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: test
 | 
			
		||||
	public byte[] toBytes() {
 | 
			
		||||
 | 
			
		||||
		final byte[] bytes = new byte[ULID_BYTES_LENGTH];
 | 
			
		||||
 | 
			
		||||
		bytes[0x0] = (byte) (msb >>> 56);
 | 
			
		||||
		bytes[0x1] = (byte) (msb >>> 48);
 | 
			
		||||
		bytes[0x2] = (byte) (msb >>> 40);
 | 
			
		||||
		bytes[0x3] = (byte) (msb >>> 32);
 | 
			
		||||
		bytes[0x4] = (byte) (msb >>> 24);
 | 
			
		||||
		bytes[0x5] = (byte) (msb >>> 16);
 | 
			
		||||
		bytes[0x6] = (byte) (msb >>> 8);
 | 
			
		||||
		bytes[0x7] = (byte) (msb);
 | 
			
		||||
 | 
			
		||||
		bytes[0x8] = (byte) (lsb >>> 56);
 | 
			
		||||
		bytes[0x9] = (byte) (lsb >>> 48);
 | 
			
		||||
		bytes[0xa] = (byte) (lsb >>> 40);
 | 
			
		||||
		bytes[0xb] = (byte) (lsb >>> 32);
 | 
			
		||||
		bytes[0xc] = (byte) (lsb >>> 24);
 | 
			
		||||
		bytes[0xd] = (byte) (lsb >>> 16);
 | 
			
		||||
		bytes[0xe] = (byte) (lsb >>> 8);
 | 
			
		||||
		bytes[0xf] = (byte) (lsb);
 | 
			
		||||
 | 
			
		||||
		return bytes;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: test
 | 
			
		||||
	public byte[] toBytes4() {
 | 
			
		||||
		return Ulid.of(this.toUuid4()).toBytes();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: optimize
 | 
			
		||||
	@Override
 | 
			
		||||
	public String toString() {
 | 
			
		||||
 | 
			
		||||
		final char[] chars = new char[STRING_LENGTH];
 | 
			
		||||
		final char[] chars = new char[ULID_LENGTH];
 | 
			
		||||
		long long0 = this.msb;
 | 
			
		||||
		long long1 = this.lsb;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -203,42 +284,70 @@ public final class Ulid implements Serializable, Comparable<Ulid> {
 | 
			
		|||
		long random1 = ((long0 & 0xffffL) << 24) | (long1 >>> 40);
 | 
			
		||||
		long random2 = (long1 & 0xffffffffffL);
 | 
			
		||||
 | 
			
		||||
		chars[0x00] = BASE32_CHARS[(int) (time >>> 45 & 0b11111)];
 | 
			
		||||
		chars[0x01] = BASE32_CHARS[(int) (time >>> 40 & 0b11111)];
 | 
			
		||||
		chars[0x02] = BASE32_CHARS[(int) (time >>> 35 & 0b11111)];
 | 
			
		||||
		chars[0x03] = BASE32_CHARS[(int) (time >>> 30 & 0b11111)];
 | 
			
		||||
		chars[0x04] = BASE32_CHARS[(int) (time >>> 25 & 0b11111)];
 | 
			
		||||
		chars[0x05] = BASE32_CHARS[(int) (time >>> 20 & 0b11111)];
 | 
			
		||||
		chars[0x06] = BASE32_CHARS[(int) (time >>> 15 & 0b11111)];
 | 
			
		||||
		chars[0x07] = BASE32_CHARS[(int) (time >>> 10 & 0b11111)];
 | 
			
		||||
		chars[0x08] = BASE32_CHARS[(int) (time >>> 5 & 0b11111)];
 | 
			
		||||
		chars[0x09] = BASE32_CHARS[(int) (time & 0b11111)];
 | 
			
		||||
		chars[0x00] = ENCODING_CHARS[(int) (time >>> 45 & 0b11111)];
 | 
			
		||||
		chars[0x01] = ENCODING_CHARS[(int) (time >>> 40 & 0b11111)];
 | 
			
		||||
		chars[0x02] = ENCODING_CHARS[(int) (time >>> 35 & 0b11111)];
 | 
			
		||||
		chars[0x03] = ENCODING_CHARS[(int) (time >>> 30 & 0b11111)];
 | 
			
		||||
		chars[0x04] = ENCODING_CHARS[(int) (time >>> 25 & 0b11111)];
 | 
			
		||||
		chars[0x05] = ENCODING_CHARS[(int) (time >>> 20 & 0b11111)];
 | 
			
		||||
		chars[0x06] = ENCODING_CHARS[(int) (time >>> 15 & 0b11111)];
 | 
			
		||||
		chars[0x07] = ENCODING_CHARS[(int) (time >>> 10 & 0b11111)];
 | 
			
		||||
		chars[0x08] = ENCODING_CHARS[(int) (time >>> 5 & 0b11111)];
 | 
			
		||||
		chars[0x09] = ENCODING_CHARS[(int) (time & 0b11111)];
 | 
			
		||||
 | 
			
		||||
		chars[0x0a] = BASE32_CHARS[(int) (random1 >>> 35 & 0b11111)];
 | 
			
		||||
		chars[0x0b] = BASE32_CHARS[(int) (random1 >>> 30 & 0b11111)];
 | 
			
		||||
		chars[0x0c] = BASE32_CHARS[(int) (random1 >>> 25 & 0b11111)];
 | 
			
		||||
		chars[0x0d] = BASE32_CHARS[(int) (random1 >>> 20 & 0b11111)];
 | 
			
		||||
		chars[0x0e] = BASE32_CHARS[(int) (random1 >>> 15 & 0b11111)];
 | 
			
		||||
		chars[0x0f] = BASE32_CHARS[(int) (random1 >>> 10 & 0b11111)];
 | 
			
		||||
		chars[0x10] = BASE32_CHARS[(int) (random1 >>> 5 & 0b11111)];
 | 
			
		||||
		chars[0x11] = BASE32_CHARS[(int) (random1 & 0b11111)];
 | 
			
		||||
		chars[0x0a] = ENCODING_CHARS[(int) (random1 >>> 35 & 0b11111)];
 | 
			
		||||
		chars[0x0b] = ENCODING_CHARS[(int) (random1 >>> 30 & 0b11111)];
 | 
			
		||||
		chars[0x0c] = ENCODING_CHARS[(int) (random1 >>> 25 & 0b11111)];
 | 
			
		||||
		chars[0x0d] = ENCODING_CHARS[(int) (random1 >>> 20 & 0b11111)];
 | 
			
		||||
		chars[0x0e] = ENCODING_CHARS[(int) (random1 >>> 15 & 0b11111)];
 | 
			
		||||
		chars[0x0f] = ENCODING_CHARS[(int) (random1 >>> 10 & 0b11111)];
 | 
			
		||||
		chars[0x10] = ENCODING_CHARS[(int) (random1 >>> 5 & 0b11111)];
 | 
			
		||||
		chars[0x11] = ENCODING_CHARS[(int) (random1 & 0b11111)];
 | 
			
		||||
 | 
			
		||||
		chars[0x12] = BASE32_CHARS[(int) (random2 >>> 35 & 0b11111)];
 | 
			
		||||
		chars[0x13] = BASE32_CHARS[(int) (random2 >>> 30 & 0b11111)];
 | 
			
		||||
		chars[0x14] = BASE32_CHARS[(int) (random2 >>> 25 & 0b11111)];
 | 
			
		||||
		chars[0x15] = BASE32_CHARS[(int) (random2 >>> 20 & 0b11111)];
 | 
			
		||||
		chars[0x16] = BASE32_CHARS[(int) (random2 >>> 15 & 0b11111)];
 | 
			
		||||
		chars[0x17] = BASE32_CHARS[(int) (random2 >>> 10 & 0b11111)];
 | 
			
		||||
		chars[0x18] = BASE32_CHARS[(int) (random2 >>> 5 & 0b11111)];
 | 
			
		||||
		chars[0x19] = BASE32_CHARS[(int) (random2 & 0b11111)];
 | 
			
		||||
		chars[0x12] = ENCODING_CHARS[(int) (random2 >>> 35 & 0b11111)];
 | 
			
		||||
		chars[0x13] = ENCODING_CHARS[(int) (random2 >>> 30 & 0b11111)];
 | 
			
		||||
		chars[0x14] = ENCODING_CHARS[(int) (random2 >>> 25 & 0b11111)];
 | 
			
		||||
		chars[0x15] = ENCODING_CHARS[(int) (random2 >>> 20 & 0b11111)];
 | 
			
		||||
		chars[0x16] = ENCODING_CHARS[(int) (random2 >>> 15 & 0b11111)];
 | 
			
		||||
		chars[0x17] = ENCODING_CHARS[(int) (random2 >>> 10 & 0b11111)];
 | 
			
		||||
		chars[0x18] = ENCODING_CHARS[(int) (random2 >>> 5 & 0b11111)];
 | 
			
		||||
		chars[0x19] = ENCODING_CHARS[(int) (random2 & 0b11111)];
 | 
			
		||||
 | 
			
		||||
		return new String(chars);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public long getTimestamp() {
 | 
			
		||||
	// TODO: test
 | 
			
		||||
	public String toString4() {
 | 
			
		||||
		return Ulid.of(this.toUuid4()).toString();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public UUID toUuid() {
 | 
			
		||||
		return new UUID(this.msb, this.lsb);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: test
 | 
			
		||||
	public UUID toUuid4() {
 | 
			
		||||
		final long msb4 = (this.msb & 0xffffffffffff0fffL) | 0x0000000000004000L; // apply version 4
 | 
			
		||||
		final long lsb4 = (this.lsb & 0x3fffffffffffffffL) | 0x8000000000000000L; // apply variant RFC-4122
 | 
			
		||||
		return new UUID(msb4, lsb4);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public long getTime() {
 | 
			
		||||
		return this.msb >>> 16;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public Instant getInstant() {
 | 
			
		||||
		return Instant.ofEpochMilli(this.getTime());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public long getMostSignificantBits() {
 | 
			
		||||
		return this.msb;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public long getLeastSignificantBits() {
 | 
			
		||||
		return this.lsb;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public int hashCode() {
 | 
			
		||||
		final int prime = 31;
 | 
			
		||||
| 
						 | 
				
			
			@ -266,19 +375,14 @@ public final class Ulid implements Serializable, Comparable<Ulid> {
 | 
			
		|||
 | 
			
		||||
	@Override
 | 
			
		||||
	public int compareTo(Ulid other) {
 | 
			
		||||
 | 
			
		||||
		if (this.msb < other.msb)
 | 
			
		||||
			return -1;
 | 
			
		||||
 | 
			
		||||
		if (this.msb > other.msb)
 | 
			
		||||
			return 1;
 | 
			
		||||
 | 
			
		||||
		if (this.lsb < other.lsb)
 | 
			
		||||
			return -1;
 | 
			
		||||
 | 
			
		||||
		if (this.lsb > other.lsb)
 | 
			
		||||
			return 1;
 | 
			
		||||
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,16 +37,16 @@ public final class UlidCreator {
 | 
			
		|||
		return DefaultCreatorHolder.INSTANCE.create();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static Ulid getUlid(Long timestamp) {
 | 
			
		||||
		return DefaultCreatorHolder.INSTANCE.create(timestamp);
 | 
			
		||||
	public static Ulid getUlid(final long time) {
 | 
			
		||||
		return DefaultCreatorHolder.INSTANCE.create(time);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static Ulid getMonotonicUlid() {
 | 
			
		||||
		return MonotonicCreatorHolder.INSTANCE.create();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static Ulid getMonotonicUlid(Long timestamp) {
 | 
			
		||||
		return MonotonicCreatorHolder.INSTANCE.create(timestamp);
 | 
			
		||||
	public static Ulid getMonotonicUlid(final long time) {
 | 
			
		||||
		return MonotonicCreatorHolder.INSTANCE.create(time);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static DefaultUlidSpecCreator getDefaultCreator() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,36 +30,20 @@ import com.github.f4b6a3.ulid.Ulid;
 | 
			
		|||
import com.github.f4b6a3.ulid.strategy.RandomStrategy;
 | 
			
		||||
import com.github.f4b6a3.ulid.strategy.random.DefaultRandomStrategy;
 | 
			
		||||
import com.github.f4b6a3.ulid.strategy.random.OtherRandomStrategy;
 | 
			
		||||
import com.github.f4b6a3.ulid.strategy.TimestampStrategy;
 | 
			
		||||
import com.github.f4b6a3.ulid.strategy.timestamp.DefaultTimestampStrategy;
 | 
			
		||||
 | 
			
		||||
public abstract class UlidSpecCreator {
 | 
			
		||||
 | 
			
		||||
	protected TimestampStrategy timestampStrategy;
 | 
			
		||||
	protected RandomStrategy randomStrategy;
 | 
			
		||||
 | 
			
		||||
	public UlidSpecCreator() {
 | 
			
		||||
		this.timestampStrategy = new DefaultTimestampStrategy();
 | 
			
		||||
		this.randomStrategy = new DefaultRandomStrategy();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public synchronized Ulid create() {
 | 
			
		||||
		return create(null);
 | 
			
		||||
		return create(System.currentTimeMillis());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public abstract Ulid create(Long timestamp);
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Used for changing the timestamp strategy.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param timestampStrategy a timestamp strategy
 | 
			
		||||
	 * @return {@link UlidSpecCreator}
 | 
			
		||||
	 */
 | 
			
		||||
	@SuppressWarnings("unchecked")
 | 
			
		||||
	public synchronized <T extends UlidSpecCreator> T withTimestampStrategy(TimestampStrategy timestampStrategy) {
 | 
			
		||||
		this.timestampStrategy = timestampStrategy;
 | 
			
		||||
		return (T) this;
 | 
			
		||||
	}
 | 
			
		||||
	public abstract Ulid create(final long time);
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Replaces the default random strategy with another.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,17 +30,14 @@ import com.github.f4b6a3.ulid.creator.UlidSpecCreator;
 | 
			
		|||
public final class DefaultUlidSpecCreator extends UlidSpecCreator {
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public synchronized Ulid create(final Long timestamp) {
 | 
			
		||||
 | 
			
		||||
		final long time = timestamp != null ? timestamp : this.timestampStrategy.getTimestamp();
 | 
			
		||||
 | 
			
		||||
		// Get random values
 | 
			
		||||
		final byte[] bytes = new byte[10];
 | 
			
		||||
		this.randomStrategy.nextBytes(bytes);
 | 
			
		||||
	public synchronized Ulid create(final long time) {
 | 
			
		||||
 | 
			
		||||
		long msb = 0;
 | 
			
		||||
		long lsb = 0;
 | 
			
		||||
 | 
			
		||||
		final byte[] bytes = new byte[10];
 | 
			
		||||
		this.randomStrategy.nextBytes(bytes);
 | 
			
		||||
 | 
			
		||||
		msb |= time << 16;
 | 
			
		||||
		msb |= (long) (bytes[0x0] & 0xff) << 8;
 | 
			
		||||
		msb |= (long) (bytes[0x1] & 0xff);
 | 
			
		||||
| 
						 | 
				
			
			@ -54,6 +51,6 @@ public final class DefaultUlidSpecCreator extends UlidSpecCreator {
 | 
			
		|||
		lsb |= (long) (bytes[0x8] & 0xff) << 8;
 | 
			
		||||
		lsb |= (long) (bytes[0x9] & 0xff);
 | 
			
		||||
 | 
			
		||||
		return Ulid.of(msb, lsb);
 | 
			
		||||
		return new Ulid(msb, lsb);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,41 +29,46 @@ import com.github.f4b6a3.ulid.creator.UlidSpecCreator;
 | 
			
		|||
 | 
			
		||||
public final class MonotonicUlidSpecCreator extends UlidSpecCreator {
 | 
			
		||||
 | 
			
		||||
	protected long msb = 0;
 | 
			
		||||
	protected long lsb = 0;
 | 
			
		||||
	private long msb = 0;
 | 
			
		||||
	private long lsb = 0;
 | 
			
		||||
 | 
			
		||||
	protected long previousTimestamp;
 | 
			
		||||
	private long lastTime;
 | 
			
		||||
 | 
			
		||||
	public synchronized Ulid create(final Long timestamp) {
 | 
			
		||||
	// 0xffffffffffffffffL + 1 = 0x0000000000000000L
 | 
			
		||||
	private static final long UNSIGNED_OVERFLOW = 0x0000000000000000L;
 | 
			
		||||
 | 
			
		||||
		final long time = timestamp != null ? timestamp : this.timestampStrategy.getTimestamp();
 | 
			
		||||
	@Override
 | 
			
		||||
	public synchronized Ulid create(final long time) {
 | 
			
		||||
 | 
			
		||||
		if (time == this.previousTimestamp) {
 | 
			
		||||
			this.lsb++;
 | 
			
		||||
		// TODO: test
 | 
			
		||||
		if (time == this.lastTime) {
 | 
			
		||||
			if (++this.lsb == UNSIGNED_OVERFLOW) {
 | 
			
		||||
				// Increment the random bits of the MSB
 | 
			
		||||
				this.msb = (this.msb & 0xffffffffffff0000L) | ((this.msb + 1) & 0x000000000000ffffL);
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			// Get random values
 | 
			
		||||
 | 
			
		||||
			this.msb = 0;
 | 
			
		||||
			this.lsb = 0;
 | 
			
		||||
 | 
			
		||||
			final byte[] bytes = new byte[10];
 | 
			
		||||
			this.randomStrategy.nextBytes(bytes);
 | 
			
		||||
 | 
			
		||||
			msb = 0;
 | 
			
		||||
			lsb = 0;
 | 
			
		||||
			this.msb |= time << 16;
 | 
			
		||||
			this.msb |= (long) (bytes[0x0] & 0xff) << 8;
 | 
			
		||||
			this.msb |= (long) (bytes[0x1] & 0xff);
 | 
			
		||||
 | 
			
		||||
			msb |= time << 16;
 | 
			
		||||
			msb |= (long) (bytes[0x0] & 0xff) << 8;
 | 
			
		||||
			msb |= (long) (bytes[0x1] & 0xff);
 | 
			
		||||
 | 
			
		||||
			lsb |= (long) (bytes[0x2] & 0xff) << 56;
 | 
			
		||||
			lsb |= (long) (bytes[0x3] & 0xff) << 48;
 | 
			
		||||
			lsb |= (long) (bytes[0x4] & 0xff) << 40;
 | 
			
		||||
			lsb |= (long) (bytes[0x5] & 0xff) << 32;
 | 
			
		||||
			lsb |= (long) (bytes[0x6] & 0xff) << 24;
 | 
			
		||||
			lsb |= (long) (bytes[0x7] & 0xff) << 16;
 | 
			
		||||
			lsb |= (long) (bytes[0x8] & 0xff) << 8;
 | 
			
		||||
			lsb |= (long) (bytes[0x9] & 0xff);
 | 
			
		||||
			this.lsb |= (long) (bytes[0x2] & 0xff) << 56;
 | 
			
		||||
			this.lsb |= (long) (bytes[0x3] & 0xff) << 48;
 | 
			
		||||
			this.lsb |= (long) (bytes[0x4] & 0xff) << 40;
 | 
			
		||||
			this.lsb |= (long) (bytes[0x5] & 0xff) << 32;
 | 
			
		||||
			this.lsb |= (long) (bytes[0x6] & 0xff) << 24;
 | 
			
		||||
			this.lsb |= (long) (bytes[0x7] & 0xff) << 16;
 | 
			
		||||
			this.lsb |= (long) (bytes[0x8] & 0xff) << 8;
 | 
			
		||||
			this.lsb |= (long) (bytes[0x9] & 0xff);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		this.previousTimestamp = time;
 | 
			
		||||
		return Ulid.of(msb, lsb);
 | 
			
		||||
		this.lastTime = time;
 | 
			
		||||
		return new Ulid(msb, lsb);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,30 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 * MIT License
 | 
			
		||||
 * 
 | 
			
		||||
 * Copyright (c) 2020 Fabio Lima
 | 
			
		||||
 * 
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 * 
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 * copies or substantial portions of the Software.
 | 
			
		||||
 * 
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package com.github.f4b6a3.ulid.strategy;
 | 
			
		||||
 | 
			
		||||
@FunctionalInterface
 | 
			
		||||
public interface TimestampStrategy {
 | 
			
		||||
	long getTimestamp();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,38 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 * MIT License
 | 
			
		||||
 * 
 | 
			
		||||
 * Copyright (c) 2020 Fabio Lima
 | 
			
		||||
 * 
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 * 
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 * copies or substantial portions of the Software.
 | 
			
		||||
 * 
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package com.github.f4b6a3.ulid.strategy.timestamp;
 | 
			
		||||
 | 
			
		||||
import com.github.f4b6a3.ulid.strategy.TimestampStrategy;
 | 
			
		||||
 | 
			
		||||
public final class DefaultTimestampStrategy implements TimestampStrategy {
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Returns the count of milliseconds since 1970-01-01 (Unix epoch).
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	public long getTimestamp() {
 | 
			
		||||
		return System.currentTimeMillis();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,41 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 * MIT License
 | 
			
		||||
 * 
 | 
			
		||||
 * Copyright (c) 2020 Fabio Lima
 | 
			
		||||
 * 
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 * 
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 * copies or substantial portions of the Software.
 | 
			
		||||
 * 
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package com.github.f4b6a3.ulid.strategy.timestamp;
 | 
			
		||||
 | 
			
		||||
import com.github.f4b6a3.ulid.strategy.TimestampStrategy;
 | 
			
		||||
 | 
			
		||||
public final class FixedTimestampStretegy implements TimestampStrategy {
 | 
			
		||||
 | 
			
		||||
	private long timestamp = 0;
 | 
			
		||||
 | 
			
		||||
	public FixedTimestampStretegy(long timestamp) {
 | 
			
		||||
		this.timestamp = timestamp;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public long getTimestamp() {
 | 
			
		||||
		return this.timestamp;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -3,7 +3,6 @@ package com.github.f4b6a3.ulid;
 | 
			
		|||
import java.util.HashSet;
 | 
			
		||||
import com.github.f4b6a3.ulid.UlidCreator;
 | 
			
		||||
import com.github.f4b6a3.ulid.creator.UlidSpecCreator;
 | 
			
		||||
import com.github.f4b6a3.ulid.strategy.timestamp.FixedTimestampStretegy;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 
 | 
			
		||||
| 
						 | 
				
			
			@ -26,6 +25,8 @@ public class UniquenessTest {
 | 
			
		|||
	// ULID Spec creator
 | 
			
		||||
	private UlidSpecCreator creator;
 | 
			
		||||
 | 
			
		||||
	private long time = System.currentTimeMillis(); // fixed timestamp
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Initialize the test.
 | 
			
		||||
	 * 
 | 
			
		||||
| 
						 | 
				
			
			@ -90,7 +91,7 @@ public class UniquenessTest {
 | 
			
		|||
			for (int i = 0; i < max; i++) {
 | 
			
		||||
 | 
			
		||||
				// Request a UUID
 | 
			
		||||
				Ulid ulid = creator.create();
 | 
			
		||||
				Ulid ulid = creator.create(time);
 | 
			
		||||
 | 
			
		||||
				if (verbose) {
 | 
			
		||||
					// Calculate and show progress
 | 
			
		||||
| 
						 | 
				
			
			@ -116,8 +117,7 @@ public class UniquenessTest {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	public static void execute(boolean verbose, int threadCount, int requestCount) {
 | 
			
		||||
		UlidSpecCreator creator = UlidCreator.getMonotonicCreator()
 | 
			
		||||
				.withTimestampStrategy(new FixedTimestampStretegy(System.currentTimeMillis()));
 | 
			
		||||
		UlidSpecCreator creator = UlidCreator.getMonotonicCreator();
 | 
			
		||||
 | 
			
		||||
		UniquenessTest test = new UniquenessTest(threadCount, requestCount, creator, verbose);
 | 
			
		||||
		test.start();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@ import static org.junit.Assert.*;
 | 
			
		|||
 | 
			
		||||
public class UlidSpecCreatorTest {
 | 
			
		||||
 | 
			
		||||
	private static final int DEFAULT_LOOP_MAX = 1_000_000;
 | 
			
		||||
	private static final int DEFAULT_LOOP_MAX = 100_000;
 | 
			
		||||
 | 
			
		||||
	protected static final String DUPLICATE_UUID_MSG = "A duplicate ULID was created.";
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -22,6 +22,8 @@ public class UlidSpecCreatorTest {
 | 
			
		|||
 | 
			
		||||
	private static final Random RANDOM = new Random();
 | 
			
		||||
 | 
			
		||||
	private static final long TIME_MASK = 0x0000ffffffffffffL;
 | 
			
		||||
 | 
			
		||||
	private static int availableProcessors() {
 | 
			
		||||
		int processors = Runtime.getRuntime().availableProcessors();
 | 
			
		||||
		if (processors < 4) {
 | 
			
		||||
| 
						 | 
				
			
			@ -31,20 +33,20 @@ public class UlidSpecCreatorTest {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void testGetUlidTimestamp() {
 | 
			
		||||
	public void testGetUlidTime() {
 | 
			
		||||
		for (int i = 0; i < 100; i++) {
 | 
			
		||||
			long timestamp = RANDOM.nextLong() & 0x0000ffffffffffffL;
 | 
			
		||||
			Ulid ulid = UlidCreator.getUlid(timestamp);
 | 
			
		||||
			assertEquals(timestamp, ulid.getTimestamp());
 | 
			
		||||
			long time = RANDOM.nextLong() & TIME_MASK;
 | 
			
		||||
			Ulid ulid = UlidCreator.getUlid(time);
 | 
			
		||||
			assertEquals(time, ulid.getTime());
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void testGetMonotonicUlidTimestamp() {
 | 
			
		||||
	public void testGetMonotonicUlidTime() {
 | 
			
		||||
		for (int i = 0; i < 100; i++) {
 | 
			
		||||
			long timestamp = RANDOM.nextLong() & 0x0000ffffffffffffL;
 | 
			
		||||
			Ulid ulid = UlidCreator.getMonotonicUlid(timestamp);
 | 
			
		||||
			assertEquals(timestamp, ulid.getTimestamp());
 | 
			
		||||
			long time = RANDOM.nextLong() & TIME_MASK;
 | 
			
		||||
			Ulid ulid = UlidCreator.getMonotonicUlid(time);
 | 
			
		||||
			assertEquals(time, ulid.getTime());
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -56,7 +56,7 @@ public class UlidCreatorDefaultStringTest {
 | 
			
		|||
		assertTrue("Start time was after end time", startTime <= endTime);
 | 
			
		||||
 | 
			
		||||
		for (String ulid : list) {
 | 
			
		||||
			long creationTime = Ulid.of(ulid).getTimestamp();
 | 
			
		||||
			long creationTime = Ulid.of(ulid).getTime();
 | 
			
		||||
			assertTrue("Creation time was before start time " + creationTime + " " + startTime,
 | 
			
		||||
					creationTime >= startTime);
 | 
			
		||||
			assertTrue("Creation time was after end time", creationTime <= endTime);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,7 +51,7 @@ public class UlidCreatorDefaultTest {
 | 
			
		|||
		assertTrue("Start time was after end time", startTime <= endTime);
 | 
			
		||||
 | 
			
		||||
		for (Ulid ulid : list) {
 | 
			
		||||
			long creationTime = ulid.getTimestamp();
 | 
			
		||||
			long creationTime = ulid.getTime();
 | 
			
		||||
			assertTrue("Creation time was before start time " + creationTime + " " + startTime,
 | 
			
		||||
					creationTime >= startTime);
 | 
			
		||||
			assertTrue("Creation time was after end time", creationTime <= endTime);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -58,7 +58,7 @@ public class UlidCreatorMonotonicStringTest {
 | 
			
		|||
		assertTrue("Start time was after end time", startTime <= endTime);
 | 
			
		||||
 | 
			
		||||
		for (String ulid : list) {
 | 
			
		||||
			long creationTime = Ulid.of(ulid).getTimestamp();
 | 
			
		||||
			long creationTime = Ulid.of(ulid).getTime();
 | 
			
		||||
			assertTrue("Creation time was before start time " + creationTime + " " + startTime,
 | 
			
		||||
					creationTime >= startTime);
 | 
			
		||||
			assertTrue("Creation time was after end time", creationTime <= endTime);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -53,7 +53,7 @@ public class UlidCreatorMonotonicTest {
 | 
			
		|||
		assertTrue("Start time was after end time", startTime <= endTime);
 | 
			
		||||
 | 
			
		||||
		for (Ulid ulid : list) {
 | 
			
		||||
			long creationTime = ulid.getTimestamp();
 | 
			
		||||
			long creationTime = ulid.getTime();
 | 
			
		||||
			assertTrue("Creation time was before start time " + creationTime + " " + startTime,
 | 
			
		||||
					creationTime >= startTime);
 | 
			
		||||
			assertTrue("Creation time was after end time", creationTime <= endTime);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -41,7 +41,7 @@ public class UlidTest {
 | 
			
		|||
			Random random = new Random();
 | 
			
		||||
			final long msb = random.nextLong();
 | 
			
		||||
			final long lsb = random.nextLong();
 | 
			
		||||
			Ulid ulid0 = Ulid.of(msb, lsb); // <-- under test
 | 
			
		||||
			Ulid ulid0 = new Ulid(msb, lsb); // <-- under test
 | 
			
		||||
 | 
			
		||||
			assertEquals(msb, ulid0.toUuid().getMostSignificantBits());
 | 
			
		||||
			assertEquals(lsb, ulid0.toUuid().getLeastSignificantBits());
 | 
			
		||||
| 
						 | 
				
			
			@ -54,7 +54,7 @@ public class UlidTest {
 | 
			
		|||
			Random random = new Random();
 | 
			
		||||
			final long random1 = random.nextLong();
 | 
			
		||||
			final long random2 = random.nextLong();
 | 
			
		||||
			Ulid ulid0 = Ulid.of(random1, random2);
 | 
			
		||||
			Ulid ulid0 = new Ulid(random1, random2);
 | 
			
		||||
 | 
			
		||||
			String string1 = toString(ulid0);
 | 
			
		||||
			Ulid struct1 = Ulid.of(string1); // <-- under test
 | 
			
		||||
| 
						 | 
				
			
			@ -83,7 +83,7 @@ public class UlidTest {
 | 
			
		|||
			Random random = new Random();
 | 
			
		||||
			final long random1 = random.nextLong();
 | 
			
		||||
			final long random2 = random.nextLong();
 | 
			
		||||
			Ulid ulid0 = Ulid.of(random1, random2);
 | 
			
		||||
			Ulid ulid0 = new Ulid(random1, random2);
 | 
			
		||||
 | 
			
		||||
			String string1 = toString(ulid0);
 | 
			
		||||
			String string2 = ulid0.toString(); // <-- under test
 | 
			
		||||
| 
						 | 
				
			
			@ -98,7 +98,7 @@ public class UlidTest {
 | 
			
		|||
			Random random = new Random();
 | 
			
		||||
			final long random1 = random.nextLong();
 | 
			
		||||
			final long random2 = random.nextLong();
 | 
			
		||||
			Ulid ulid0 = Ulid.of(random1, random2);
 | 
			
		||||
			Ulid ulid0 = new Ulid(random1, random2);
 | 
			
		||||
 | 
			
		||||
			UUID uuid1 = toUuid(ulid0);
 | 
			
		||||
			UUID uuid2 = ulid0.toUuid(); // <-- under test
 | 
			
		||||
| 
						 | 
				
			
			@ -127,7 +127,7 @@ public class UlidTest {
 | 
			
		|||
		long msb = (time << 16) | (random1 >>> 24);
 | 
			
		||||
		long lsb = (random1 << 40) | (random2 & 0xffffffffffL);
 | 
			
		||||
 | 
			
		||||
		return Ulid.of(msb, lsb);
 | 
			
		||||
		return new Ulid(msb, lsb);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static UUID toUuid(Ulid struct) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue