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]
Nothing unreleased.
Add a MIN and MAX constants and methods. #26
## [5.2.0] - 2023-??-??
To be released.
## [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 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.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

View File

@ -66,4 +66,14 @@ public class Throughput {
public String 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
*
* 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
* 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.time.Instant;
import java.util.SplittableRandom;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
/**
* 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.
*/
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 = //
{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', //
@ -243,22 +251,64 @@ public final class Ulid implements Serializable, Comparable<Ulid> {
* <p>
* This static method is a quick alternative to {@link UlidCreator#getUlid()}.
* <p>
* It employs {@link SplittableRandom} which works very well, although not
* cryptographically strong.
* It employs {@link ThreadLocalRandom} which works very well, although not
* cryptographically strong. It can be useful, for example, for logging.
* <p>
* Security-sensitive applications that require a cryptographically secure
* pseudo-random generator should use {@link UlidCreator#getUlid()}.
*
* @return a ULID
* @see {@link SplittableRandom}
* @see {@link ThreadLocalRandom}
* @since 5.1.0
*/
public static Ulid fast() {
final long time = System.currentTimeMillis();
final SplittableRandom random = new SplittableRandom();
ThreadLocalRandom random = ThreadLocalRandom.current();
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.
*

View File

@ -1,7 +1,7 @@
/*
* 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
* 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.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.util.Arrays;
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
public void testGetTimeAndGetRandom() {
long time = 0;
byte[] bytes = new byte[Ulid.RANDOM_BYTES];
Random random = new Random();
byte[] bytes = new byte[Ulid.RANDOM_BYTES];
for (int i = 0; i < 100; i++) {
@ -292,18 +327,18 @@ public class UlidTest extends UlidFactoryTest {
// Instance methods
Ulid ulid = new Ulid(time, bytes);
assertEquals(time, ulid.getTime()); // test Ulid.getTime()
assertEquals(Instant.ofEpochMilli(time), ulid.getInstant()); // test Ulid.getInstant()
assertEquals(time, ulid.getTime());
assertEquals(Instant.ofEpochMilli(time), ulid.getInstant());
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
String string = new Ulid(time, bytes).toString();
assertEquals(time, Ulid.getTime(string)); // test Ulid.getTime()
assertEquals(Instant.ofEpochMilli(time), Ulid.getInstant(string)); // test Ulid.getInstant()
assertEquals(time, Ulid.getTime(string));
assertEquals(Instant.ofEpochMilli(time), Ulid.getInstant(string));
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]);
}
}
}