4 Commits

Author SHA256 Message Date
Minimons
8cce8303b5 NoIssue: Better fail safety 2025-12-03 10:38:59 +01:00
Minimons
04d26543b5 NoIssue: Add notnull annotations 2025-12-03 10:01:13 +01:00
Minimons
71bc4a2e05 NoIssue: Add some String generators 2025-12-03 09:45:27 +01:00
Minimons
909eba4575 NoIssue: Add RandomValueGeneratorInt 2025-11-26 15:25:16 +01:00
3 changed files with 109 additions and 1 deletions

View File

@@ -30,7 +30,7 @@ repositories {
dependencies {
implementation("org.jetbrains:annotations:26.0.1")
implementation("log4j:log4j:1.2.17")
implementation("com.r35157.libs:random-api:0.0.0")
implementation("com.r35157.libs:random-api:0.1-dev")
}
java {

View File

@@ -0,0 +1,54 @@
package com.r35157.libs.random.impl.ref;
import com.r35157.libs.random.RandomValueGeneratorInt;
import java.util.concurrent.ThreadLocalRandom;
import static java.lang.Integer.MAX_VALUE;
import static java.lang.Integer.MIN_VALUE;
public class RandomValueGeneratorIntImpl implements RandomValueGeneratorInt {
@Override
public int getSomeInt() {
// Default: use the full int range
return getSomeInt(MIN_VALUE, MAX_VALUE);
}
@Override
public int getSomeInt(int minInclusive, int maxInclusive) {
if (minInclusive > maxInclusive) {
String errorMessage = String.format("'minInclusive' (%d) must be less than or equal to 'maxInclusive' (%d)",
minInclusive, maxInclusive);
throw new IllegalArgumentException(errorMessage);
}
if (minInclusive == maxInclusive) {
// Edge case: only one possible value
return minInclusive;
}
// Fast path: full int range ThreadLocalRandom.nextInt() already covers it
if (minInclusive == MIN_VALUE && maxInclusive == MAX_VALUE) {
return ThreadLocalRandom.current().nextInt();
}
// Use long to avoid overflow when calculating range size
long bound = ((long) maxInclusive - (long) minInclusive) + 1L;
if (bound <= Integer.MAX_VALUE) {
// Normal case: the range fits in an int
// nextInt(bound) gives a uniform value in [0, bound],
// then shift it into the target range by adding minInclusive
return minInclusive + ThreadLocalRandom.current().nextInt((int) bound);
} else {
// Rare case: the range is larger than Integer.MAX_VALUE
// (e.g. almost the full int space). Use rejection sampling:
// draw values until one falls within the desired interval.
int r;
do {
r = ThreadLocalRandom.current().nextInt();
} while (r < minInclusive || r > maxInclusive);
return r;
}
}
}

View File

@@ -0,0 +1,54 @@
package com.r35157.libs.random.impl.ref;
import com.r35157.libs.random.RandomValueGeneratorInt;
import com.r35157.libs.random.RandomValueGeneratorString;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
public class RandomValueGeneratorStringImpl implements RandomValueGeneratorString {
public RandomValueGeneratorStringImpl(@NotNull RandomValueGeneratorInt rvgi) {
Objects.requireNonNull(rvgi, "Cannot initialize with <null> RandomValueGeneratorInt!");
this.rvgi = rvgi;
}
public @NotNull String getSomeStringAlphaNumericOnly(int length) throws IllegalArgumentException {
if(length < 0) {
throw new IllegalArgumentException("Cannot generate random Strings of size " + length + "!");
}
// ASCII Range size
// Numeric 48-57 10
// Alpha upper 65-90 26
// Alpha lower 97-122 26
int totalNumberOfCandidates = 10 + 26 + 26;
StringBuilder buffer = new StringBuilder(length);
for (int i = 0; i < length; i++) {
int randomInt = rvgi.getSomeInt(0, totalNumberOfCandidates - 1);
int asciiIndex = convertRandomIndexToASCIIIndex(randomInt);
buffer.append((char) asciiIndex);
}
return buffer.toString();
}
private static int convertRandomIndexToASCIIIndex(int randomIndex) {
// RandomIndex 0... ...9 - 10... ...35 - 36... ... 61
// ASCII values: 48...<numeric>...57 - 65...<alpha upper>...90 - 97...<alpha lower>...122
int asciiIndex;
if(randomIndex >= 36) {
asciiIndex = 97 + (randomIndex - 36);
} else if(randomIndex >= 10) {
asciiIndex = 65 + (randomIndex - 10);
} else {
asciiIndex = 48 + randomIndex;
}
return asciiIndex;
}
private RandomValueGeneratorInt rvgi;
}