You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ah...@apache.org on 2019/10/11 13:28:19 UTC
[commons-rng] 07/16: Created Hex class for encoding/decoding hex
bytes.
This is an automated email from the ASF dual-hosted git repository.
aherbert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-rng.git
commit e637b4f300955942ebb875cc53735e73f4b2a952
Author: Alex Herbert <ah...@apache.org>
AuthorDate: Sat Oct 5 00:41:35 2019 +0100
Created Hex class for encoding/decoding hex bytes.
Added hex seed option to the output command.
---
.../apache/commons/rng/examples/stress/Hex.java | 106 +++++++++++++++++++++
.../commons/rng/examples/stress/OutputCommand.java | 58 +++++++++--
.../commons/rng/examples/stress/RNGUtils.java | 32 -------
.../rng/examples/stress/StressTestCommand.java | 2 +-
4 files changed, 157 insertions(+), 41 deletions(-)
diff --git a/commons-rng-examples/examples-stress/src/main/java/org/apache/commons/rng/examples/stress/Hex.java b/commons-rng-examples/examples-stress/src/main/java/org/apache/commons/rng/examples/stress/Hex.java
new file mode 100644
index 0000000..c71532c
--- /dev/null
+++ b/commons-rng-examples/examples-stress/src/main/java/org/apache/commons/rng/examples/stress/Hex.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.rng.examples.stress;
+
+/**
+ * Encodes and decodes bytes as hexadecimal characters.
+ *
+ * <p>Adapted from commons-codec.</p>
+ */
+final class Hex {
+ /**
+ * Used to build 4-bit numbers as Hex.
+ */
+ private static final char[] HEX_DIGITS = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+ };
+
+ /** No public construction. */
+ private Hex() {}
+
+ /**
+ * Converts an array of bytes into an array of characters representing the hexadecimal
+ * values of each byte in order. The returned array will be double the length of the
+ * passed array, as it takes two characters to represent any given byte.
+ *
+ * <p>This can be used to encode byte array seeds into a text representation.</p>
+ *
+ * @param data A byte[] to convert to Hex characters
+ * @return A char[] containing the lower-case Hex representation
+ */
+ static char[] encodeHex(final byte[] data) {
+ final int l = data.length;
+ final char[] out = new char[l << 1];
+ // Two characters form the hex value
+ for (int i = 0; i < l; i++) {
+ // Upper 4-bits
+ out[2 * i] = HEX_DIGITS[(0xf0 & data[i]) >>> 4];
+ // Lower 4-bits
+ out[2 * i + 1] = HEX_DIGITS[ 0x0f & data[i]];
+ }
+ return out;
+ }
+
+ /**
+ * Converts an array of characters representing hexadecimal values into an array
+ * of bytes of those same values. The returned array will be half the length of
+ * the passed array, as it takes two characters to represent any given byte. An
+ * exception is thrown if the passed char array has an odd number of elements.
+ *
+ * @param data An array of characters containing hexadecimal digits
+ * @return A byte array containing binary data decoded from the supplied char array.
+ * @throws IllegalArgumentException Thrown if an odd number or illegal of
+ * characters is supplied
+ */
+ public static byte[] decodeHex(final CharSequence data) {
+
+ final int len = data.length();
+
+ if ((len & 0x01) != 0) {
+ throw new IllegalArgumentException("Odd number of characters.");
+ }
+
+ final byte[] out = new byte[len >> 1];
+
+ // Two characters form the hex value
+ for (int j = 0; j < len; j += 2) {
+ final int f = (toDigit(data, j) << 4) |
+ toDigit(data, j + 1);
+ out[j / 2] = (byte) f;
+ }
+
+ return out;
+ }
+
+ /**
+ * Converts a hexadecimal character to an integer.
+ *
+ * @param data An array of characters containing hexadecimal digits
+ * @param index The index of the character in the source
+ * @return An integer
+ * @throws IllegalArgumentException Thrown if ch is an illegal hex character
+ */
+ protected static int toDigit(final CharSequence data, final int index) {
+ final char ch = data.charAt(index);
+ final int digit = Character.digit(ch, 16);
+ if (digit == -1) {
+ throw new IllegalArgumentException("Illegal hexadecimal character " + ch +
+ " at index " + index);
+ }
+ return digit;
+ }
+}
diff --git a/commons-rng-examples/examples-stress/src/main/java/org/apache/commons/rng/examples/stress/OutputCommand.java b/commons-rng-examples/examples-stress/src/main/java/org/apache/commons/rng/examples/stress/OutputCommand.java
index da5646b..b27b197 100644
--- a/commons-rng-examples/examples-stress/src/main/java/org/apache/commons/rng/examples/stress/OutputCommand.java
+++ b/commons-rng-examples/examples-stress/src/main/java/org/apache/commons/rng/examples/stress/OutputCommand.java
@@ -91,9 +91,16 @@ class OutputCommand implements Callable<Void> {
/** The random seed. */
@Option(names = {"-s", "--seed"},
- description = {"The random seed (default: auto)."})
+ description = {"The 64-bit number random seed (default: auto)."})
private Long seed;
+ /** The random seed as a byte[]. */
+ @Option(names = {"-x", "--hex-seed"},
+ description = {"The hex-encoded random seed.",
+ "Bytes for other primitives use little-endian format.",
+ "Over-rides the --seed parameter."})
+ private String byteSeed;
+
/** The count of numbers to output. */
@Option(names = {"-n", "--count"},
description = {"The count of numbers to output.",
@@ -156,7 +163,8 @@ class OutputCommand implements Callable<Void> {
@Override
public Void call() {
LogUtils.setLogLevel(reusableOptions.logLevel);
- UniformRandomProvider rng = createRNG();
+ final Object objectSeed = createSeed();
+ UniformRandomProvider rng = createRNG(objectSeed);
// Upper or lower bits from 64-bit generators must be created first.
// This will throw if not a 64-bit generator.
@@ -183,7 +191,7 @@ class OutputCommand implements Callable<Void> {
writeBinaryData(rng, out);
break;
case DIEHARDER:
- writeDieharder(rng, seed == null ? "auto" : seed, out);
+ writeDieharder(rng, out);
break;
case BITS:
writeBitData(rng, out);
@@ -198,12 +206,48 @@ class OutputCommand implements Callable<Void> {
}
/**
+ * Creates the seed.
+ *
+ * @return the seed
+ */
+ private Object createSeed() {
+ if (byteSeed != null) {
+ try {
+ return Hex.decodeHex(byteSeed);
+ } catch (IllegalArgumentException ex) {
+ throw new ApplicationException("Invalid hex seed: " + ex.getMessage(), ex);
+ }
+ }
+ if (seed != null) {
+ return seed;
+ }
+ // Let the factory constructor create the native seed.
+ return null;
+ }
+
+ /**
+ * Creates the seed.
+ *
+ * @return the seed
+ */
+ private String createSeedString() {
+ if (byteSeed != null) {
+ return byteSeed;
+ }
+ if (seed != null) {
+ return seed.toString();
+ }
+ return "auto";
+ }
+
+ /**
* Creates the RNG.
*
+ * @param objectSeed Seed.
* @return the uniform random provider
* @throws ApplicationException If the RNG cannot be created
*/
- private UniformRandomProvider createRNG() {
+ private UniformRandomProvider createRNG(Object objectSeed) {
if (randomSource == null) {
throw new ApplicationException("Random source is null");
}
@@ -216,7 +260,7 @@ class OutputCommand implements Callable<Void> {
data.add(RNGUtils.parseArgument(argument));
}
try {
- return RandomSource.create(randomSource, seed, data.toArray());
+ return RandomSource.create(randomSource, objectSeed, data.toArray());
} catch (IllegalStateException | IllegalArgumentException ex) {
throw new ApplicationException("Failed to create RNG: " + randomSource + ". " + ex.getMessage(), ex);
}
@@ -310,13 +354,11 @@ class OutputCommand implements Callable<Void> {
* Write int data to the specified output using the dieharder text format.
*
* @param rng The random generator.
- * @param seedObject The seed using to create the random source.
* @param out The output.
* @throws IOException Signals that an I/O exception has occurred.
* @throws ApplicationException If the count is not positive.
*/
private void writeDieharder(final UniformRandomProvider rng,
- final Object seedObject,
final OutputStream out) throws IOException {
checkCount(count, OutputFormat.DIEHARDER);
@@ -333,7 +375,7 @@ class OutputCommand implements Callable<Void> {
output.write("# generator ");
output.write(rng.toString());
output.write(" seed = ");
- output.write(String.valueOf(seedObject));
+ output.write(createSeedString());
output.write(NEW_LINE);
writeHeaderLine(output);
output.write("type: d");
diff --git a/commons-rng-examples/examples-stress/src/main/java/org/apache/commons/rng/examples/stress/RNGUtils.java b/commons-rng-examples/examples-stress/src/main/java/org/apache/commons/rng/examples/stress/RNGUtils.java
index 4c3056c..29c09a5 100644
--- a/commons-rng-examples/examples-stress/src/main/java/org/apache/commons/rng/examples/stress/RNGUtils.java
+++ b/commons-rng-examples/examples-stress/src/main/java/org/apache/commons/rng/examples/stress/RNGUtils.java
@@ -46,13 +46,6 @@ final class RNGUtils {
/** Message when not a RandomLongSource. */
private static final String NOT_LONG_SOURCE = "Not a 64-bit long generator: ";
- /**
- * Used to build 4-bit numbers as Hex.
- */
- private static final char[] HEX_DIGITS = {
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
- };
-
/** No public construction. */
private RNGUtils() {}
@@ -419,29 +412,4 @@ final class RNGUtils {
throw new ApplicationException("Failed to parse RandomSource argument: " + argument, ex);
}
}
-
- /**
- * Converts an array of bytes into an array of characters representing the hexadecimal
- * values of each byte in order. The returned array will be double the length of the
- * passed array, as it takes two characters to represent any given byte.
- *
- * <p>This can be used to encode byte array seeds into a text representation.</p>
- *
- * <p>Adapted from commons-codec.</p>
- *
- * @param data a byte[] to convert to Hex characters
- * @return A char[] containing the lower-case Hex representation
- */
- static char[] encodeHex(final byte[] data) {
- final int l = data.length;
- final char[] out = new char[l << 1];
- // Two characters form the hex value
- for (int i = 0; i < l; i++) {
- // Upper 4-bits
- out[2 * i] = HEX_DIGITS[(0xf0 & data[i]) >>> 4];
- // Lower 4-bits
- out[2 * i + 1] = HEX_DIGITS[ 0x0f & data[i]];
- }
- return out;
- }
}
diff --git a/commons-rng-examples/examples-stress/src/main/java/org/apache/commons/rng/examples/stress/StressTestCommand.java b/commons-rng-examples/examples-stress/src/main/java/org/apache/commons/rng/examples/stress/StressTestCommand.java
index b8b2c5d..286f825 100644
--- a/commons-rng-examples/examples-stress/src/main/java/org/apache/commons/rng/examples/stress/StressTestCommand.java
+++ b/commons-rng-examples/examples-stress/src/main/java/org/apache/commons/rng/examples/stress/StressTestCommand.java
@@ -690,7 +690,7 @@ class StressTestCommand implements Callable<Void> {
sb.append(C).append(N)
.append(C).append("RandomSource: ").append(randomSource.name()).append(N)
.append(C).append("RNG: ").append(rng.toString()).append(N)
- .append(C).append("Seed: ").append(RNGUtils.encodeHex(seed)).append(N)
+ .append(C).append("Seed: ").append(Hex.encodeHex(seed)).append(N)
.append(C).append(N)
// Match the output of 'java -version', e.g.