Add a MIN and MAX constants and methods #26

This commit is contained in:
Fabio Lima 2023-04-25 23:30:07 -03:00
parent dc0082bad6
commit 41c15148d3
5 changed files with 116 additions and 16 deletions

View File

@ -4,7 +4,11 @@ All notable changes to this project will be documented in this file.
## [Unreleased] ## [Unreleased]
Nothing unreleased. Add a MIN and MAX constants and methods. #26
## [5.2.0] - 2023-??-??
To be released.
## [5.1.0] - 2022-10-22 ## [5.1.0] - 2022-10-22
@ -302,7 +306,8 @@ Project created as an alternative Java implementation of [ULID spec](https://git
- Added `LICENSE` - Added `LICENSE`
- Added test cases - Added test cases
[unreleased]: https://github.com/f4b6a3/ulid-creator/compare/ulid-creator-5.1.0...HEAD [unreleased]: https://github.com/f4b6a3/ulid-creator/compare/ulid-creator-5.2.0...HEAD
[5.2.0]: https://github.com/f4b6a3/ulid-creator/compare/ulid-creator-5.1.0...ulid-creator-5.2.0
[5.1.0]: https://github.com/f4b6a3/ulid-creator/compare/ulid-creator-5.0.2...ulid-creator-5.1.0 [5.1.0]: https://github.com/f4b6a3/ulid-creator/compare/ulid-creator-5.0.2...ulid-creator-5.1.0
[5.0.2]: https://github.com/f4b6a3/ulid-creator/compare/ulid-creator-5.0.1...ulid-creator-5.0.2 [5.0.2]: https://github.com/f4b6a3/ulid-creator/compare/ulid-creator-5.0.1...ulid-creator-5.0.2
[5.0.1]: https://github.com/f4b6a3/ulid-creator/compare/ulid-creator-5.0.0...ulid-creator-5.0.1 [5.0.1]: https://github.com/f4b6a3/ulid-creator/compare/ulid-creator-5.0.0...ulid-creator-5.0.1

View File

@ -66,4 +66,14 @@ public class Throughput {
public String UlidCreator_getMonotonicUlid_toString() { public String UlidCreator_getMonotonicUlid_toString() {
return UlidCreator.getMonotonicUlid().toString(); return UlidCreator.getMonotonicUlid().toString();
} }
@Benchmark
public Ulid UlidCreator_getHashUlid() {
return UlidCreator.getHashUlid(0L, "this is a test");
}
@Benchmark
public Ulid UlidCreator_getHashUlidString() {
return UlidCreator.getHashUlid(0L, "this is a test").toString();
}
} }

View File

