View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.rng.simple.internal;
18  
19  import org.apache.commons.rng.core.util.NumberFactory;
20  
21  /**
22   * The native seed type. Contains values for all native seed types and methods
23   * to convert supported seed types to the native seed type.
24   *
25   * <p>Valid native seed types are:</p>
26   * <ul>
27   *  <li>{@code Integer}</li>
28   *  <li>{@code Long}</li>
29   *  <li>{@code int[]}</li>
30   *  <li>{@code long[]}</li>
31   * </ul>
32   *
33   * <p>Valid types for seed conversion are:</p>
34   * <ul>
35   *  <li>{@code Integer} (or {@code int})</li>
36   *  <li>{@code Long} (or {@code long})</li>
37   *  <li>{@code int[]}</li>
38   *  <li>{@code long[]}</li>
39   *  <li>{@code byte[]}</li>
40   * </ul>
41   *
42   * @since 1.3
43   */
44  public enum NativeSeedType {
45      /** The seed type is {@code Integer}. */
46      INT(Integer.class, 4) {
47          @Override
48          public Integer createSeed(int size, int from, int to) {
49              return SeedFactory.createInt();
50          }
51          @Override
52          protected Integer convert(Integer seed, int size) {
53              return seed;
54          }
55          @Override
56          protected Integer convert(Long seed, int size) {
57              return Conversions.long2Int(seed);
58          }
59          @Override
60          protected Integer convert(int[] seed, int size) {
61              return Conversions.intArray2Int(seed);
62          }
63          @Override
64          protected Integer convert(long[] seed, int size) {
65              return Conversions.longArray2Int(seed);
66          }
67          @Override
68          protected Integer convert(byte[] seed, int size) {
69              return Conversions.byteArray2Int(seed);
70          }
71      },
72      /** The seed type is {@code Long}. */
73      LONG(Long.class, 8) {
74          @Override
75          public Long createSeed(int size, int from, int to) {
76              return SeedFactory.createLong();
77          }
78          @Override
79          protected Long convert(Integer seed, int size) {
80              return Conversions.int2Long(seed);
81          }
82          @Override
83          protected Long convert(Long seed, int size) {
84              return seed;
85          }
86          @Override
87          protected Long convert(int[] seed, int size) {
88              return Conversions.intArray2Long(seed);
89          }
90          @Override
91          protected Long convert(long[] seed, int size) {
92              return Conversions.longArray2Long(seed);
93          }
94          @Override
95          protected Long convert(byte[] seed, int size) {
96              return Conversions.byteArray2Long(seed);
97          }
98      },
99      /** 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 }