001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.rng.simple.internal; 018 019import org.apache.commons.rng.core.util.NumberFactory; 020 021/** 022 * The native seed type. Contains values for all native seed types and methods 023 * to convert supported seed types to the native seed type. 024 * 025 * <p>Valid native seed types are:</p> 026 * <ul> 027 * <li>{@code Integer}</li> 028 * <li>{@code Long}</li> 029 * <li>{@code int[]}</li> 030 * <li>{@code long[]}</li> 031 * </ul> 032 * 033 * <p>Valid types for seed conversion are:</p> 034 * <ul> 035 * <li>{@code Integer} (or {@code int})</li> 036 * <li>{@code Long} (or {@code long})</li> 037 * <li>{@code int[]}</li> 038 * <li>{@code long[]}</li> 039 * <li>{@code byte[]}</li> 040 * </ul> 041 * 042 * @since 1.3 043 */ 044public enum NativeSeedType { 045 /** The seed type is {@code Integer}. */ 046 INT(Integer.class, 4) { 047 @Override 048 public Integer createSeed(int size, int from, int to) { 049 return SeedFactory.createInt(); 050 } 051 @Override 052 protected Integer convert(Integer seed, int size) { 053 return seed; 054 } 055 @Override 056 protected Integer convert(Long seed, int size) { 057 return Conversions.long2Int(seed); 058 } 059 @Override 060 protected Integer convert(int[] seed, int size) { 061 return Conversions.intArray2Int(seed); 062 } 063 @Override 064 protected Integer convert(long[] seed, int size) { 065 return Conversions.longArray2Int(seed); 066 } 067 @Override 068 protected Integer convert(byte[] seed, int size) { 069 return Conversions.byteArray2Int(seed); 070 } 071 }, 072 /** The seed type is {@code Long}. */ 073 LONG(Long.class, 8) { 074 @Override 075 public Long createSeed(int size, int from, int to) { 076 return SeedFactory.createLong(); 077 } 078 @Override 079 protected Long convert(Integer seed, int size) { 080 return Conversions.int2Long(seed); 081 } 082 @Override 083 protected Long convert(Long seed, int size) { 084 return seed; 085 } 086 @Override 087 protected Long convert(int[] seed, int size) { 088 return Conversions.intArray2Long(seed); 089 } 090 @Override 091 protected Long convert(long[] seed, int size) { 092 return Conversions.longArray2Long(seed); 093 } 094 @Override 095 protected Long convert(byte[] seed, int size) { 096 return Conversions.byteArray2Long(seed); 097 } 098 }, 099 /** The seed type is {@code int[]}. */ 100 INT_ARRAY(int[].class, 4) { 101 @Override 102 public int[] createSeed(int size, int from, int to) { 103 // Limit the number of calls to the synchronized method. The generator 104 // will support self-seeding. 105 return SeedFactory.createIntArray(Math.min(size, RANDOM_SEED_ARRAY_SIZE), 106 from, to); 107 } 108 @Override 109 protected int[] convert(Integer seed, int size) { 110 return Conversions.int2IntArray(seed, size); 111 } 112 @Override 113 protected int[] convert(Long seed, int size) { 114 return Conversions.long2IntArray(seed, size); 115 } 116 @Override 117 protected int[] convert(int[] seed, int size) { 118 return seed; 119 } 120 @Override 121 protected int[] convert(long[] seed, int size) { 122 // Avoid zero filling seeds that are too short 123 return Conversions.longArray2IntArray(seed, 124 Math.min(size, Conversions.intSizeFromLongSize(seed.length))); 125 } 126 @Override 127 protected int[] convert(byte[] seed, int size) { 128 // Avoid zero filling seeds that are too short 129 return Conversions.byteArray2IntArray(seed, 130 Math.min(size, Conversions.intSizeFromByteSize(seed.length))); 131 } 132 }, 133 /** The seed type is {@code long[]}. */ 134 LONG_ARRAY(long[].class, 8) { 135 @Override 136 public long[] createSeed(int size, int from, int to) { 137 // Limit the number of calls to the synchronized method. The generator 138 // will support self-seeding. 139 return SeedFactory.createLongArray(Math.min(size, RANDOM_SEED_ARRAY_SIZE), 140 from, to); 141 } 142 @Override 143 protected long[] convert(Integer seed, int size) { 144 return Conversions.int2LongArray(seed, size); 145 } 146 @Override 147 protected long[] convert(Long seed, int size) { 148 return Conversions.long2LongArray(seed, size); 149 } 150 @Override 151 protected long[] convert(int[] seed, int size) { 152 // Avoid zero filling seeds that are too short 153 return Conversions.intArray2LongArray(seed, 154 Math.min(size, Conversions.longSizeFromIntSize(seed.length))); 155 } 156 @Override 157 protected long[] convert(long[] seed, int size) { 158 return seed; 159 } 160 @Override 161 protected long[] convert(byte[] seed, int size) { 162 // Avoid zero filling seeds that are too short 163 return Conversions.byteArray2LongArray(seed, 164 Math.min(size, Conversions.longSizeFromByteSize(seed.length))); 165 } 166 }; 167 168 /** Error message for unrecognised seed types. */ 169 private static final String UNRECOGNISED_SEED = "Unrecognized seed type: "; 170 /** Maximum length of the seed array (for creating array seeds). */ 171 private static final int RANDOM_SEED_ARRAY_SIZE = 128; 172 173 /** Define the class type of the native seed. */ 174 private final Class<?> type; 175 176 /** 177 * Define the number of bytes required to represent the native seed. If the type is 178 * an array then this represents the size of a single value of the type. 179 */ 180 private final int bytes; 181 182 /** 183 * Instantiates a new native seed type. 184 * 185 * @param type Define the class type of the native seed. 186 * @param bytes Define the number of bytes required to represent the native seed. 187 */ 188 NativeSeedType(Class<?> type, int bytes) { 189 this.type = type; 190 this.bytes = bytes; 191 } 192 193 /** 194 * Gets the class type of the native seed. 195 * 196 * @return the type 197 */ 198 public Class<?> getType() { 199 return type; 200 } 201 202 /** 203 * Gets the number of bytes required to represent the native seed type. If the type is 204 * an array then this represents the size of a single value of the type. 205 * 206 * @return the number of bytes 207 */ 208 public int getBytes() { 209 return bytes; 210 } 211 212 /** 213 * Creates the seed. The output seed type is determined by the native seed type. If the 214 * output is an array the required size of the array can be specified. 215 * 216 * @param size The size of the seed (array types only). 217 * @return the seed 218 */ 219 public Object createSeed(int size) { 220 // Maintain behaviour since 1.3 to ensure position [0] of array seeds is non-zero. 221 return createSeed(size, 0, Math.min(size, 1)); 222 } 223 224 /** 225 * Creates the seed. The output seed type is determined by the native seed type. If 226 * the output is an array the required size of the array can be specified and a 227 * sub-range that must not be all-zero. 228 * 229 * @param size The size of the seed (array types only). 230 * @param from The start of the not all-zero sub-range (inclusive; array types only). 231 * @param to The end of the not all-zero sub-range (exclusive; array types only). 232 * @return the seed 233 * @throws IndexOutOfBoundsException if the sub-range is out of bounds 234 * @since 1.5 235 */ 236 public abstract Object createSeed(int size, int from, int to); 237 238 /** 239 * Converts the input seed from any of the supported seed types to the native seed type. 240 * If the output is an array the required size of the array can be specified. 241 * 242 * @param seed Input seed. 243 * @param size The size of the output seed (array types only). 244 * @return the native seed. 245 * @throws UnsupportedOperationException if the {@code seed} type is invalid. 246 */ 247 public Object convertSeed(Object seed, 248 int size) { 249 // Convert to native type. 250 // Each method must be overridden by specific implementations. 251 252 if (seed instanceof Integer) { 253 return convert((Integer) seed, size); 254 } else if (seed instanceof Long) { 255 return convert((Long) seed, size); 256 } else if (seed instanceof int[]) { 257 return convert((int[]) seed, size); 258 } else if (seed instanceof long[]) { 259 return convert((long[]) seed, size); 260 } else if (seed instanceof byte[]) { 261 return convert((byte[]) seed, size); 262 } 263 264 throw new UnsupportedOperationException(unrecognisedSeedMessage(seed)); 265 } 266 267 /** 268 * Convert the input {@code Integer} seed to the native seed type. 269 * 270 * @param seed Input seed. 271 * @param size The size of the output seed (array types only). 272 * @return the native seed. 273 */ 274 protected abstract Object convert(Integer seed, int size); 275 276 /** 277 * Convert the input {@code Long} seed to the native seed type. 278 * 279 * @param seed Input seed. 280 * @param size The size of the output seed (array types only). 281 * @return the native seed. 282 */ 283 protected abstract Object convert(Long seed, int size); 284 285 /** 286 * Convert the input {@code int[]} seed to the native seed type. 287 * 288 * @param seed Input seed. 289 * @param size The size of the output seed (array types only). 290 * @return the native seed. 291 */ 292 protected abstract Object convert(int[] seed, int size); 293 294 /** 295 * Convert the input {@code long[]} seed to the native seed type. 296 * 297 * @param seed Input seed. 298 * @param size The size of the output seed (array types only). 299 * @return the native seed. 300 */ 301 protected abstract Object convert(long[] seed, int size); 302 303 /** 304 * Convert the input {@code byte[]} seed to the native seed type. 305 * 306 * @param seed Input seed. 307 * @param size The size of the output seed (array types only). 308 * @return the native seed. 309 */ 310 protected abstract Object convert(byte[] seed, int size); 311 312 /** 313 * Converts the input seed from any of the supported seed types to bytes. 314 * 315 * @param seed Input seed. 316 * @return the seed bytes. 317 * @throws UnsupportedOperationException if the {@code seed} type is invalid. 318 */ 319 public static byte[] convertSeedToBytes(Object seed) { 320 if (seed instanceof Integer) { 321 return NumberFactory.makeByteArray((Integer) seed); 322 } else if (seed instanceof Long) { 323 return NumberFactory.makeByteArray((Long) seed); 324 } else if (seed instanceof int[]) { 325 return NumberFactory.makeByteArray((int[]) seed); 326 } else if (seed instanceof long[]) { 327 return NumberFactory.makeByteArray((long[]) seed); 328 } else if (seed instanceof byte[]) { 329 return (byte[]) seed; 330 } 331 332 throw new UnsupportedOperationException(unrecognisedSeedMessage(seed)); 333 } 334 335 /** 336 * Create an unrecognised seed message. This will add the class type of the seed. 337 * 338 * @param seed the seed 339 * @return the message 340 */ 341 private static String unrecognisedSeedMessage(Object seed) { 342 return UNRECOGNISED_SEED + ((seed == null) ? "null" : seed.getClass().getName()); 343 } 344}