diff --git a/README.md b/README.md
index 7f72ef0..ef7fa3c 100644
--- a/README.md
+++ b/README.md
@@ -31,10 +31,15 @@ To speed up process, you can ignore unit tests by using: `-DskipTests=true -Dmav
```
```java
-final CUID cuid = CUID.randomCUID();
+final CUID cuid = CUID.randomCUID1();
System.out.println("CUID: " + cuid);
```
+```java
+final CUID cuid = CUID.randomCUID2();
+System.out.println("CUID (Version 2): " + cuid);
+```
+
```java
final CUID cuid = CUID.fromString("cl9gts1kw00393647w1z4v2tc");
System.out.println("CUID: " + cuid);
diff --git a/src/main/java/io/github/thibaultmeyer/cuid/CUID.java b/src/main/java/io/github/thibaultmeyer/cuid/CUID.java
index 455fd32..a0901ee 100644
--- a/src/main/java/io/github/thibaultmeyer/cuid/CUID.java
+++ b/src/main/java/io/github/thibaultmeyer/cuid/CUID.java
@@ -1,6 +1,13 @@
package io.github.thibaultmeyer.cuid;
+import io.github.thibaultmeyer.cuid.exception.CUIDGenerationException;
+
+import java.io.Serializable;
import java.lang.management.ManagementFactory;
+import java.math.BigInteger;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Objects;
@@ -8,30 +15,24 @@
* Collision-resistant ID optimized for horizontal scaling and performance.
*
* @see CUID official website
+ * @since 1.0.0
*/
-public final class CUID implements java.io.Serializable, Comparable {
+public final class CUID implements Serializable, Comparable {
// Explicit serialVersionUID for interoperability.
private static final long serialVersionUID = -2441709761088574861L;
- // CUID configuration.
+ // Base to use
private static final int NUMBER_BASE = 36;
- private static final int BLOCK_SIZE = 4;
- private static final int CUID_VALUE_LENGTH = 25;
- private static final String START_CHARACTER = "c";
- private static final int RANDOM_BUFFER_SIZE = 4096;
-
- // Counter
- private static int counter = 0;
- private static int randomBufferIndex = RANDOM_BUFFER_SIZE;
// CUID value
private final String value;
/**
- * Build a new instance.
+ * Creates a new instance.
*
* @param value A valid CUID value
+ * @since 1.0.0
*/
private CUID(final String value) {
@@ -39,103 +40,100 @@ private CUID(final String value) {
}
/**
- * Generates a new random CUID.
+ * Generates a new random CUID (Version 2).
*
- * @return Newly generated CUID
+ * @return Newly generated CUID (Version 2)
+ * @since 2.0.0
*/
- public static CUID randomCUID() {
-
- final String timestamp = Long.toString(System.currentTimeMillis(), NUMBER_BASE);
- final String counter = padWithZero(Integer.toString(nextCounterValue(), NUMBER_BASE), BLOCK_SIZE);
- final String random = getRandomBlock() + getRandomBlock();
+ public static CUID randomCUID2() {
- return new CUID(START_CHARACTER + timestamp + counter + Holder.MACHINE_FINGERPRINT + random);
+ return randomCUID2(CUIDv2.LENGTH_STANDARD);
}
/**
- * Creates a {@code CUID} from the string standard representation.
+ * Generates a new random CUID (Version 2).
*
- * @param cuidAsString A string that specifies a {@code CUID}
- * @return A {@code CUID} with the specified value
- * @throws IllegalArgumentException If the string is not conform
+ * @param withBigLength {@code true} to generate a long CUID (Version 2), otherwise, {@code false}
+ * @return Newly generated CUID (Version 2)
+ * @since 2.0.0
*/
- public static CUID fromString(final String cuidAsString) {
-
- if (isValid(cuidAsString)) {
- return new CUID(cuidAsString);
- }
+ public static CUID randomCUID2(final boolean withBigLength) {
- throw new IllegalArgumentException("CUID string is invalid: '" + cuidAsString + "'");
+ return randomCUID2(withBigLength ? CUIDv2.LENGTH_BIG : CUIDv2.LENGTH_STANDARD);
}
/**
- * Retrieves the counter next value.
+ * Generates a new random CUID (Version 2).
*
- * @return The counter next value
+ * @param length requested CUID length
+ * @return Newly generated CUID (Version 2)
+ * @since 2.0.0
*/
- private static synchronized int nextCounterValue() {
+ private static CUID randomCUID2(final int length) {
- counter = counter < Holder.DISCRETE_VALUES ? counter : 0;
- return counter++;
- }
+ final String time = Long.toString(System.currentTimeMillis(), NUMBER_BASE);
+ final char firstLetter = CUIDv2.ALPHABET_ARRAY[Math.abs(Common.nextIntValue()) % CUIDv2.ALPHABET_ARRAY.length];
+ final String hash = CUIDv2.computeHash(
+ time + CUIDv2.createEntropy(length) + CUIDv2.nextCounterValue() + Common.MACHINE_FINGERPRINT,
+ length);
- /**
- * Generates a random block of data.
- *
- * @return Newly generated block of data
- */
- private static String getRandomBlock() {
-
- return padWithZero(Integer.toString(nextIntValue() * Holder.DISCRETE_VALUES, NUMBER_BASE), BLOCK_SIZE);
+ return new CUID(firstLetter + hash.substring(1, length));
}
/**
- * Retrieves next random integer value.
+ * Generates a new random CUID (Version 1).
*
- * @return A random integer
+ * @return Newly generated CUID (Version 1)
+ * @since 2.0.0
*/
- private static synchronized int nextIntValue() {
+ public static CUID randomCUID1() {
- if (randomBufferIndex == RANDOM_BUFFER_SIZE) {
- Holder.NUMBER_GENERATOR.nextBytes(Holder.RANDOM_BUFFER);
- randomBufferIndex = 0;
- }
+ final String timestamp = Long.toString(System.currentTimeMillis(), NUMBER_BASE);
+ final String counter = Common.padWithZero(Integer.toString(CUIDv1.nextCounterValue(), NUMBER_BASE), CUIDv1.BLOCK_SIZE);
+ final String random = CUIDv1.getRandomBlock() + CUIDv1.getRandomBlock();
- return Holder.RANDOM_BUFFER[randomBufferIndex++] << 24
- | (Holder.RANDOM_BUFFER[randomBufferIndex++] & 0xff) << 16
- | (Holder.RANDOM_BUFFER[randomBufferIndex++] & 0xff) << 8
- | (Holder.RANDOM_BUFFER[randomBufferIndex++] & 0xff);
+ return new CUID(CUIDv1.START_CHARACTER + timestamp + counter + Common.MACHINE_FINGERPRINT + random);
}
/**
- * Pads string with leading zero.
+ * Creates a {@code CUID} from the string standard representation.
*
- * @param str The string to pad
- * @param size The size to keep
- * @return The padded string
+ * @param cuidAsString A string that specifies a {@code CUID} (Version 1 or 2)
+ * @return A {@code CUID} with the specified value
+ * @throws IllegalArgumentException If the string is not conform
+ * @since 1.0.0
*/
- private static String padWithZero(final String str, final int size) {
+ public static CUID fromString(final String cuidAsString) {
- final String paddedString = "000000000" + str;
- return paddedString.substring(paddedString.length() - size);
+ if (isValid(cuidAsString)) {
+ return new CUID(cuidAsString);
+ }
+
+ throw new IllegalArgumentException("CUID string is invalid: '" + cuidAsString + "'");
}
/**
* Checks the {@code CUID} from the string standard representation.
*
- * @param cuidAsString A string that specifies a {@code CUID}
+ * @param cuidAsString A string that specifies a {@code CUID} (Version 1 or 2)
* @return {@code true} If the string is not conform, otherwise, {@code false}
+ * @since 1.0.0
*/
public static boolean isValid(final String cuidAsString) {
return cuidAsString != null
- && cuidAsString.length() == CUID_VALUE_LENGTH
- && cuidAsString.startsWith(START_CHARACTER)
+ && (cuidAsString.length() == CUIDv1.LENGTH_STANDARD && cuidAsString.startsWith(CUIDv1.START_CHARACTER) // Version 1
+ || (cuidAsString.length() == CUIDv2.LENGTH_STANDARD || cuidAsString.length() == CUIDv2.LENGTH_BIG)) // Version 2
&& cuidAsString.chars()
.filter(c -> !((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')))
.count() == 0;
}
+ /**
+ * {@inheritDoc}
+ *
+ * @since 1.0.0
+ */
@Override
public int compareTo(final CUID cuid) {
@@ -146,12 +144,24 @@ public int compareTo(final CUID cuid) {
return this.value.compareTo(cuid.value);
}
+ /**
+ * Returns the string representation.
+ *
+ * @return String containing the {@code CUID}
+ * @since 1.0.0
+ */
@Override
public String toString() {
return this.value;
}
+ /**
+ * Returns {@code true} if the argument is equal to current object, {@code false} otherwise.
+ *
+ * @param o An object
+ * @since 1.0.0
+ */
@Override
public boolean equals(final Object o) {
@@ -161,26 +171,186 @@ public boolean equals(final Object o) {
return Objects.equals(value, cuid.value);
}
+ /**
+ * Generates a hash code.
+ *
+ * @return Generated hashcode
+ * @since 1.0.0
+ */
@Override
public int hashCode() {
return Objects.hash(value);
}
+ /**
+ * CUID Version 1.
+ *
+ * @since 1.0.0
+ */
+ private static final class CUIDv1 {
+
+ // CUID configuration
+ private static final int BLOCK_SIZE = 4;
+ private static final int LENGTH_STANDARD = 25;
+ private static final String START_CHARACTER = "c";
+ private static final int DISCRETE_VALUE = (int) Math.pow(NUMBER_BASE, BLOCK_SIZE);
+
+ // Counter
+ private static int counter = 0;
+
+ /**
+ * Retrieves the counter next value.
+ *
+ * @return The counter next value
+ * @since 1.0.0
+ */
+ private static synchronized int nextCounterValue() {
+
+ counter = counter < DISCRETE_VALUE ? counter : 0;
+ return counter++;
+ }
+
+ /**
+ * Generates a random block of data.
+ *
+ * @return Newly generated block of data
+ * @since 1.0.0
+ */
+ private static String getRandomBlock() {
+
+ return Common.padWithZero(Integer.toString(Common.nextIntValue() * DISCRETE_VALUE, NUMBER_BASE), BLOCK_SIZE);
+ }
+ }
+
+ /**
+ * CUID Version 2.
+ *
+ * @since 2.0.0
+ */
+ private static final class CUIDv2 {
+
+ private static final char[] ALPHABET_ARRAY = new char[]{
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+ 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
+ private static final int[] PRIME_NUMBER_ARRAY = new int[]{
+ 109717,
+ 109721,
+ 109741,
+ 109751,
+ 109789,
+ 109793,
+ 109807,
+ 109819,
+ 109829,
+ 109831};
+
+ // CUID configuration
+ private static final int LENGTH_STANDARD = 24;
+ private static final int LENGTH_BIG = 32;
+
+ // Counter
+ private static int counter = Integer.MAX_VALUE;
+
+ /**
+ * Retrieves the counter next value.
+ *
+ * @return The counter next value
+ */
+ private static synchronized int nextCounterValue() {
+
+ counter = counter < Integer.MAX_VALUE ? counter : Math.abs(Common.nextIntValue());
+ return counter++;
+ }
+
+ /**
+ * Creates an entropy string.
+ *
+ * @param length Length of the entropy string
+ * @return String containing entropy in base {@link CUID#NUMBER_BASE}
+ */
+ private static String createEntropy(final int length) {
+
+ int primeNumber;
+ final StringBuilder stringBuilder = new StringBuilder(length);
+
+ while (stringBuilder.length() < length) {
+ primeNumber = PRIME_NUMBER_ARRAY[Math.abs(Common.nextIntValue()) % PRIME_NUMBER_ARRAY.length];
+ stringBuilder.append(Integer.toString(primeNumber * Common.nextIntValue(), NUMBER_BASE));
+ }
+
+ return stringBuilder.toString();
+ }
+
+ /**
+ * Computes hash.
+ *
+ * @return String containing hash
+ */
+ private static String computeHash(final String content, final int saltLength) {
+
+ final String salt = createEntropy(saltLength);
+ try {
+ return new BigInteger(MessageDigest.getInstance("SHA3-256").digest((content + salt).getBytes(StandardCharsets.UTF_8)))
+ .toString(NUMBER_BASE);
+ } catch (final NoSuchAlgorithmException exception) {
+ throw new CUIDGenerationException(exception);
+ }
+ }
+ }
+
/*
* Holder class to defer initialization until needed.
+ *
+ * @since 1.0.0
*/
- private static final class Holder {
+ private static final class Common {
- static final byte[] RANDOM_BUFFER = new byte[RANDOM_BUFFER_SIZE];
- static final SecureRandom NUMBER_GENERATOR = new SecureRandom();
- static final String MACHINE_FINGERPRINT = getMachineFingerprint();
- private static final int DISCRETE_VALUES = (int) Math.pow(NUMBER_BASE, BLOCK_SIZE);
+ private static final int RANDOM_BUFFER_SIZE = 4096;
+ private static final byte[] RANDOM_BUFFER = new byte[RANDOM_BUFFER_SIZE];
+ private static final SecureRandom NUMBER_GENERATOR = new SecureRandom();
+ private static final String MACHINE_FINGERPRINT = getMachineFingerprint();
+
+ private static int randomBufferIndex = RANDOM_BUFFER_SIZE;
+
+ /**
+ * Retrieves next random integer value.
+ *
+ * @return A random integer
+ * @since 1.0.0
+ */
+ private static synchronized int nextIntValue() {
+
+ if (randomBufferIndex == RANDOM_BUFFER_SIZE) {
+ Common.NUMBER_GENERATOR.nextBytes(Common.RANDOM_BUFFER);
+ randomBufferIndex = 0;
+ }
+
+ return Common.RANDOM_BUFFER[randomBufferIndex++] << 24
+ | (Common.RANDOM_BUFFER[randomBufferIndex++] & 0xff) << 16
+ | (Common.RANDOM_BUFFER[randomBufferIndex++] & 0xff) << 8
+ | (Common.RANDOM_BUFFER[randomBufferIndex++] & 0xff);
+ }
+
+ /**
+ * Pads string with leading zero.
+ *
+ * @param str The string to pad
+ * @param size The size to keep
+ * @return The padded string
+ * @since 1.0.0
+ */
+ private static String padWithZero(final String str, final int size) {
+
+ final String paddedString = "000000000" + str;
+ return paddedString.substring(paddedString.length() - size);
+ }
/**
* retrieves the machine fingerprint.
*
* @return The machine fingerprint
+ * @since 1.0.0
*/
private static String getMachineFingerprint() {
diff --git a/src/main/java/io/github/thibaultmeyer/cuid/exception/CUIDGenerationException.java b/src/main/java/io/github/thibaultmeyer/cuid/exception/CUIDGenerationException.java
new file mode 100644
index 0000000..2cddf3a
--- /dev/null
+++ b/src/main/java/io/github/thibaultmeyer/cuid/exception/CUIDGenerationException.java
@@ -0,0 +1,20 @@
+package io.github.thibaultmeyer.cuid.exception;
+
+/**
+ * Exception indicates that the generation of a new CUID has failed.
+ *
+ * @since 2.0.0
+ */
+public class CUIDGenerationException extends RuntimeException {
+
+ /**
+ * Creates a new instance.
+ *
+ * @param cause Cause of the exception
+ * @since 2.0.0
+ */
+ public CUIDGenerationException(final Throwable cause) {
+
+ super("CUID generation failure", cause);
+ }
+}
diff --git a/src/test/java/io/github/thibaultmeyer/cuid/CUIDTest.java b/src/test/java/io/github/thibaultmeyer/cuid/CUIDv1Test.java
similarity index 68%
rename from src/test/java/io/github/thibaultmeyer/cuid/CUIDTest.java
rename to src/test/java/io/github/thibaultmeyer/cuid/CUIDv1Test.java
index 8490d4a..d6b3208 100644
--- a/src/test/java/io/github/thibaultmeyer/cuid/CUIDTest.java
+++ b/src/test/java/io/github/thibaultmeyer/cuid/CUIDv1Test.java
@@ -5,14 +5,11 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
-import java.util.ArrayList;
import java.util.HashSet;
-import java.util.List;
import java.util.Set;
-import java.util.UUID;
@TestMethodOrder(MethodOrderer.MethodName.class)
-final class CUIDTest {
+final class CUIDv1Test {
@Test
void fromString() {
@@ -49,7 +46,7 @@ void fromStringInvalid() {
void randomCUID() {
// Act
- final CUID cuid = CUID.randomCUID();
+ final CUID cuid = CUID.randomCUID1();
// Assert
Assertions.assertNotNull(cuid);
@@ -103,42 +100,10 @@ void unicityOver500000() {
// Act
final Set cuidSet = new HashSet<>();
for (int i = 0; i < 500000; i += 1) {
- cuidSet.add(CUID.randomCUID());
+ cuidSet.add(CUID.randomCUID1());
}
// Assert
Assertions.assertEquals(500000, cuidSet.size());
}
-
- @Test
- void speedVersusUUID() {
-
- System.gc();
- for (int i = 0; i < 10; i += 1) {
- UUID.randomUUID();
- }
-
- final List uuidList = new ArrayList<>();
- final long start2 = System.nanoTime();
- for (int i = 0; i < 1_000_000; i += 1) {
- uuidList.add(UUID.randomUUID());
- }
- final long end2 = System.nanoTime();
- System.err.println("1,000,000 UUID have been generated in " + (end2 - start2) / 1000000 + " ms");
- uuidList.clear();
-
- System.gc();
- for (int i = 0; i < 10; i += 1) {
- CUID.randomCUID();
- }
-
- final List cuidList = new ArrayList<>();
- final long start = System.nanoTime();
- for (int i = 0; i < 1_000_000; i += 1) {
- cuidList.add(CUID.randomCUID());
- }
- final long end = System.nanoTime();
- System.err.println("1,000,000 CUID have been generated in " + (end - start) / 1000000 + " ms");
- cuidList.clear();
- }
}
diff --git a/src/test/java/io/github/thibaultmeyer/cuid/CUIDv2Test.java b/src/test/java/io/github/thibaultmeyer/cuid/CUIDv2Test.java
new file mode 100644
index 0000000..67ec9f7
--- /dev/null
+++ b/src/test/java/io/github/thibaultmeyer/cuid/CUIDv2Test.java
@@ -0,0 +1,120 @@
+package io.github.thibaultmeyer.cuid;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+
+import java.util.HashSet;
+import java.util.Set;
+
+@TestMethodOrder(MethodOrderer.MethodName.class)
+final class CUIDv2Test {
+
+ @Test
+ void fromString() {
+
+ // Arrange
+ final String cuidAsString = "n1ht3jch1r23dy9ramd6ts16";
+
+ // Act
+ final CUID cuid = CUID.fromString(cuidAsString);
+
+ // Assert
+ Assertions.assertNotNull(cuid);
+ Assertions.assertEquals(24, cuid.toString().length());
+ Assertions.assertEquals("n1ht3jch1r23dy9ramd6ts16", cuid.toString());
+ }
+
+ @Test
+ void fromStringInvalid() {
+
+ // Arrange
+ final String cuidAsString = "invalid-cuid";
+
+ // Act
+ final IllegalArgumentException exception = Assertions.assertThrows(
+ IllegalArgumentException.class,
+ () -> CUID.fromString(cuidAsString));
+
+ // Assert
+ Assertions.assertNotNull(exception);
+ Assertions.assertEquals("CUID string is invalid: 'invalid-cuid'", exception.getMessage());
+ }
+
+ @Test
+ void randomCUIDv2() {
+
+ // Act
+ final CUID cuid = CUID.randomCUID2();
+
+ // Assert
+ Assertions.assertNotNull(cuid);
+ Assertions.assertEquals(24, cuid.toString().length());
+ }
+
+ @Test
+ void randomCUIDv2BigLength() {
+
+ // Act
+ final CUID cuid = CUID.randomCUID2(true);
+
+ // Assert
+ Assertions.assertNotNull(cuid);
+ Assertions.assertEquals(32, cuid.toString().length());
+ }
+
+ @Test
+ void compareToNotSame() {
+
+ // Arrange
+ final CUID cuidOne = CUID.fromString("g346rykdwn4m117cupchv9m6");
+ final CUID cuidTwo = CUID.fromString("o7ti2h84195cdvxmbx9vb2gg");
+
+ // Act
+ final int result = cuidOne.compareTo(cuidTwo);
+
+ // Assert
+ Assertions.assertEquals(-8, result);
+ }
+
+ @Test
+ void compareToNotSameNull() {
+
+ // Arrange
+ final CUID cuidOne = CUID.fromString("f23nsqjlsmd1oo0kooedsg07");
+
+ // Act
+ final int result = cuidOne.compareTo(null);
+
+ // Assert
+ Assertions.assertEquals(-1, result);
+ }
+
+ @Test
+ void compareToSame() {
+
+ // Arrange
+ final CUID cuidOne = CUID.fromString("z976prixkgxs0u13x7g67fo3");
+ final CUID cuidTwo = CUID.fromString("z976prixkgxs0u13x7g67fo3");
+
+ // Act
+ final int result = cuidOne.compareTo(cuidTwo);
+
+ // Assert
+ Assertions.assertEquals(0, result);
+ }
+
+ @Test
+ void unicityOver500000() {
+
+ // Act
+ final Set cuidSet = new HashSet<>();
+ for (int i = 0; i < 500000; i += 1) {
+ cuidSet.add(CUID.randomCUID2());
+ }
+
+ // Assert
+ Assertions.assertEquals(500000, cuidSet.size());
+ }
+}
diff --git a/src/test/java/io/github/thibaultmeyer/cuid/PerformanceTest.java b/src/test/java/io/github/thibaultmeyer/cuid/PerformanceTest.java
new file mode 100644
index 0000000..bbbae79
--- /dev/null
+++ b/src/test/java/io/github/thibaultmeyer/cuid/PerformanceTest.java
@@ -0,0 +1,90 @@
+package io.github.thibaultmeyer.cuid;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+@TestMethodOrder(MethodOrderer.MethodName.class)
+final class PerformanceTest {
+
+ @BeforeAll
+ public static void beforeAll() {
+
+ System.gc();
+ }
+
+ @Test
+ void speedUUID() {
+
+ for (int i = 0; i < 10; i += 1) {
+ UUID.randomUUID();
+ }
+
+ final List uuidList = new ArrayList<>();
+ final long start = System.nanoTime();
+ for (int i = 0; i < 1_000_000; i += 1) {
+ uuidList.add(UUID.randomUUID());
+ }
+ final long end = System.nanoTime();
+
+ System.err.println("1,000,000 UUID have been generated in " + (end - start) / 1_000_000 + " ms");
+ Assertions.assertEquals(1_000_000, uuidList.size());
+ }
+
+ @Test
+ void speedCUIDv1() {
+ for (int i = 0; i < 10; i += 1) {
+ CUID.randomCUID1();
+ }
+
+ final List cuidList = new ArrayList<>();
+ final long start = System.nanoTime();
+ for (int i = 0; i < 1_000_000; i += 1) {
+ cuidList.add(CUID.randomCUID1());
+ }
+ final long end = System.nanoTime();
+
+ System.err.println("1,000,000 CUIDv1 have been generated in " + (end - start) / 1_000_000 + " ms");
+ Assertions.assertEquals(1_000_000, cuidList.size());
+ }
+
+ @Test
+ void speedCUIDv2Standard() {
+ for (int i = 0; i < 10; i += 1) {
+ CUID.randomCUID2();
+ }
+
+ final List cuidList = new ArrayList<>();
+ final long start = System.nanoTime();
+ for (int i = 0; i < 1_000_000; i += 1) {
+ cuidList.add(CUID.randomCUID2());
+ }
+ final long end = System.nanoTime();
+
+ System.err.println("1,000,000 CUIDv2 have been generated in " + (end - start) / 1_000_000 + " ms");
+ Assertions.assertEquals(1_000_000, cuidList.size());
+ }
+
+ @Test
+ void speedCUIDv2Big() {
+ for (int i = 0; i < 10; i += 1) {
+ CUID.randomCUID2(true);
+ }
+
+ final List cuidList = new ArrayList<>();
+ final long start = System.nanoTime();
+ for (int i = 0; i < 1_000_000; i += 1) {
+ cuidList.add(CUID.randomCUID2(true));
+ }
+ final long end = System.nanoTime();
+
+ System.err.println("1,000,000 CUIDv2 have been generated in " + (end - start) / 1_000_000 + " ms");
+ Assertions.assertEquals(1_000_000, cuidList.size());
+ }
+}