@ -1,7 +1,7 @@
/* /*
* MIT License * MIT License
* *
* Copyright (c) 2020-2022 Fabio Lima * Copyright (c) 2020-2023 Fabio Lima
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -26,8 +26,8 @@ package com.github.f4b6a3.ulid;
import java.io.Serializable; import java.io.Serializable;
import java.time.Instant; import java.time.Instant;
import java.util.SplittableRandom;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
/** /**
* A class that represents ULIDs. * A class that represents ULIDs.
@ -79,6 +79,14 @@ public final class Ulid implements Serializable, Comparable<Ulid> {
* Number of bytes of the random component of a ULID. * Number of bytes of the random component of a ULID.
*/ */
public static final int RANDOM_BYTES = 10; public static final int RANDOM_BYTES = 10;
/**
* A special ULID that has all 128 bits set to ZERO.
*/
public static final Ulid MIN = new Ulid(0x0000000000000000L, 0x0000000000000000L);
/**
* A special ULID that has all 128 bits set to ONE.
*/
public static final Ulid MAX = new Ulid(0xffffffffffffffffL, 0xffffffffffffffffL);
private static final char[] ALPHABET_UPPERCASE = // private static final char[] ALPHABET_UPPERCASE = //
{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', // { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', //
@ -243,22 +251,64 @@ public final class Ulid implements Serializable, Comparable<Ulid> {
* <p> * <p>
* This static method is a quick alternative to {@link UlidCreator#getUlid()}. * This static method is a quick alternative to {@link UlidCreator#getUlid()}.
* <p> * <p>
* It employs {@link SplittableRandom} which works very well, although not * It employs {@link ThreadLocalRandom} which works very well, although not
* cryptographically strong. * cryptographically strong. It can be useful, for example, for logging.
* <p> * <p>
* Security-sensitive applications that require a cryptographically secure * Security-sensitive applications that require a cryptographically secure
* pseudo-random generator should use {@link UlidCreator#getUlid()}. * pseudo-random generator should use {@link UlidCreator#getUlid()}.
* *
* @return a ULID * @return a ULID
* @see {@link SplittableRandom} * @see {@link ThreadLocalRandom}
* @since 5.1.0 * @since 5.1.0
*/ */
public static Ulid fast() { public static Ulid fast() {
final long time = System.currentTimeMillis(); final long time = System.currentTimeMillis();
final SplittableRandom random = new SplittableRandom(); ThreadLocalRandom random = ThreadLocalRandom.current();
return new Ulid((time << 16) | (random.nextLong() & 0xffffL), random.nextLong()); return new Ulid((time << 16) | (random.nextLong() & 0xffffL), random.nextLong());
} }
/**
* Returns the minimum ULID for a given time.
* <p>
* The 48 bits of the time component are filled with the given time and the 80
* bits of the random component are all set to ZERO.
* <p>
* For example, the minimum ULID for 2022-02-22 22:22:22.222 is
* `{@code new Ulid(0x018781ebb25e0000L, 0x0000000000000000L)}`, where
* `{@code 0x018781ebb25e}` is the timestamp in hexadecimal.
* <p>
* It can be useful to find all records before or after a specific timestamp in
* a table without a `{@code created_at}` field.
*
* @param time the the number of milliseconds since 1970-01-01
* @return a ULID
* @since 5.2.0
*/
public static Ulid min(long time) {
return new Ulid((time << 16) | 0x0000L, 0x0000000000000000L);
}
/**
* Returns the maximum ULID for a given time.
* <p>
* The 48 bits of the time component are filled with the given time and the 80
* bits or the random component are all set to ONE.
* <p>
* For example, the maximum ULID for 2022-02-22 22:22:22.222 is
* `{@code new Ulid(0x018781ebb25effffL, 0xffffffffffffffffL)}`, where
* `{@code 0x018781ebb25e}` is the timestamp in hexadecimal.
* <p>
* It can be useful to find all records before or after a specific timestamp in
* a table without a `{@code created_at}` field.
*
* @param time the the number of milliseconds since 1970-01-01
* @return a ULID
* @since 5.2.0
*/
public static Ulid max(long time) {
return new Ulid((time << 16) | 0xffffL, 0xffffffffffffffffL);
}
/** /**
* Converts a UUID into a ULID. * Converts a UUID into a ULID.
* *

View File

@ -1,7 +1,7 @@
/* /*
* MIT License * MIT License
* *
* Copyright (c) 2020-2022 Fabio Lima * Copyright (c) 2020-2023 Fabio Lima
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View File

@ -3,11 +3,15 @@ package com.github.f4b6a3.ulid;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import java.math.BigInteger; import java.math.BigInteger;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.Instant; import java.time.Instant;
import java.util.Arrays; import java.util.Arrays;
import java.util.Random; import java.util.Random;
@ -278,12 +282,43 @@ public class UlidTest extends UlidFactoryTest {
} }
} }
@Test
public void testMinAndMax() {
long time = 0;
Random random = new Random();
byte[] bytes = new byte[Ulid.RANDOM_BYTES];
for (int i = 0; i < 100; i++) {
time = random.nextLong() & TIME_MASK;
{
// Test MIN
Ulid ulid = Ulid.min(time);
assertEquals(time, ulid.getTime());
for (int j = 0; j < bytes.length; j++) {
assertEquals(0, ulid.getRandom()[j]);
}
}
{
// Test MAX
Ulid ulid = Ulid.max(time);
assertEquals(time, ulid.getTime());
for (int j = 0; j < bytes.length; j++) {
assertEquals(-1, ulid.getRandom()[j]);
}
}
}
}
@Test @Test
public void testGetTimeAndGetRandom() { public void testGetTimeAndGetRandom() {
long time = 0; long time = 0;
byte[] bytes = new byte[Ulid.RANDOM_BYTES];
Random random = new Random(); Random random = new Random();
byte[] bytes = new byte[Ulid.RANDOM_BYTES];
for (int i = 0; i < 100; i++) { for (int i = 0; i < 100; i++) {
@ -292,18 +327,18 @@ public class UlidTest extends UlidFactoryTest {
// Instance methods // Instance methods
Ulid ulid = new Ulid(time, bytes); Ulid ulid = new Ulid(time, bytes);
assertEquals(time, ulid.getTime()); // test Ulid.getTime() assertEquals(time, ulid.getTime());
assertEquals(Instant.ofEpochMilli(time), ulid.getInstant()); // test Ulid.getInstant() assertEquals(Instant.ofEpochMilli(time), ulid.getInstant());
for (int j = 0; j < bytes.length; j++) { for (int j = 0; j < bytes.length; j++) {
assertEquals(bytes[j], ulid.getRandom()[j]); // test Ulid.getRandom() assertEquals(bytes[j], ulid.getRandom()[j]);
} }
// Static methods // Static methods
String string = new Ulid(time, bytes).toString(); String string = new Ulid(time, bytes).toString();
assertEquals(time, Ulid.getTime(string)); // test Ulid.getTime() assertEquals(time, Ulid.getTime(string));
assertEquals(Instant.ofEpochMilli(time), Ulid.getInstant(string)); // test Ulid.getInstant() assertEquals(Instant.ofEpochMilli(time), Ulid.getInstant(string));
for (int j = 0; j < bytes.length; j++) { for (int j = 0; j < bytes.length; j++) {
assertEquals(bytes[j], Ulid.getRandom(string)[j]); // test Ulid.getRandom() assertEquals(bytes[j], Ulid.getRandom(string)[j]);
} }
} }
} }